Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/resend

src/domains.ts

163 lines · 4.8 KB · TypeScript
import {
	domainSummary,
	mutationPreview,
	parseAction,
	resendRequest,
	unwrapList,
	type MutationGuardInput,
	type ResendAuthOptions,
} from './resend-core.ts'

/** GET /domains — sending domains as compact summaries. */
export async function listDomains(input: ResendAuthOptions = {}) {
	const body = await resendRequest({
		path: '/domains',
		account: input.account,
		secretName: input.secretName,
		integration: input.integration,
	})
	return unwrapList(body).map((domain) => domainSummary(domain)).filter(Boolean)
}

/** GET /domains/{domain_id} — full detail including DNS records. */
export async function getDomain(input: ResendAuthOptions & { domainId: string }) {
	if (!input.domainId) throw new Error('getDomain: domainId is required')
	return await resendRequest({
		path: '/domains/' + encodeURIComponent(input.domainId),
		account: input.account,
		secretName: input.secretName,
		integration: input.integration,
	})
}

export type CreateDomainInput = MutationGuardInput & {
	name: string
	region?: 'us-east-1' | 'eu-west-1' | 'sa-east-1' | 'ap-northeast-1'
	custom_return_path?: string
}

/** POST /domains — register a sending domain. Response includes DNS records. */
export async function createDomain(input: CreateDomainInput) {
	if (!input.name) throw new Error('createDomain: name is required (e.g. "mail.example.com")')
	const body = {
		name: input.name,
		region: input.region,
		custom_return_path: input.custom_return_path,
	}
	const preview = mutationPreview(input, {
		action: 'create domain ' + input.name,
		method: 'POST',
		path: '/domains',
		body,
	})
	if (preview) return preview
	return await resendRequest({
		path: '/domains',
		method: 'POST',
		body,
		account: input.account,
		secretName: input.secretName,
		integration: input.integration,
	})
}

/** POST /domains/{domain_id}/verify — trigger DNS verification. */
export async function verifyDomain(input: MutationGuardInput & { domainId: string }) {
	if (!input.domainId) throw new Error('verifyDomain: domainId is required')
	const preview = mutationPreview(input, {
		action: 'verify domain ' + input.domainId,
		method: 'POST',
		path: '/domains/' + input.domainId + '/verify',
	})
	if (preview) return preview
	return await resendRequest({
		path: '/domains/' + encodeURIComponent(input.domainId) + '/verify',
		method: 'POST',
		account: input.account,
		secretName: input.secretName,
		integration: input.integration,
	})
}

export type UpdateDomainSettingsInput = MutationGuardInput & {
	domainId: string
	click_tracking?: boolean
	open_tracking?: boolean
	tls?: 'enforced' | 'opportunistic'
}

/** PATCH /domains/{domain_id} — tracking and TLS settings. */
export async function updateDomainSettings(input: UpdateDomainSettingsInput) {
	if (!input.domainId) throw new Error('updateDomainSettings: domainId is required')
	const body = {
		click_tracking: input.click_tracking,
		open_tracking: input.open_tracking,
		tls: input.tls,
	}
	const preview = mutationPreview(input, {
		action: 'update domain settings ' + input.domainId,
		method: 'PATCH',
		path: '/domains/' + input.domainId,
		body,
	})
	if (preview) return preview
	return await resendRequest({
		path: '/domains/' + encodeURIComponent(input.domainId),
		method: 'PATCH',
		body,
		account: input.account,
		secretName: input.secretName,
		integration: input.integration,
	})
}

/** DELETE /domains/{domain_id}. Destructive; requires confirm: true. */
export async function deleteDomain(input: MutationGuardInput & { domainId: string }) {
	if (!input.domainId) throw new Error('deleteDomain: domainId is required')
	const preview = mutationPreview(input, {
		action: 'delete domain ' + input.domainId,
		method: 'DELETE',
		path: '/domains/' + input.domainId,
		requireConfirm: true,
	})
	if (preview) return preview
	return await resendRequest({
		path: '/domains/' + encodeURIComponent(input.domainId),
		method: 'DELETE',
		account: input.account,
		secretName: input.secretName,
		integration: input.integration,
	})
}

const domainActions = [
	'list-domains',
	'get-domain',
	'create-domain',
	'verify-domain',
	'update-domain-settings',
	'delete-domain',
] as const

/** Domains dispatcher. Defaults to list-domains. */
export default async function domains(input: Record<string, unknown> = {}) {
	const action = parseAction(input.action, domainActions, 'list-domains', 'domains')
	switch (action) {
		case 'list-domains':
			return await listDomains(input)
		case 'get-domain':
			return await getDomain(input as never)
		case 'create-domain':
			return await createDomain(input as CreateDomainInput)
		case 'verify-domain':
			return await verifyDomain(input as never)
		case 'update-domain-settings':
			return await updateDomainSettings(input as UpdateDomainSettingsInput)
		case 'delete-domain':
			return await deleteDomain(input as never)
		default: {
			const exhaustive: never = action
			throw new Error('Unhandled domains action: ' + String(exhaustive))
		}
	}
}