/** * Node-only x402-wrapped fetch. Reads the allowance file, checks on-chain * USDC balances through independent RPC providers, and returns a fetch wrapper * that auto-signs 402 responses only when the requested chain has confirmed * funds. * * Balance reads are pre-payment, read-only operations. They may be retried and * failed over safely; a payment payload has not been created or submitted yet. * An exhausted RPC check is never represented as a zero balance. * * The viem / @x402/* / mppx imports live behind `./_paid-stack.ts` so the * SDK's direct surface to those packages is auditable from one file and the * packages can be declared as optional peer dependencies in package.json. * * Never calls `process.exit` — the SDK leaves exit-code decisions to the * CLI edge. */ import type { CredentialsProvider } from "../credentials.js"; import { Run402Error } from "../errors.js"; import type { MppStack, X402Stack } from "./_paid-stack.js"; import { PaymentBuyerError, type PayExecutor } from "../namespaces/pay.js"; import { type PaymentAttemptStore } from "./payment-attempts.js"; type FetchFn = typeof globalThis.fetch; interface RpcClient { readContract: (args: unknown) => Promise; } interface BalanceRetryOptions { attemptsPerProvider?: number; baseDelayMs?: number; sleep?: (milliseconds: number) => Promise; random?: () => number; } interface PaymentRequirementLike { network?: string; amount?: string; [key: string]: unknown; } export interface X402PaymentRequirements { scheme: string; network: string; asset: string; amount: string; payTo: string; maxTimeoutSeconds: number; extra: Record; } export interface X402PaymentRequired { x402Version: number; error?: string; resource: { url: string; description?: string; mimeType?: string; }; accepts: X402PaymentRequirements[]; extensions?: Record; } export interface X402PaymentPayload { x402Version: number; resource?: X402PaymentRequired["resource"]; accepted: X402PaymentRequirements; payload: Record; extensions?: Record; } export interface X402BuyerClient { createPaymentPayload(required: X402PaymentRequired): Promise; } interface KnownBalance { status: "known"; balance: bigint; } interface UnknownBalance { status: "unknown"; error: X402BalanceError; } type BalanceState = KnownBalance | UnknownBalance; type BalanceStates = Record; export type X402BalanceErrorCode = "X402_RPC_TIMEOUT" | "X402_RPC_RATE_LIMITED" | "X402_RPC_UNAVAILABLE" | "X402_INSUFFICIENT_FUNDS"; /** * A machine-readable x402 balance-preflight failure. * * `safeToRetry` is true only for read-only RPC failures. A confirmed balance * miss is not retryable without changing wallet funds or payment requirements. * Both states are emitted before payment payload creation, so * `mutationState` is always `not_started`. */ /** * The largest amount a first-party (api.run402.com) challenge may ask for: * the team tier. Every gateway price is at or under it, so a challenge above * it is not a price, it is a compromised or misconfigured host — refuse to * sign rather than trust a number the server chose. Arbitrary-URL purchases * through `pay.fetch` are bounded separately by the caller's `maxUsdMicros`. */ export declare const FIRST_PARTY_MAX_PAYMENT_USD_MICROS = 20000000; /** * Refuse a first-party challenge whose every accepted requirement exceeds the * first-party cap. Requirements at or under the cap are left alone; the * selector picks among them as usual. */ export declare function assertFirstPartyPaymentWithinCap(required: unknown, firstPartyOrigin: string | null): void; /** A first-party challenge above the largest known price. Never retried blindly. */ export declare class PaymentBuyerCapError extends Run402Error { readonly kind: "local_error"; readonly code: "X402_AMOUNT_EXCEEDS_FIRST_PARTY_CAP"; constructor(requestedUsdMicros: number); } export declare class X402BalanceError extends Run402Error { readonly kind: "local_error"; readonly code: X402BalanceErrorCode; readonly cause?: unknown; constructor(code: X402BalanceErrorCode, message: string, details: Record, cause?: unknown, nextActions?: import("../errors.js").NextAction[]); } export type X402PaymentNetwork = "eip155:8453" | "eip155:84532"; /** Public-chain operations exposed to an opaque signer provider. */ export interface PaymentPublicClient { readContract(args: unknown): Promise; } /** * Minimum EVM signer shape needed by x402. Implementations may keep key * material behind KMS/HSM boundaries; only the public payer address and * signing operation cross into the SDK. */ export interface EvmPaymentSigner { readonly address: `0x${string}`; signTypedData(message: { domain: Record; types: Record; primaryType: string; message: Record; }): Promise<`0x${string}`>; readContract?(args: unknown): Promise; signTransaction?(args: unknown): Promise<`0x${string}`>; getTransactionCount?(args: { address: `0x${string}`; }): Promise; estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint; }>; } /** Async, opaque x402 payer. Returning null means that network is unsupported. */ export interface EvmPaymentSignerProvider { getSigner(context: { network: X402PaymentNetwork; publicClient: PaymentPublicClient; }): Promise; } export type PaymentPayerSource = "payment_signer" | "allowance_path" | "credentials" | "default_allowance"; /** Safe, key-free provenance for the payer selected by paid fetch. */ export interface PaymentPayerProvenance { readonly source: PaymentPayerSource; readonly rail: "x402" | "mpp" | "lightning"; readonly payers: readonly { readonly address: string; readonly network?: X402PaymentNetwork; }[]; } export type ConfiguredPaidFetch = FetchFn & { readonly payer: PaymentPayerProvenance; readonly pay?: PayExecutor; /** Refreshes mutable balance state without re-resolving the selected payer. */ refreshBalances(): Promise; }; export type LazyPaidFetch = FetchFn & { /** Initializes the selected source if needed and returns public payer provenance only. */ getPayer(): Promise; /** Execute the receipt-bearing arbitrary-URL buyer flow. */ pay: PayExecutor; }; export interface PaidFetchOptions { /** Explicit local allowance file. When set, no other allowance is consulted. */ allowancePath?: string; /** Auth provider whose optional allowance capability may also fund payments. */ credentials?: Pick; /** Explicit opaque x402 signer. Mutually exclusive with allowancePath. */ paymentSigner?: EvmPaymentSignerProvider; /** * The run402 API origin this fetch is wired to (defaults to * `getApiBase()`). Used ONLY to recognize a same-origin gateway response * carrying one of its own terminal, never-settled refusal codes (live-proof * defect B — see {@link isTerminalRoomInviteRefusal}) — never to route or * validate requests. A response from any other origin is unaffected. */ apiBase?: string; /** Build the buyer for this rail regardless of the persisted one (the Lightning buyer's x402 fallback). */ railOverride?: "x402"; } /** @internal Test seam; not re-exported from `@run402/sdk/node`. */ export declare function _setPaidStackLoadersForTest(loaders?: { x402?: () => Promise; mpp?: () => Promise; }): void; interface TrackedPaidFetchOptions { store?: PaymentAttemptStore; createAttemptId?: () => string; now?: () => string; fetch?: FetchFn; classifyPaymentResponse?: (response: Response) => Promise<"completed" | "failed" | "already_settled" | "intent_pending" | "ambiguous">; } /** @internal Exported only for deterministic source-level tests; not re-exported by the package. */ export declare function checkBalanceAcrossProviders(clients: readonly RpcClient[], tokenAddress: string, walletAddress: string, network: string, options?: BalanceRetryOptions): Promise; /** @internal Exported only for deterministic source-level tests; not re-exported by the package. */ export declare function filterAffordableRequirements(requirements: PaymentRequirementLike[], balances: BalanceStates, /** * Payer address per network. Surfaced in the insufficient-funds error so the * `fund_wallet` next_action names WHERE to send money — "fund the wallet" is * not executable without an address. Optional: omitting it only omits the * `payers` detail. */ payers?: Readonly>): PaymentRequirementLike[]; export declare function setupPaidFetch(options?: PaidFetchOptions): Promise; declare function createLazyPaidFetchFrom(setup: () => Promise): FetchFn; /** * Returns a fetch that lazily initializes the x402 wrapper on first call. * Failed initialization is not cached; concurrent first calls share one * attempt, and a later request can recover after transient RPC/setup failure. */ export declare function createLazyPaidFetch(options?: PaidFetchOptions): LazyPaidFetch; /** @internal Source-level unit-test seam; not re-exported by the package. */ export declare const __paidFetchInternals: { createLazyPaidFetchFrom: typeof createLazyPaidFetchFrom; }; interface X402BuyerFetchOptions extends TrackedPaidFetchOptions { supportedNetworks: readonly string[]; payerAddresses?: readonly string[]; offerReceipt?: X402OfferReceiptRuntime; verifyAtSeconds?: () => number; } interface X402OfferReceiptRuntime { extractOffersFromPaymentRequired: (required: unknown) => unknown[]; decodeSignedOffers: (offers: unknown[]) => unknown[]; findAcceptsObjectFromSignedOffer: (offer: unknown, accepts: unknown[]) => unknown | undefined; isEIP712SignedOffer: (offer: unknown) => boolean; isEIP712SignedReceipt: (receipt: unknown) => boolean; verifyOfferSignatureEIP712: (offer: unknown) => Promise<{ signer: `0x${string}`; payload: Record; }>; verifyReceiptSignatureEIP712: (receipt: unknown) => Promise<{ signer: `0x${string}`; payload: Record; }>; extractReceiptFromResponse: (response: Response) => unknown | undefined; } /** * Receipt-bearing buyer orchestration over an already-configured x402 client. * Signed proofs live only in this SDK instance's memory. An ambiguous retry of * the identical request re-presents that proof; it never mints a replacement. */ export declare function createX402BuyerFetch(client: X402BuyerClient, options: X402BuyerFetchOptions): PayExecutor; export declare function paymentNetworkUnsupportedError(challengeNetworkValues: string[], walletNetworkValues: string[], extra?: Record): PaymentBuyerError; /** * Request-scoped payment tracker around `@x402/fetch`. * * The wrapped package may call its base fetch twice: first without payment to * obtain the 402 challenge, then with a signed payment authorization. The * AsyncLocalStorage context lets the base-fetch boundary update the correct * durable attempt even when multiple paid requests run concurrently. * * Exported from this module for deterministic boundary tests, but intentionally * not re-exported from the package entry point. */ export declare function createTrackedX402Fetch(wrapFetchWithPayment: (fetch: FetchFn, client: unknown) => FetchFn, client: unknown, opts?: TrackedPaidFetchOptions): FetchFn; export {}; //# sourceMappingURL=paid-fetch.d.ts.map