| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export const RESEND_API_BASE = "https://api.resend.com"; |
| export const USER_AGENT = |
| "WorldMonitor-PROLaunchExporter/1.0 (+https://worldmonitor.app)"; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function isDuplicateContactError(body: unknown): boolean { |
| if (!body || typeof body !== "object") return false; |
| const obj = body as Record<string, unknown>; |
| const name = typeof obj.name === "string" ? obj.name.toLowerCase() : ""; |
| const message = typeof obj.message === "string" ? obj.message.toLowerCase() : ""; |
| if (name.includes("already_exists") || name.includes("duplicate")) return true; |
| if (/already (exists|in (the )?(audience|segment))|duplicate/.test(message)) |
| return true; |
| return false; |
| } |
|
|
| export type UpsertOutcome = |
| | { kind: "created" } |
| | { kind: "linkedExisting" } |
| | { kind: "alreadyInSegment" } |
| | { kind: "failed"; reason: string }; |
|
|
| |
| |
| |
| |
| |
| export async function upsertContactToSegment( |
| apiKey: string, |
| email: string, |
| segmentId: string, |
| ): Promise<UpsertOutcome> { |
| const createRes = await fetch(`${RESEND_API_BASE}/contacts`, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| Authorization: `Bearer ${apiKey}`, |
| "User-Agent": USER_AGENT, |
| }, |
| body: JSON.stringify({ |
| email, |
| segments: [{ id: segmentId }], |
| unsubscribed: false, |
| }), |
| }); |
|
|
| if (createRes.ok) return { kind: "created" }; |
|
|
| if (createRes.status === 422) { |
| const createBody = await createRes.json().catch(() => null); |
| if (!isDuplicateContactError(createBody)) { |
| return { |
| kind: "failed", |
| reason: `POST /contacts 422 (non-duplicate): ${JSON.stringify(createBody)}`, |
| }; |
| } |
|
|
| |
| const addRes = await fetch( |
| `${RESEND_API_BASE}/contacts/${encodeURIComponent(email)}/segments/${encodeURIComponent(segmentId)}`, |
| { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| Authorization: `Bearer ${apiKey}`, |
| "User-Agent": USER_AGENT, |
| }, |
| }, |
| ); |
|
|
| if (addRes.ok) return { kind: "linkedExisting" }; |
|
|
| if (addRes.status === 422) { |
| const addBody = await addRes.json().catch(() => null); |
| if (isDuplicateContactError(addBody)) return { kind: "alreadyInSegment" }; |
| return { |
| kind: "failed", |
| reason: `POST /contacts/{email}/segments/{id} 422 (non-duplicate): ${JSON.stringify(addBody)}`, |
| }; |
| } |
|
|
| const addText = await addRes.text().catch(() => "<no body>"); |
| return { |
| kind: "failed", |
| reason: `POST /contacts/{email}/segments/{id} ${addRes.status}: ${addText}`, |
| }; |
| } |
|
|
| const createText = await createRes.text().catch(() => "<no body>"); |
| return { |
| kind: "failed", |
| reason: `POST /contacts ${createRes.status}: ${createText}`, |
| }; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export async function createSegment( |
| apiKey: string, |
| name: string, |
| ): Promise<string> { |
| const res = await fetch(`${RESEND_API_BASE}/segments`, { |
| method: "POST", |
| headers: { |
| "Content-Type": "application/json", |
| Authorization: `Bearer ${apiKey}`, |
| "User-Agent": USER_AGENT, |
| }, |
| body: JSON.stringify({ name }), |
| }); |
|
|
| if (!res.ok) { |
| const body = await res.text().catch(() => "<no body>"); |
| throw new Error( |
| `[createSegment] Resend POST /segments ${res.status}: ${body}`, |
| ); |
| } |
|
|
| const json = (await res.json().catch(() => null)) as { id?: string } | null; |
| if (!json?.id) { |
| throw new Error( |
| `[createSegment] Resend response missing id: ${JSON.stringify(json)}`, |
| ); |
| } |
| return json.id; |
| } |
|
|