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 }