import { RESEND_CONTACT_IMPORT_SCHEMA, RESEND_CONTACT_IMPORT_MUTATION_RESPONSE_SCHEMA, RESEND_CONTACT_IMPORT_WIRE_SCHEMA, resendListSchema, resendListWireSchema, } from "@automate.ax/integration-contracts/resend" import * as z from "zod" import { defineAction } from "../../automation/actions" import { getResendApi, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS } from "./lib" const RESEND_ACCOUNT = "resend" const CONTACT_IMPORT_STATUS_SCHEMA = z.enum([ "completed", "failed", "in_progress", "queued", ]) const CONTACT_IMPORT_LIST_SCHEMA = resendListSchema( RESEND_CONTACT_IMPORT_SCHEMA, ) const CONTACT_IMPORT_LIST_WIRE_SCHEMA = resendListWireSchema( RESEND_CONTACT_IMPORT_WIRE_SCHEMA, ) /** Queues an asynchronous CSV import of Resend contacts. */ export const createResendContactImport = defineAction( "Create Resend contact import", ) .describe("Uploads a CSV file and queues an asynchronous contact import.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input( z.object({ /** Contact-field and property keys mapped to CSV column names. */ columnMap: z .object({ email: z.string().min(1).optional(), firstName: z.string().min(1).optional(), lastName: z.string().min(1).optional(), properties: z .record( z.string().min(1), z.object({ column: z.string().min(1), type: z.enum(["boolean", "number", "string"]).optional(), }), ) .optional(), unsubscribed: z.string().min(1).optional(), }) .optional(), /** CSV file, up to 50 MB. */ file: z.instanceof(File).refine((file) => file.size <= 50 * 1024 * 1024, { message: "Contact import files cannot exceed 50 MB.", }), /** Behavior when a CSV row matches an existing contact. */ onConflict: z.enum(["skip", "upsert"]).prefault("skip"), /** Existing segments applied to every imported contact. */ segments: z .object({ id: z.string().min(1) }) .array() .optional(), /** Topic choices applied to every imported contact. */ topics: z .object({ id: z.string().min(1), subscription: z.enum(["opt_in", "opt_out"]), }) .array() .optional(), }), ) .output(RESEND_CONTACT_IMPORT_MUTATION_RESPONSE_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => { const body = new FormData() body.append("file", input.file, input.file.name) body.append("on_conflict", input.onConflict) if (input.columnMap) { const { firstName, lastName, ...columnMap } = input.columnMap body.append( "column_map", JSON.stringify({ ...columnMap, first_name: firstName, last_name: lastName, }), ) } if (input.segments) body.append("segments", JSON.stringify(input.segments)) if (input.topics) body.append("topics", JSON.stringify(input.topics)) return await getResendApi(account).call("/contacts/imports", { body, httpMethod: "POST", responseSchema: RESEND_CONTACT_IMPORT_MUTATION_RESPONSE_SCHEMA, }) }) /** Lists Resend contact imports with status and cursor filters. */ export const listResendContactImports = defineAction( "List Resend contact imports", ) .describe("Lists current and historical contact imports.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input( z .object({ after: z.string().min(1).optional(), before: z.string().min(1).optional(), limit: z.number().int().min(1).max(100).prefault(20), status: CONTACT_IMPORT_STATUS_SCHEMA.optional(), }) .refine(({ after, before }) => !(after && before), { message: "after and before cannot be used together.", }), ) .output(CONTACT_IMPORT_LIST_SCHEMA) .retry({ replaySafety: "safe" }) .handler( async ({ account, input }) => await getResendApi(account).call("/contacts/imports", { query: input, responseSchema: CONTACT_IMPORT_LIST_WIRE_SCHEMA, }), ) /** Retrieves one Resend contact import and its processing counts. */ export const getResendContactImport = defineAction("Get Resend contact import") .describe("Retrieves status and row counts for one contact import.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ contactImportId: z.string().min(1) })) .output(RESEND_CONTACT_IMPORT_SCHEMA) .retry({ replaySafety: "safe" }) .handler( async ({ account, input }) => await getResendApi(account).call( `/contacts/imports/${encodeURIComponent(input.contactImportId)}`, { responseSchema: RESEND_CONTACT_IMPORT_WIRE_SCHEMA }, ), )