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_PROPERTY_KEY_SCHEMA = z .string() .min(1) .max(50) .regex(/^[A-Za-z0-9_]+$/) const CONTACT_PROPERTY_INPUT_SCHEMA = z.discriminatedUnion("type", [ z.object({ /** Optional value used when a string property is unset. */ fallbackValue: z.string().nullable().optional(), /** Contact-property key. */ key: CONTACT_PROPERTY_KEY_SCHEMA, /** Property value type. */ type: z.literal("string"), }), z.object({ /** Optional value used when a numeric property is unset. */ fallbackValue: z.number().nullable().optional(), /** Contact-property key. */ key: CONTACT_PROPERTY_KEY_SCHEMA, /** Property value type. */ type: z.literal("number"), }), ]) const CONTACT_PROPERTY_WIRE_SCHEMA = z.discriminatedUnion("type", [ z.object({ created_at: z.string(), fallback_value: z.string().nullable(), id: z.string(), key: z.string(), object: z.literal("contact_property").optional(), type: z.literal("string"), }), z.object({ created_at: z.string(), fallback_value: z.number().nullable(), id: z.string(), key: z.string(), object: z.literal("contact_property").optional(), type: z.literal("number"), }), ]) const CONTACT_PROPERTY_SCHEMA = CONTACT_PROPERTY_WIRE_SCHEMA.transform( ({ created_at: createdAt, fallback_value: fallbackValue, ...property }) => ({ ...property, createdAt, fallbackValue, }), ) const CONTACT_PROPERTY_LIST_WIRE_SCHEMA = z.object({ data: CONTACT_PROPERTY_WIRE_SCHEMA.array(), has_more: z.boolean(), object: z.literal("list"), }) const CONTACT_PROPERTY_LIST_SCHEMA = z .object({ data: CONTACT_PROPERTY_SCHEMA.array(), has_more: z.boolean(), object: z.literal("list"), }) .transform(({ has_more: hasMore, ...result }) => ({ ...result, hasMore })) const CONTACT_PROPERTY_MUTATION_SCHEMA = z.object({ id: z.string(), object: z.literal("contact_property"), }) const CONTACT_PROPERTY_DELETE_SCHEMA = CONTACT_PROPERTY_MUTATION_SCHEMA.extend({ deleted: z.boolean(), }) const PAGINATION_SCHEMA = z .object({ after: z.string().min(1).optional(), before: z.string().min(1).optional(), limit: z.number().int().min(1).max(100).prefault(20), }) .refine(({ after, before }) => !(after && before), { message: "after and before cannot be used together.", }) /** Creates a typed custom property for Resend contacts. */ export const createResendContactProperty = defineAction( "Create Resend contact property", ) .describe("Creates a string or number property for Resend contacts.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(CONTACT_PROPERTY_INPUT_SCHEMA) .output(CONTACT_PROPERTY_MUTATION_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => { const { fallbackValue, ...property } = input return await getResendApi(account).call("contact-properties", { body: { ...property, ...(fallbackValue === undefined ? {} : { fallback_value: fallbackValue }), }, httpMethod: "POST", responseSchema: CONTACT_PROPERTY_MUTATION_SCHEMA, }) }) /** Lists Resend contact properties with cursor pagination. */ export const listResendContactProperties = defineAction( "List Resend contact properties", ) .describe("Lists typed custom properties defined for Resend contacts.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(PAGINATION_SCHEMA) .output(CONTACT_PROPERTY_LIST_SCHEMA) .retry({ replaySafety: "safe" }) .handler( async ({ account, input }) => await getResendApi(account).call("contact-properties", { query: input, responseSchema: CONTACT_PROPERTY_LIST_WIRE_SCHEMA, }), ) /** Retrieves one Resend contact property. */ export const getResendContactProperty = defineAction( "Get Resend contact property", ) .describe("Retrieves one custom Resend contact property by ID.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ propertyId: z.string().min(1) })) .output(CONTACT_PROPERTY_SCHEMA) .retry({ replaySafety: "safe" }) .handler( async ({ account, input }) => await getResendApi(account).call( `contact-properties/${encodeURIComponent(input.propertyId)}`, { responseSchema: CONTACT_PROPERTY_WIRE_SCHEMA }, ), ) /** Changes the fallback value of a Resend contact property. */ export const updateResendContactProperty = defineAction( "Update Resend contact property", ) .describe("Changes or clears a custom contact property's fallback value.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input( z.object({ /** New fallback value, or null to clear it. */ fallbackValue: z.union([z.string(), z.number()]).nullable(), /** Resend contact-property ID. */ propertyId: z.string().min(1), }), ) .output(CONTACT_PROPERTY_MUTATION_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler( async ({ account, input }) => await getResendApi(account).call( `contact-properties/${encodeURIComponent(input.propertyId)}`, { body: { fallback_value: input.fallbackValue }, httpMethod: "PATCH", responseSchema: CONTACT_PROPERTY_MUTATION_SCHEMA, }, ), ) /** Permanently deletes a Resend contact property. */ export const deleteResendContactProperty = defineAction( "Delete Resend contact property", ) .describe("Permanently deletes a custom Resend contact property.") .account(RESEND_ACCOUNT, RESEND_FULL_ACCESS_ACCOUNT_OPTIONS) .input(z.object({ propertyId: z.string().min(1) })) .output(CONTACT_PROPERTY_DELETE_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler( async ({ account, input }) => await getResendApi(account).call( `contact-properties/${encodeURIComponent(input.propertyId)}`, { httpMethod: "DELETE", responseSchema: CONTACT_PROPERTY_DELETE_SCHEMA, }, ), )