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()
}