Skip to content

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

Package listing

@kody/postmark

src/smoke-test.ts

119 lines · 3.5 KB · TypeScript
import { kody } from 'kody:runtime'
import {
	API_HOST,
	DEFAULT_ACCOUNT_SECRET,
	DEFAULT_SERVER_SECRET,
	resolveAccountSecretName,
	resolveServerSecretName,
	secretSetupUrl,
	type PostmarkAuthOptions,
} from './core.ts'
import { sendEmail } from './emails.ts'
import { searchOutboundMessages } from './messages.ts'
import { getServer } from './servers.ts'

function secretEntries(result: unknown): Array<{ name?: string; scope?: string }> {
	if (result && typeof result === 'object' && Array.isArray((result as { secrets?: unknown }).secrets)) {
		return (result as { secrets: Array<{ name?: string; scope?: string }> }).secrets
	}
	return Array.isArray(result) ? result : []
}

async function listUserSecretNames(): Promise<Set<string>> {
	try {
		const listed = await kody.secret_list({ scope: 'user' })
		const names = new Set<string>()
		for (const entry of secretEntries(listed)) {
			if (entry?.name && (entry.scope === 'user' || !entry.scope)) names.add(entry.name)
		}
		return names
	} catch {
		return new Set()
	}
}

/**
 * Local dry-run self-check plus an optional live server + message-search read.
 *
 * Without a `postmark` Server API token this still returns
 * `{ ok: true, live: false }` and the prefilled setup URLs. Never sends mail.
 *
 * @example
 * import { smokeTest } from 'kody:@kody/postmark'
 * const result = await smokeTest()
 */
export async function smokeTest(input: PostmarkAuthOptions = {}) {
	const preview = await sendEmail({
		from: 'Sender <sender@example.com>',
		to: 'person@example.com',
		subject: 'kody postmark smoke',
		textBody: 'dry-run only',
		dryRun: true,
	})
	if (!preview || typeof preview !== 'object' || !('dryRun' in preview)) {
		throw new Error('sendEmail dryRun self-check failed.')
	}
	const dry = preview as { dryRun?: unknown; path?: unknown }
	if (dry.dryRun !== true || dry.path !== '/email') {
		throw new Error('sendEmail dryRun self-check failed.')
	}

	const serverSecret = resolveServerSecretName(input)
	const accountSecret = resolveAccountSecretName(input)
	const secretNames = await listUserSecretNames()
	const hasServerSecret = secretNames.has(serverSecret)
	const hasAccountSecret = secretNames.has(accountSecret)

	if (!hasServerSecret) {
		return {
			ok: true,
			live: false,
			selfCheck: { dryRunSendEmail: true },
			serverSecret,
			accountSecret,
			setup: {
				auth: 'server-token',
				hosts: [API_HOST],
				nextSteps: [
					'Save a Postmark Server API token as ' + serverSecret + '.',
					secretSetupUrl(serverSecret, 'server'),
					'Approve host ' + API_HOST + ' on that secret.',
					'Optional Account API token for listing all servers and managing domains: ' +
						secretSetupUrl(accountSecret, 'account'),
				],
			},
		}
	}

	const server = await getServer(input)
	const outbound = await searchOutboundMessages({ ...input, count: 5, offset: 0 })

	return {
		ok: true,
		live: true,
		selfCheck: { dryRunSendEmail: true },
		serverSecret,
		accountSecret,
		hasAccountSecret,
		server: {
			id: server.id ?? null,
			name: server.name ?? null,
			deliveryType: server.deliveryType ?? null,
			serverLink: server.serverLink ?? null,
		},
		recentOutboundCount: outbound.messages.length,
		outboundTotalCount: outbound.totalCount,
		sampleMessage: outbound.messages[0] ?? null,
		setup: {
			auth: 'server-token',
			hosts: [API_HOST],
			accountToken: hasAccountSecret
				? 'present'
				: 'optional — ' + secretSetupUrl(accountSecret, 'account'),
		},
	}
}

export default smokeTest

export { DEFAULT_ACCOUNT_SECRET, DEFAULT_SERVER_SECRET }