import type { DryRunResult, JsonRecord, MutationInput } from './types.ts' import { requireString } from './types.ts' import { KIT_API_BASE_URL, KIT_REQUIRED_HOST } from './setup.ts' const ALLOWED_HOSTS = new Set(['api.kit.com']) export function mutationPreview( input: MutationInput, preview: { method: string; path: string; body?: JsonRecord }, ): DryRunResult | null { if (!input.dryRun) { if (input.confirm !== true) { throw new Error( `${preview.method} ${preview.path} requires confirm: true after explicit user approval, or dryRun: true.`, ) } return null } return { dryRun: true, method: preview.method, path: preview.path, body: preview.body, } } export function rejectBroadcastSend(input: JsonRecord, action: string): void { if (input.send_at !== undefined && input.send_at !== null) { throw new Error( `${action} is draft-only and refuses send_at. Create or update a draft, then send from the Kit UI.`, ) } if (input.status === 'published' || input.status === 'sent' || input.status === 'scheduled') { throw new Error( `${action} is draft-only and refuses status ${String(input.status)}. Send from the Kit UI.`, ) } } export function normalizeKitPath(path: string): string { const trimmed = requireString(path, 'path') if (trimmed.startsWith('https://')) { const url = new URL(trimmed) if (!ALLOWED_HOSTS.has(url.host)) { throw new Error(`Kit requests must use host ${KIT_REQUIRED_HOST}. Got ${url.host}.`) } return `${url.pathname}${url.search}` } return trimmed.startsWith('/') ? trimmed : `/${trimmed}` } export function kitUrl(path: string, query?: JsonRecord): string { const normalized = normalizeKitPath(path) const url = new URL(normalized, `${KIT_API_BASE_URL.replace(/\/v4$/, '')}/`) if (!url.pathname.startsWith('/v4')) { url.pathname = `/v4${url.pathname === '/' ? '' : url.pathname}` } if (query) { for (const [key, value] of Object.entries(query)) { if (value === undefined || value === null) continue if (typeof value === 'boolean' || typeof value === 'number') { url.searchParams.set(key, String(value)) continue } if (typeof value === 'string') { url.searchParams.set(key, value) continue } throw new Error(`query.${key} must be a string, number, or boolean.`) } } return url.toString() }