Repository Public
1import type { Provider } from '@aos/shared';23export interface ProviderErrorInit {4 provider: Provider;5 retryable: boolean;6 status?: number | null;7 code?: string | null;8 requestId?: string | null;9 retryAfterMs?: number | null;10 attempts?: number;11 cause?: unknown;12}1314/**15 * The only error type thrown by the adapters. `message` comes from the vendor's error body or from this16 * package; it never contains request headers or API keys.17 */18export class ProviderError extends Error {19 readonly provider: Provider;20 readonly retryable: boolean;21 readonly status: number | null;22 readonly code: string | null;23 readonly requestId: string | null;24 readonly retryAfterMs: number | null;25 attempts: number;2627 constructor(message: string, init: ProviderErrorInit) {28 super(message, init.cause === undefined ? undefined : { cause: init.cause });29 this.name = 'ProviderError';30 this.provider = init.provider;31 this.retryable = init.retryable;32 this.status = init.status ?? null;33 this.code = init.code ?? null;34 this.requestId = init.requestId ?? null;35 this.retryAfterMs = init.retryAfterMs ?? null;36 this.attempts = init.attempts ?? 1;37 }3839 toJSON(): Record<string, unknown> {40 return {41 name: this.name, message: this.message, provider: this.provider, retryable: this.retryable,42 status: this.status, code: this.code, requestId: this.requestId, attempts: this.attempts,43 };44 }45}4647/** `retry-after-ms` (milliseconds) wins over `retry-after` (seconds or HTTP date). Null when absent/invalid. */48export function parseRetryAfter(headers: unknown, nowMs: number = Date.now()): number | null {49 const get = (name: string): string | null => {50 if (headers && typeof (headers as Headers).get === 'function') return (headers as Headers).get(name);51 if (headers && typeof headers === 'object') {52 const v = (headers as Record<string, unknown>)[name];53 return typeof v === 'string' ? v : null;54 }55 return null;56 };57 const ms = get('retry-after-ms');58 if (ms !== null) {59 const n = Number(ms);60 if (Number.isFinite(n) && n >= 0) return n;61 }62 const s = get('retry-after');63 if (s !== null) {64 const n = Number(s);65 if (Number.isFinite(n) && n >= 0) return n * 1000;66 const date = Date.parse(s);67 if (Number.isFinite(date)) return Math.max(0, date - nowMs);68 }69 return null;70}71