/** * Three-dimensional buyer-side circuit breaker for createX402Fetch. * * Inspected BEFORE budget checks / EIP-3009 signing on HTTP 402 pay paths: * 1. Rate — max paid 402s per rolling 60s window * 2. Minute spend — max USDC paid in rolling 60s * 3. Fingerprint dead-loop — same sanitized request fingerprint ≥2 prior times */ /** Rolling window for rate / spend / fingerprint (ms). */ export declare const CIRCUIT_BREAKER_WINDOW_MS = 60000; /** Default max paid 402s in the rolling window (N_max). */ export declare const DEFAULT_MAX_PAID_REQUESTS_PER_MINUTE = 10; /** Default max USDC paid in the rolling window (S_max). */ export declare const DEFAULT_MAX_SPEND_USDC_PER_MINUTE = 0.05; /** Truncate non-JSON / oversized body strings before hashing. */ export declare const FINGERPRINT_BODY_MAX_CHARS = 4096; export type CircuitBreakerLimits = { maxPaidRequestsPerMinute: number; maxSpendUsdcPerMinute: number; enableFingerprintBreaker: boolean; }; export type CircuitBreakerEvent = { at: number; fingerprint: string; amountUsdc: number; }; export type CircuitBreaker = { events: CircuitBreakerEvent[]; readonly limits: CircuitBreakerLimits; readonly windowMs: number; }; export type CircuitBreakerConfig = Partial & { windowMs?: number; }; export declare function createCircuitBreaker(config?: CircuitBreakerConfig): CircuitBreaker; /** Drop events older than the rolling window. */ export declare function pruneCircuitBreaker(breaker: CircuitBreaker, now?: number): void; /** * Recursively strip dynamic keys from JSON-compatible values. * Used so fingerprints ignore uuid / timestamp / nonce churn. */ export declare function stripDynamicKeys(value: unknown): unknown; /** * Sanitize a request body for fingerprinting: * - JSON: parse → strip dynamic keys → stable stringify * - non-JSON: raw string truncated to FINGERPRINT_BODY_MAX_CHARS */ export declare function sanitizeBodyForFingerprint(body: string): string; /** SHA-256 hex of method + url + sanitized body. */ export declare function fingerprintRequest(method: string, url: string, body: string): string; /** * Convert fetch body init to a string for fingerprinting. * Best-effort: strings / URLSearchParams / buffers; otherwise empty. */ export declare function bodyInitToString(body: BodyInit | null | undefined): Promise; /** Resolve method / url / body text from fetch arguments. */ export declare function resolveRequestParts(input: RequestInfo | URL, init?: RequestInit): Promise<{ method: string; url: string; bodyText: string; }>; /** * Enforce the three circuit dimensions before signing a 402 payment. * @throws Error with a `CIRCUIT_BREAKER:` prefix when halted */ export declare function assertCircuitAllowsPayment(breaker: CircuitBreaker, fingerprint: string, amountUsdc: number, now?: number): void; /** Record a successfully signed paid 402 into the rolling window. */ export declare function recordCircuitPayment(breaker: CircuitBreaker, fingerprint: string, amountUsdc: number, now?: number): void;