import * as z from "zod" import { defineAction } from "../../automation/actions" import { getResendApi, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS } from "./lib" const RESEND_ACCOUNT = "resend" const SUPPRESSION_ORIGIN_SCHEMA = z.enum(["bounce", "complaint", "manual"]) const SUPPRESSION_WIRE_SCHEMA = z.object({ created_at: z.coerce.date(), email: z.email(), id: z.string().min(1), object: z.literal("suppression"), origin: SUPPRESSION_ORIGIN_SCHEMA, source_id: z.string().nullable(), }) const SUPPRESSION_SCHEMA = SUPPRESSION_WIRE_SCHEMA.transform( ({ created_at: createdAt, source_id: sourceId, ...suppression }) => ({ ...suppression, createdAt, sourceId, }), ) const SUPPRESSION_LIST_ITEM_WIRE_SCHEMA = SUPPRESSION_WIRE_SCHEMA.omit({ object: true, }) const SUPPRESSION_LIST_ITEM_SCHEMA = SUPPRESSION_LIST_ITEM_WIRE_SCHEMA.transform( ({ created_at: createdAt, source_id: sourceId, ...suppression }) => ({ ...suppression, createdAt, sourceId, }), ) const SUPPRESSION_LIST_WIRE_SCHEMA = z.object({ data: SUPPRESSION_LIST_ITEM_WIRE_SCHEMA.array(), has_more: z.boolean(), object: z.literal("list"), }) const SUPPRESSION_LIST_SCHEMA = SUPPRESSION_LIST_WIRE_SCHEMA.transform( ({ data, has_more: hasMore, ...result }) => ({ ...result, data: data.map((suppression) => SUPPRESSION_LIST_ITEM_SCHEMA.parse(suppression), ), hasMore, }), ) const SUPPRESSION_MUTATION_SCHEMA = z.object({ id: z.string().min(1), object: z.literal("suppression"), }) const SUPPRESSION_DELETE_SCHEMA = SUPPRESSION_MUTATION_SCHEMA.extend({ deleted: z.boolean(), }) const SUPPRESSION_BATCH_MUTATION_SCHEMA = z.object({ data: SUPPRESSION_MUTATION_SCHEMA.array(), }) const SUPPRESSION_BATCH_DELETE_SCHEMA = z.object({ data: SUPPRESSION_DELETE_SCHEMA.array(), }) const PAGINATION_SCHEMA = z .object({ /** Return suppressions after this cursor. */ after: z.string().min(1).optional(), /** Return suppressions before this cursor. */ before: z.string().min(1).optional(), /** Maximum suppressions to return. */ limit: z.number().int().min(1).max(100).optional(), /** Restrict results by how the suppression was created. */ origin: SUPPRESSION_ORIGIN_SCHEMA.optional(), }) .refine(({ after, before }) => !(after && before), { message: "after and before cannot be used together.", }) const EMAILS_SCHEMA = z.email().array().min(1).max(100) const SUPPRESSION_BATCH_REMOVE_SCHEMA = z.union([ z.object({ emails: EMAILS_SCHEMA, ids: z.never().optional() }), z.object({ emails: z.never().optional(), ids: z.string().min(1).array().min(1).max(100), }), ]) /** Adds one address to the Resend suppression list. */ export const createResendSuppression = defineAction("Create Resend suppression") .describe("Adds one email address to the Resend suppression list.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ email: z.email() })) .output(SUPPRESSION_MUTATION_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler( async ({ account, input }) => await getResendApi(account).call("suppressions", { body: input, httpMethod: "POST", responseSchema: SUPPRESSION_MUTATION_SCHEMA, }), ) /** Lists Resend suppressions with cursor pagination. */ export const listResendSuppressions = defineAction("List Resend suppressions") .describe("Lists suppressed recipients with optional origin filtering.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(PAGINATION_SCHEMA) .output(SUPPRESSION_LIST_SCHEMA) .retry({ replaySafety: "safe" }) .handler( async ({ account, input }) => await getResendApi(account).call("suppressions", { query: input, responseSchema: SUPPRESSION_LIST_WIRE_SCHEMA, }), ) /** Retrieves one Resend suppression by ID or email address. */ export const getResendSuppression = defineAction("Get Resend suppression") .describe("Retrieves one suppression by its ID or email address.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ suppression: z.string().min(1) })) .output(SUPPRESSION_SCHEMA) .retry({ replaySafety: "safe" }) .handler( async ({ account, input }) => await getResendApi(account).call( `suppressions/${encodeURIComponent(input.suppression)}`, { responseSchema: SUPPRESSION_WIRE_SCHEMA }, ), ) /** Removes one Resend suppression by ID or email address. */ export const deleteResendSuppression = defineAction("Delete Resend suppression") .describe("Removes one address from the Resend suppression list.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ suppression: z.string().min(1) })) .output(SUPPRESSION_DELETE_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler( async ({ account, input }) => await getResendApi(account).call( `suppressions/${encodeURIComponent(input.suppression)}`, { httpMethod: "DELETE", responseSchema: SUPPRESSION_DELETE_SCHEMA, }, ), ) /** Adds up to 100 addresses to the Resend suppression list. */ export const addResendSuppressionsBatch = defineAction( "Add Resend suppressions batch", ) .describe("Adds up to 100 email addresses to Resend suppressions.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ emails: EMAILS_SCHEMA })) .output(SUPPRESSION_BATCH_MUTATION_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler( async ({ account, input }) => await getResendApi(account).call("suppressions/batch/add", { body: input, httpMethod: "POST", responseSchema: SUPPRESSION_BATCH_MUTATION_SCHEMA, }), ) /** Removes up to 100 Resend suppressions by IDs or email addresses. */ export const removeResendSuppressionsBatch = defineAction( "Remove Resend suppressions batch", ) .describe("Removes up to 100 Resend suppressions by IDs or addresses.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(SUPPRESSION_BATCH_REMOVE_SCHEMA) .output(SUPPRESSION_BATCH_DELETE_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler( async ({ account, input }) => await getResendApi(account).call("suppressions/batch/remove", { body: input.emails === undefined ? { ids: input.ids } : { emails: input.emails }, httpMethod: "POST", responseSchema: SUPPRESSION_BATCH_DELETE_SCHEMA, }), )