/** * Outbound-HTTP resilience primitives (RFC voyant#1687 Phase 3.3). * * Every outbound call from a Worker burns request CPU/subrequest budget * (now platform-enforced per plan tier), so a slow third-party must * fail fast, a flaky one must retry with jitter instead of hammering, * and a down one must trip a breaker instead of cascading. These are * the defaults the plugin clients (e-invoicing, CMS sync, payments) * and channel push wrap their fetches with — consumers stop * hand-rolling them. */ export interface RetryOptions { /** Max attempts INCLUDING the first. Default 3. */ attempts?: number; /** Base backoff before the 2nd attempt; doubles per retry. Default 250ms. */ baseDelayMs?: number; /** Backoff ceiling. Default 4s. */ maxDelayMs?: number; /** * Which failures retry. Defaults to network errors, timeouts, 429 and * 5xx responses — for requests considered idempotent (see * `retryNonIdempotent` on {@link ResilientFetchOptions}). */ retryOn?: (result: { response?: Response; error?: unknown; }) => boolean; } export interface CircuitBreakerOptions { /** Consecutive failures before the circuit opens. Default 5. */ failureThreshold?: number; /** How long an open circuit rejects immediately. Default 30s. */ openMs?: number; } /** * Minimal consecutive-failure circuit breaker. Half-open after * `openMs`: the next call probes; success closes, failure re-opens. * State is per-isolate (Workers have many isolates — the breaker bounds * each isolate's contribution to a hammering herd rather than providing * a global cutoff, which is the right scope for edge runtimes). */ export interface CircuitBreaker { /** Throws {@link CircuitOpenError} when open. */ assertClosed(): void; recordSuccess(): void; recordFailure(): void; readonly state: "closed" | "open" | "half-open"; } export declare class CircuitOpenError extends Error { readonly retryAfterMs: number; constructor(retryAfterMs: number); } export declare function createCircuitBreaker(options?: CircuitBreakerOptions): CircuitBreaker; export interface ResilientFetchOptions { /** Per-attempt timeout. Default 10s. */ timeoutMs?: number; /** Retry policy. `false` disables retries. */ retry?: RetryOptions | false; /** * Retries default to idempotent methods only (GET/HEAD/PUT/DELETE). * POSTs against APIs with their own idempotency keys (most payment / * e-invoicing providers) can opt in. */ retryNonIdempotent?: boolean; /** Optional breaker — share one per upstream service. */ breaker?: CircuitBreaker; /** Injection point for tests. Defaults to global fetch. */ fetchImpl?: (input: string | URL | Request, init?: RequestInit) => Promise; } /** * `fetch` with a per-attempt timeout, capped exponential retries with * full jitter, and an optional circuit breaker. * * Defaults: 10s timeout, 3 attempts on network errors/timeouts/429/5xx — * but only for idempotent methods unless `retryNonIdempotent` is set. * 4xx responses (other than 429) are returned, never retried. Breaker * failures count once per attempt; a `CircuitOpenError` is thrown * without touching the network. */ export declare function resilientFetch(input: string | URL | Request, init?: RequestInit, options?: ResilientFetchOptions): Promise; //# sourceMappingURL=resilience.d.ts.map