/** * @fileoverview Shared Airtable types: `JsonRecord`, `AirtableAuthMode`, `AirtableAuthInput`, `AirtablePageInfo`, `AirtableBaseSummary`, `AirtableFieldSummary`, `AirtableViewSummary`, `AirtableTableSummary`, and related shapes. * Import from `kody:@kody/airtable/types` when typing Airtable helpers. Default export returns a type-name catalog. * * @example * import { type AirtableAuthMode } from 'kody:@kody/airtable/types' */ export type JsonRecord = Record export type AirtableAuthMode = 'oauth' | 'pat' export type AirtableAuthInput = { /** Saved OAuth integration name. Defaults to `airtable`. */ integrationName?: string /** Alias of `integrationName`. */ integration?: string /** * Short account alias. `work` → `airtable-work`. Values that already start * with `airtable-` are used as-is. `default` / `airtable` / omitted → `airtable`. */ account?: string /** User secret name for a personal access token. Defaults to `airtablePat`. */ secretName?: string /** Force OAuth or PAT auth when both exist. */ auth?: AirtableAuthMode } export type AirtablePageInfo = { hasNextPage: boolean nextOffset: string | null } export type AirtableBaseSummary = { id: string name: string permissionLevel: string | null } export type AirtableFieldSummary = { id: string name: string type: string | null description: string | null } export type AirtableViewSummary = { id: string name: string type: string | null } export type AirtableTableSummary = { id: string name: string description: string | null primaryFieldId: string | null fieldCount: number viewCount: number fields: Array views: Array } export type AirtableRecordSummary = { id: string createdTime: string | null commentCount: number | null fields: JsonRecord } export type AirtableCommentAuthor = { id: string name: string | null } export type AirtableCommentSummary = { id: string text: string | null createdTime: string | null lastUpdatedTime: string | null author: AirtableCommentAuthor | null } export type DryRunResult = { dryRun: true wouldCall: T } /** * Shared Airtable types and parsing helpers for this package. * Import from `kody:@kody/airtable/types` when typing other Airtable exports. * * @returns Catalog of exported type/helper names for agent discovery. * * @example * import types from 'kody:@kody/airtable/types' * const catalog = await types() */ export function requireRecord(value: unknown, label: string): JsonRecord { if (!value || typeof value !== 'object' || Array.isArray(value)) { throw new Error(`${label} must be an object.`) } return value as JsonRecord } export function requireString( value: unknown, label: string, options: { allowEmpty?: boolean } = {}, ): string { if (typeof value !== 'string' || (!options.allowEmpty && value.trim().length === 0)) { throw new Error( `${label} must be ${options.allowEmpty ? 'a string' : 'a non-empty string'}.`, ) } return options.allowEmpty ? value : value.trim() } export function optionalString(value: unknown, label: string): string | undefined { if (value === undefined || value === null) return undefined return requireString(value, label) } export function optionalBoolean(value: unknown, label: string): boolean | undefined { if (value === undefined) return undefined if (typeof value !== 'boolean') throw new Error(`${label} must be a boolean.`) return value } export function optionalStringArray(value: unknown, label: string): Array | undefined { if (value === undefined || value === null) return undefined if (!Array.isArray(value)) throw new Error(`${label} must be an array of strings.`) return value.map((item, index) => requireString(item, `${label}[${index}]`)) } export function clampInt( value: unknown, min: number, max: number, fallback: number, label = 'limit', ): number { if (value === undefined || value === null) return fallback if (typeof value !== 'number' || !Number.isInteger(value)) { throw new Error(`${label} must be an integer.`) } if (value < min || value > max) { throw new Error(`${label} must be between ${min} and ${max}.`) } return value } export function compactRecord(value: T): T { const output: JsonRecord = {} for (const [key, item] of Object.entries(value)) { if (item === undefined) continue output[key] = item } return output as T } export function requireConfirmOrDryRun( input: { confirm?: boolean; dryRun?: boolean }, action: string, ): 'dryRun' | 'confirm' { if (input.dryRun === true) return 'dryRun' if (input.confirm === true) return 'confirm' throw new Error( `${action} requires confirm: true after explicit user approval, or dryRun: true.`, ) } /** * Shared Airtable types for this package: `JsonRecord`, `AirtableAuthMode`, `AirtableAuthInput`, `AirtablePageInfo`, `AirtableBaseSummary`, `AirtableFieldSummary`, `AirtableViewSummary`, `AirtableTableSummary`, and related shapes. * Import from `kody:@kody/airtable/types` when typing Airtable helpers without pulling runtime clients. * * @returns Catalog of exported type names for agent discovery. * * @example * import types from 'kody:@kody/airtable/types' * const catalog = await types() */ export default async function typesOverview() { return { auth: ['AirtableAuthInput', 'AirtableAuthMode'], models: [ 'AirtableBaseSummary', 'AirtableTableSummary', 'AirtableRecordSummary', 'AirtableCommentSummary', ], } }