/** * session-fetch.ts — fetch that attaches x402 session credentials safely. * * Two invariants for every request that carries a paid session token: * * 1. Session headers always win. Caller-supplied X-Session-Token / * PAYMENT-SESSION / X-Session-Wallet (any casing) cannot replace the * stored credential. On the x402_pay session-reuse path that overwrite * used to produce a 402 and a second on-chain payment. * * 2. Redirects are not followed automatically. Node/undici `fetch` defaults * to `redirect: 'follow'` and only strips `Authorization` on a * cross-origin hop — custom entitlement headers are forwarded. Same-origin * hops are followed only when the next URL is still inside the paid * session scope. A different origin, or a same-origin path the payment * does not cover (`/v10` when the session is `/v1`), is refused so the * bearer token never leaves the resource that was paid for. */ /** Paid session boundary used to decide whether a redirect may carry the token. */ export type SessionCredentialScope = { endpoint: string; scope: 'prefix' | 'exact'; }; /** Header names that must never be caller-overridable or cross-origin forwarded. */ export declare const SESSION_CREDENTIAL_HEADERS: readonly ["X-Session-Token", "X-Session-Wallet", "PAYMENT-SESSION"]; export declare class CrossOriginSessionRedirectError extends Error { readonly fromOrigin: string; readonly toOrigin: string; constructor(fromOrigin: string, toOrigin: string); } export declare class SessionScopeRedirectError extends Error { readonly fromUrl: string; readonly toUrl: string; constructor(fromUrl: string, toUrl: string); } export declare class MalformedRedirectLocationError extends Error { readonly fromUrl: string; readonly location: string; constructor(fromUrl: string, location: string); } export declare function isSessionCredentialHeader(name: string): boolean; export declare function headersToRecord(headers: RequestInit['headers']): Record; /** * Merge caller headers with session entitlement headers. * * Caller keys that collide with a session credential (any casing) are dropped * so a Fetch `Headers` object cannot send both the attacker value and the * real token, and so a later spread cannot replace the paid credential. */ export declare function mergeSessionHeaders(callerHeaders: Record | undefined, sessionHeaders: Record): Record; /** * Fetch `url` with session credentials attached. * * Session headers are applied last. Redirects are resolved only while the * next hop stays on the same origin and inside `session`. A cross-origin * Location, or a same-origin Location outside the paid scope, is an error * and is not fetched. */ export declare function fetchWithSessionCredentials(url: string, init: RequestInit, sessionHeaders: Record, session: SessionCredentialScope): Promise; //# sourceMappingURL=session-fetch.d.ts.map