export interface SharedAgentOptions { /** Enable TCP keep-alive. Default: true */ keepAlive?: boolean; /** Idle keep-alive duration in ms. Default: 30_000 */ keepAliveMsecs?: number; /** Max concurrent sockets per host. Default: 25 */ maxSockets?: number; /** Max idle sockets in pool. Default: 10 */ maxFreeSockets?: number; /** Socket timeout in ms. Default: 60_000 */ timeout?: number; /** Reject unauthorized TLS certificates. Default: true (secure). Set to false only for testing/development. */ rejectUnauthorized?: boolean; /** DNS cache TTL in seconds. Default: 300 */ dnsCacheTtl?: number; } export interface ProxyConfig { /** "http://host:port" | "https://host:port" | "socks5://host:port" | "socks5h://host:port". Catcher treats socks5 as remote DNS. */ url: string; auth?: { username: string; password: string; }; noProxy?: string[]; } export interface DnsConfig { /** DNS mode. Default catcher. Use native only when you want the transport resolver. */ mode?: 'catcher' | 'native'; /** Custom DNS nameservers (e.g. ["8.8.8.8"]) */ nameservers?: string[]; /** Hostname → IP mapping for custom DNS resolution */ hostMapping?: Record; /** Allow fallback to default nameservers when system DNS config cannot be read. Default: false */ fallbackToDefaultNameservers?: boolean; } export interface TlsConfig { /** Whether to reject unauthorized certificates (default: true) — TS ✅ / Rust ✅ */ rejectUnauthorized?: boolean; /** Path to CA certificate PEM file — TS ✅ / Rust ✅ */ caCertPath?: string; /** CA certificate PEM content — TS ✅ / Rust ✅ */ caCertPem?: string; /** Path to client certificate PEM file — TS ✅ / Rust ✅ */ clientCertPath?: string; /** Client certificate PEM content — TS ✅ / Rust ✅ */ clientCertPem?: string; /** Path to client private key PEM file — TS ✅ / Rust ✅ */ clientKeyPath?: string; /** Client private key PEM content — TS ✅ / Rust ✅ */ clientKeyPem?: string; /** PFX/PKCS12 client identity (binary) — TS ✅ / Rust ❌ */ clientIdentityPfx?: Uint8Array; /** Password for PFX identity — TS ✅ / Rust ❌ */ clientIdentityPassword?: string; /** Override TLS SNI hostname — TS ✅ / Rust ✅ */ tlsSniOverride?: string; /** Minimum TLS version — TS ✅ / Rust ✅ */ minTlsVersion?: '1.0' | '1.1' | '1.2' | '1.3'; /** * SHA-256 public key pins — TS ❌ / Rust ❌ (deferred) * Requires custom cert verifier in both Node.js and rustls. * See NEW-1 in handoff doc. */ pinSha256?: string[]; } export interface RedirectInfo { url: string; status: number; headers: Record; } export interface HttpClientConfig { /** Base URL for all requests */ baseURL: string; /** Connection layer options */ keepAlive?: boolean; dnsCacheTtl?: number; rejectUnauthorized?: boolean; /** Timeout options in ms */ timeout?: { connect?: number; response?: number; } | number; /** Auto-retry on failure */ retry?: { attempts: number; backoff?: 'fixed' | 'exponential'; retryIf?: (error: any) => boolean; /** Called on each retry attempt (attempt number 1-based) */ onRetry?: (attempt: number) => void; /** Minimum retry delay in ms */ minTimeout?: number; /** Maximum retry delay in ms */ maxTimeout?: number; }; /** Max concurrent requests */ concurrency?: number; /** Circuit breaker */ circuitBreaker?: { failureThreshold: number; resetTimeout: number; }; /** Request/response interceptors (axios-compatible) */ interceptors?: { request?: Array<(config: any) => any>; response?: Array<(response: any) => any>; }; /** Browser fetch credentials policy */ credentials?: 'include' | 'same-origin' | 'omit'; /** Browser fetch mode */ fetchMode?: 'cors' | 'no-cors' | 'same-origin' | 'navigate'; /** Node.js axios withCredentials */ withCredentials?: boolean; /** HTTP/SOCKS5 proxy: true = auto-detect env, string = proxy URL, object = full config */ proxy?: boolean | string | ProxyConfig; redirect?: { follow?: boolean; maxRedirects?: number; beforeRedirect?: (info: RedirectInfo) => boolean; }; dns?: DnsConfig; tls?: TlsConfig; /** @deprecated Not yet consumed by the client. Reserved for future use. */ adapter?: TransportAdapter; /** Basic authentication */ auth?: { username: string; password: string; }; /** Bearer token — static string or async function for dynamic refresh */ bearerToken?: string | (() => string | Promise); /** XSRF/CSRF cookie name (browser only, reads from document.cookie) */ xsrfCookieName?: string; /** XSRF/CSRF header name. Default: "X-XSRF-TOKEN" */ xsrfHeaderName?: string; } export interface RequestConfig { /** Per-request headers, merged with instance defaults */ headers?: Record; /** Override timeout for this request (ms) */ timeout?: number; /** AbortController signal for cancellation */ signal?: AbortSignal; /** Override instance-level retry; false = disable retry for this request */ retry?: RetryOptions | false; /** Response body parsing mode */ responseType?: 'json' | 'text' | 'bytes' | 'stream'; /** Custom success status code predicate */ validateStatus?: (status: number) => boolean; /** Override priority (0 = highest) */ priority?: number; /** Opaque metadata, passed through to response interceptors */ meta?: Record; /** Query parameters appended to URL */ params?: Record; /** Custom params serializer */ paramsSerializer?: (params: Record) => string; /** Upload progress callback */ onUploadProgress?: (event: ProgressEvent) => void; /** Download progress callback */ onDownloadProgress?: (event: ProgressEvent) => void; credentials?: 'include' | 'same-origin' | 'omit'; proxy?: boolean | string | ProxyConfig; } export interface ProgressEvent { loaded: number; total?: number; } export interface InterceptorFulfilled { (value: T): T | Promise; } export interface InterceptorRejected { (error: any): any; } export interface InterceptorHandler { onFulfilled: InterceptorFulfilled; onRejected?: InterceptorRejected; runWhen?: (config: RequestConfig) => boolean; synchronous?: boolean; } export interface InterceptorManager { use(onFulfilled: InterceptorFulfilled, onRejected?: InterceptorRejected, options?: { runWhen?: (config: RequestConfig) => boolean; synchronous?: boolean; }): number; eject(id: number): void; clear(): void; } /** Response object passed through response interceptors */ export interface HttpResponse { status: number; headers: Record; data: T; config: RequestConfig; } export interface IHttpClient { get(url: string, config?: RequestConfig): Promise; post(url: string, body?: any, config?: RequestConfig): Promise; put(url: string, body?: any, config?: RequestConfig): Promise; delete(url: string, config?: RequestConfig): Promise; patch(url: string, body?: any, config?: RequestConfig): Promise; /** Dynamic interceptor managers */ interceptors: { request: InterceptorManager; response: InterceptorManager; }; /** Current circuit breaker state */ circuitBreakerState(): 'closed' | 'open' | 'half-open'; /** Number of requests waiting in the concurrency queue */ queueDepth(): number; /** Subscribe to client events. Returns unsubscribe function. */ on?(event: ClientEvent['type'], listener: (event: ClientEvent) => void): () => void; /** Unsubscribe from client events */ off?(event: ClientEvent['type'], listener?: (event: ClientEvent) => void): void; /** Hot-update retry configuration at runtime */ updateConfig?(updates: Partial>): void; } export interface ResilientWSOptions { /** WebSocket server URL(s). Multiple = multi-endpoint racing */ url: string | string[]; /** Sub-protocols */ protocol?: string | string[]; /** Enable per-message deflate compression */ perMessageDeflate?: boolean | { threshold?: number; }; /** Handshake timeout in ms. Default: 10_000 */ handshakeTimeout?: number; /** Max payload in bytes. Default: 1MB */ maxPayload?: number; /** Auto-reconnect strategy */ reconnect?: { initialDelay?: number; maxDelay?: number; backoffMultiplier?: number; maxAttempts?: number; }; /** Multi-endpoint: how many to race. Default: 3 */ raceCount?: number; /** Custom headers */ headers?: Record; /** Skip TLS cert validation */ rejectUnauthorized?: boolean; /** DNS configuration. Not setting dns lets the transport use its native resolver. */ dns?: DnsConfig; /** TLS configuration */ tls?: TlsConfig; cookie?: string; proxy?: boolean | string | ProxyConfig; } export interface ResilientWS extends EventTarget { send(data: string | Uint8Array): void; close(code?: number, reason?: string): void; readonly readyState: number; readonly url: string; readonly status: 'CONNECTING' | 'CONNECTED' | 'CLOSED'; addEventListener(type: 'open' | 'close' | 'message' | 'error' | 'statuschange', listener: EventListener): void; removeEventListener(type: string, listener: EventListener): void; } export interface PriorityQueueOptions { /** Max concurrent tasks. Default: 10 */ concurrency?: number; /** Queue timeout in ms. Default: no timeout */ timeout?: number; } export interface RetryOptions { attempts: number; backoff?: 'fixed' | 'exponential'; minTimeout?: number; maxTimeout?: number; /** Called on each retry attempt. attemptNum: 1-based retry number (1 = first retry) */ onRetry?: (attemptNum: number) => void; } export interface SSEStreamOptions { /** SSE endpoint URL */ url: string; /** HTTP method, default 'GET'. AI scenarios typically use 'POST' */ method?: 'GET' | 'POST'; /** Request headers (e.g. Authorization) */ headers?: Record; /** Request body (POST). Objects are auto JSON.stringify'd */ body?: string | Record; /** Request timeout in ms, default 30_000 */ timeout?: number; /** Abort signal */ signal?: AbortSignal; } export interface SSEClientOptions extends SSEStreamOptions { /** Auto-reconnect configuration */ reconnect?: { enabled?: boolean; maxRetries?: number; initialDelay?: number; maxDelay?: number; backoffMultiplier?: number; }; /** Circuit breaker configuration */ circuitBreaker?: { failureThreshold: number; resetTimeout: number; }; } /** * SSE content line stream — yields content lines, silently filters control lines. * * Library silently handles: * - `id:` → records lastEventId for reconnect * - `retry:` → adjusts reconnect interval * - `: comment` → heartbeat, consumed * - empty line → event separator, consumed * - chunk buffering → guarantees complete lines per yield */ export interface SSEStream extends AsyncIterable { /** Extracted from `id:` lines, used for reconnect Last-Event-ID */ readonly lastEventId: string; } export interface SSEClient extends AsyncIterable { readonly readyState: 'CONNECTING' | 'OPEN' | 'CLOSED'; readonly lastEventId: string; /** Close the connection (only for createSSEClient) */ close(): void; } export interface SSETimeoutError extends Error { readonly type: 'SSE_TIMEOUT'; } export type CatcherErrorType = 'timeout' | 'connection' | 'dns' | 'tls' | 'http' | 'cancelled' | 'unknown'; export interface CatcherHttpError extends Error { readonly type: CatcherErrorType; readonly request: { method: string; url: string; headers: Record; config: RequestConfig; }; readonly response?: { status: number; headers: Record; data: unknown; rawData?: Uint8Array; }; readonly attempt: number; readonly elapsedMs: number; toJSON(): Record; } export declare function isCatcherError(err: unknown): err is CatcherHttpError; /** @deprecated Not yet consumed by the client. Reserved for future use. */ export interface TransportAdapter { execute(config: RequestConfig & { method: string; url: string; body?: any; }): Promise; } export type QualityLevel = 'excellent' | 'good' | 'fair' | 'poor' | 'bad'; export type ClientEvent = { type: 'retry'; attempt: number; error: Error; url: string; } | { type: 'requestComplete'; method: string; url: string; status: number; durationMs: number; } | { type: 'circuitBreakerChange'; from: 'closed' | 'open' | 'half-open'; to: 'closed' | 'open' | 'half-open'; } | { type: 'networkQualityChange'; from: QualityLevel; to: QualityLevel; };