import { kitListAll, kitRequest, unwrapRecord } from './client.ts'
import { mutationPreview } from './safety.ts'
import { parseAuthInput } from './auth.ts'
import { formSummary, segmentSummary, subscriberSummary } from './models.ts'
import type { FormSummary, JsonRecord, KitAuthInput, MutationInput, SegmentSummary } from './types.ts'
import {
clampInt,
compactRecord,
optionalBoolean,
optionalString,
requireId,
requireRecord,
requireString,
} from './types.ts'
/**
* List signup forms. Pass `maxItems` (default 25). Form ids come from the
* caller's Kit account — this package has no baked-in form ids.
* @example
* import { listForms } from 'kody:@kody/kit/forms'
* const forms = await listForms({ maxItems: 20 })
*/
export async function listForms(
input: KitAuthInput & { maxItems?: number } = {},
): Promise<Array<FormSummary>> {
const items = await kitListAll<JsonRecord>({
...input,
path: '/forms',
itemKey: 'forms',
maxItems: clampInt(input.maxItems, 1, 500, 25),
})
return items.map((item) => formSummary(item)).filter((item): item is FormSummary => Boolean(item))
}
/**
* Add a subscriber to a form by email. Requires `confirm: true`, or use `dryRun: true`.
* @example
* import { addSubscriberToForm } from 'kody:@kody/kit/forms'
* const preview = await addSubscriberToForm({
* formId: 123,
* email_address: 'ada@example.com',
* dryRun: true,
* })
*/
export async function addSubscriberToForm(
input: KitAuthInput & MutationInput & { formId: number | string; email_address: string; referrer?: string },
) {
const formId = requireId(input.formId, 'formId')
const email = requireString(input.email_address, 'email_address')
const body = compactRecord({
email_address: email,
referrer: input.referrer,
})
const preview = mutationPreview(input, {
method: 'POST',
path: `/forms/${formId}/subscribers`,
body,
})
if (preview) return preview
const result = await kitRequest<JsonRecord>({
...input,
method: 'POST',
path: `/forms/${formId}/subscribers`,
body,
confirm: true,
})
return subscriberSummary(unwrapRecord(result.data, 'subscriber', 'addSubscriberToForm'))
}
/**
* List segments (read-only in Kit v4).
* @example
* import { listSegments } from 'kody:@kody/kit/forms'
* const segments = await listSegments()
*/
export async function listSegments(
input: KitAuthInput & { maxItems?: number } = {},
): Promise<Array<SegmentSummary>> {
const items = await kitListAll<JsonRecord>({
...input,
path: '/segments',
itemKey: 'segments',
maxItems: clampInt(input.maxItems, 1, 500, 25),
})
return items
.map((item) => segmentSummary(item))
.filter((item): item is SegmentSummary => Boolean(item))
}
/**
* Form and segment helpers. Defaults to `list`.
* @example
* import forms from 'kody:@kody/kit/forms'
* const all = await forms({ action: 'list' })
*/
export default async function formsEntrypoint(params: Record<string, unknown> = {}) {
const input = requireRecord(params, 'forms')
const auth = parseAuthInput(input)
const action = optionalString(input.action, 'action') ?? 'list'
switch (action) {
case 'list':
return listForms({ ...auth, maxItems: input.maxItems as number | undefined })
case 'add-subscriber':
return addSubscriberToForm({
...auth,
formId: requireId(input.formId, 'formId'),
email_address: requireString(input.email_address, 'email_address'),
referrer: optionalString(input.referrer, 'referrer'),
confirm: optionalBoolean(input.confirm, 'confirm'),
dryRun: optionalBoolean(input.dryRun, 'dryRun'),
})
case 'segments':
return listSegments({ ...auth, maxItems: input.maxItems as number | undefined })
default:
throw new Error('forms action must be one of: list, add-subscriber, segments.')
}
}