export type InputRecord = Record export function inputRecord(value: unknown): InputRecord { if (value === null || typeof value !== 'object' || Array.isArray(value)) { throw new Error('Input must be an object.') } return value as InputRecord } export function requiredString(input: InputRecord, key: string): string { const value = input[key] if (typeof value !== 'string' || value.trim().length === 0) { throw new Error(key + ' is required.') } return value.trim() } export function optionalString(input: InputRecord, key: string): string | undefined { const value = input[key] if (value === undefined || value === null || value === '') return undefined if (typeof value !== 'string') throw new Error(key + ' must be a string.') return value } export function optionalBoolean(input: InputRecord, key: string): boolean | undefined { const value = input[key] if (value === undefined || value === null) return undefined if (typeof value !== 'boolean') throw new Error(key + ' must be a boolean.') return value } export function optionalNumber(input: InputRecord, key: string): number | undefined { const value = input[key] if (value === undefined || value === null || value === '') return undefined if (typeof value !== 'number' || !Number.isFinite(value)) { throw new Error(key + ' must be a number.') } return value } export function boundedLimit(value: unknown, fallback = 10, max = 50): number { if (value === undefined || value === null) return fallback if (!Number.isInteger(value) || Number(value) < 1 || Number(value) > max) { throw new Error('limit must be an integer from 1 through ' + max + '.') } return Number(value) } export function optionalRecord(input: InputRecord, key: string): InputRecord | undefined { const value = input[key] if (value === undefined || value === null) return undefined if (typeof value !== 'object' || Array.isArray(value)) { throw new Error(key + ' must be an object.') } return value as InputRecord } const TOKEN_KEYS = /^(access_token|accessToken|page_access_token|pageAccessToken)$/ /** Strip token fields from Graph payloads so helpers never leak credentials. */ export function stripSecrets(value: T): T { if (Array.isArray(value)) { return value.map((item) => stripSecrets(item)) as T } if (value && typeof value === 'object') { const out: Record = {} for (const [key, nested] of Object.entries(value as Record)) { if (TOKEN_KEYS.test(key)) continue out[key] = stripSecrets(nested) } return out as T } return value }