export type CloudflareAccount = 'default' | 'kody' | 'pages'
export type CloudflareAccountInfo = {
account: CloudflareAccount
label: string
default: boolean
secretName: string
useWhen: string
avoidWhen: string
}
export type CloudflareAuthOptions = {
/**
* Credential alias mapped to a known Kody secret. Defaults to `default`
* (`cloudflareApiToken`).
*/
account?: CloudflareAccount
/**
* Explicit Kody secret name when no alias covers the token. Never pass a raw
* token value — only the secret's name. Mutually exclusive with `account`.
*/
apiTokenSecret?: string
}
export const DEFAULT_CLOUDFLARE_ACCOUNT: CloudflareAccount = 'default'
const cloudflareAccounts = [
{
account: 'default',
label: 'Default Cloudflare API token',
default: true,
secretName: 'cloudflareApiToken',
useWhen:
'Routine Cloudflare API work against accounts and zones covered by the primary token.',
avoidWhen:
'The primary token is not authorized for the target account (for example the Kody Cloudflare account).',
},
{
account: 'kody',
label: 'Kody Cloudflare account token',
default: false,
secretName: 'cloudflareApiTokenKodyAccount',
useWhen:
'Calls against the Kody Cloudflare account (for example Kody production D1, Workers, or Log Explorer on that account). Typically an account-scoped token — verify with kody:@kentcdodds/cloudflare/verify ({ account: "kody" }), not /user/tokens/verify alone.',
avoidWhen: 'Zones and resources that the default token already covers.',
},
{
account: 'pages',
label: 'Cloudflare Pages API token',
default: false,
secretName: 'cloudflarePagesApiToken',
useWhen: 'Cloudflare Pages operations that require the dedicated Pages token.',
avoidWhen: 'General API, analytics, logs, or WAF work better served by default or kody.',
},
] as const satisfies readonly CloudflareAccountInfo[]
const SECRET_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/
/**
* Return the supported Cloudflare account aliases and selection guidance.
*/
export function accounts(): readonly CloudflareAccountInfo[] {
return cloudflareAccounts
}
/**
* Return documentation for one Cloudflare account alias.
*/
export function getAccountInfo(
account: CloudflareAccount = DEFAULT_CLOUDFLARE_ACCOUNT,
): CloudflareAccountInfo {
const info = cloudflareAccounts.find((candidate) => candidate.account === account)
if (!info) {
throw new Error('Unsupported Cloudflare account: ' + String(account))
}
return info
}
/**
* Resolve the Kody secret name for an optional account alias or explicit secret.
*/
export function resolveApiTokenSecretName(options: CloudflareAuthOptions = {}): string {
const hasExplicit =
options.apiTokenSecret !== undefined &&
options.apiTokenSecret !== null &&
String(options.apiTokenSecret).trim() !== ''
if (hasExplicit && options.account !== undefined) {
throw new Error('Pass either account or apiTokenSecret, not both.')
}
if (hasExplicit) {
const name = String(options.apiTokenSecret).trim()
if (!SECRET_NAME.test(name)) {
throw new Error(
'apiTokenSecret must be a simple Kody secret name (letters, numbers, underscore).',
)
}
return name
}
const account = options.account ?? DEFAULT_CLOUDFLARE_ACCOUNT
switch (account) {
case 'default':
return 'cloudflareApiToken'
case 'kody':
return 'cloudflareApiTokenKodyAccount'
case 'pages':
return 'cloudflarePagesApiToken'
default: {
const exhaustive: never = account
throw new Error('Unsupported Cloudflare account: ' + String(exhaustive))
}
}
}
/**
* Build the Authorization header value using a `{{secret:name}}` placeholder.
* Never accepts or returns a raw token value.
*/
export function getAuthorizationHeader(options: CloudflareAuthOptions = {}): string {
const secretName = resolveApiTokenSecretName(options)
return `Bearer {{secret:${secretName}}}`
}
/**
* Common Cloudflare API headers including the selected token placeholder.
*/
export function cloudflareAuthHeaders(
options: CloudflareAuthOptions = {},
): Record<string, string> {
return {
Accept: 'application/json',
Authorization: getAuthorizationHeader(options),
'User-Agent': 'kody-cloudflare/1.0',
}
}
/**
* Pick auth-related fields from a wider params object.
*/
export function pickAuthOptions(params: CloudflareAuthOptions = {}): CloudflareAuthOptions {
const out: CloudflareAuthOptions = {}
if (params.account !== undefined) out.account = params.account
if (params.apiTokenSecret !== undefined) out.apiTokenSecret = params.apiTokenSecret
return out
}