import type { HumanInputV2ErrorCategory } from './types' const CATEGORY_BY_CODE: Record = { expired: 'form-expired', already_submitted: 'already-submitted', workflow_not_active: 'unavailable', not_found: 'not-found', human_input_form_not_found: 'not-found', human_input_form_expired: 'form-expired', human_input_form_submitted: 'already-submitted', web_form_rate_limit_exceeded: 'form-rate-limit', human_input_access_rate_limit_exceeded: 'access-rate-limit', human_input_access_delivery_failed: 'access-delivery-failed', human_input_invalid_otp: 'invalid-otp', human_input_challenge_expired: 'challenge-expired', human_input_challenge_stale: 'challenge-stale', human_input_upload_failed: 'upload-failed', human_input_v2_unavailable: 'unavailable', } const SAFE_MESSAGE_BY_CATEGORY: Record = { 'not-found': 'Human Input form not found', 'form-expired': 'Human Input form expired', 'already-submitted': 'Human Input form already submitted', 'form-rate-limit': 'Human Input form rate limited', 'access-rate-limit': 'Human Input access request rate limited', 'access-delivery-failed': 'Human Input access delivery failed', 'invalid-otp': 'Human Input verification code is invalid', 'challenge-expired': 'Human Input challenge expired', 'challenge-stale': 'Human Input challenge is stale', 'upload-failed': 'Human Input file upload failed', network: 'Human Input request failed because the network is unavailable', unavailable: 'Human Input v2 service is unavailable', unknown: 'Human Input request failed', } export class HumanInputV2TransportError extends Error { category: HumanInputV2ErrorCategory code: string status?: number constructor(category: HumanInputV2ErrorCategory, code: string, status?: number) { super(SAFE_MESSAGE_BY_CATEGORY[category]) this.name = 'HumanInputV2TransportError' this.category = category this.code = code this.status = status } } type ErrorLike = { code?: unknown status?: unknown name?: unknown data?: { code?: unknown; body?: { code?: unknown } } } export const normalizeHumanInputV2Error = (error: unknown): HumanInputV2TransportError => { if (error instanceof HumanInputV2TransportError) return error const candidate = error as ErrorLike | null const responseCode = candidate?.data?.body?.code ?? candidate?.data?.code ?? candidate?.code const code = typeof responseCode === 'string' ? responseCode : 'human_input_unknown' const status = typeof candidate?.status === 'number' ? candidate.status : undefined const category = CATEGORY_BY_CODE[code] ?? (candidate?.name === 'AbortError' ? 'network' : undefined) ?? (status === 404 ? 'not-found' : undefined) ?? (status === 410 ? 'form-expired' : undefined) ?? (status === 429 ? 'form-rate-limit' : undefined) ?? (status === 501 ? 'unavailable' : undefined) ?? (candidate instanceof TypeError ? 'network' : undefined) ?? 'unknown' return new HumanInputV2TransportError(category, code, status) } export const isTerminalFormError = (category: HumanInputV2ErrorCategory) => ['not-found', 'form-expired', 'already-submitted', 'form-rate-limit'].includes(category)