@bosonprotocol/x402-server 0.2.0 → 0.3.0-alpha-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/onchain/web3lib-read-stub.ts","../../src/config.ts","../../src/onchain/core-sdk-read.ts","../../src/server.ts","../../src/internal/x-payment-response.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Minimal throwing `Web3LibAdapter` for the server's read-only\n// `CoreSDK` instance. The funds-subgraph and accounts-subgraph helpers\n// (`getFunds`, `getSellersByAddress`, `getBuyers`) never touch the\n// adapter at runtime, but `new CoreSDK({...})` requires one in its\n// constructor. Each method throws so any future leak into a non-read\n// path is loud rather than silent.\n\nimport type { Web3LibAdapter } from \"@bosonprotocol/common\";\n\nconst TAG = \"x402-server:read\";\n\nfunction unreachable(method: string): Error {\n return new Error(\n `${TAG}: stub Web3LibAdapter.${method}() should never be called from the read-only ` +\n `CoreSDK instance. If you see this, a non-subgraph code path leaked through.`,\n );\n}\n\nexport function createReadOnlyWeb3LibStub(): Web3LibAdapter {\n return {\n uuid: `${TAG}:stub`,\n getSignerAddress: () => Promise.reject(unreachable(\"getSignerAddress\")),\n isSignerContract: () => Promise.reject(unreachable(\"isSignerContract\")),\n getChainId: () => Promise.reject(unreachable(\"getChainId\")),\n getBalance: () => Promise.reject(unreachable(\"getBalance\")),\n estimateGas: () => Promise.reject(unreachable(\"estimateGas\")),\n sendTransaction: () => Promise.reject(unreachable(\"sendTransaction\")),\n call: () => Promise.reject(unreachable(\"call\")),\n send: () => Promise.reject(unreachable(\"send\")),\n getTransactionReceipt: () => Promise.reject(unreachable(\"getTransactionReceipt\")),\n getCurrentTimeMs: () => Promise.reject(unreachable(\"getCurrentTimeMs\")),\n };\n}\n","// X402bServerConfig — the per-server context passed to\n// `createX402bServer`. The config holds everything that doesn't vary\n// per request: the network + escrow address, the seller's signer, the\n// facilitator URL (for both the future HTTP client and the public\n// advertisement embedded in `nextActions[].endpoints.facilitator`),\n// and the channel registry consumed by `deriveNextActions`.\n//\n// Per-offer values (price, asset, fulfillment, etc.) come in through\n// the per-request `buildPaymentRequirements` call instead — see\n// `./challenge/build-requirements.ts`.\n\nimport { channelRegistryZodSchema, type ChannelRegistry } from \"@bosonprotocol/x402-actions\";\nimport {\n addressSchema,\n evmNetworkSchema,\n hexSchema,\n type Address,\n type EvmNetwork,\n} from \"@bosonprotocol/x402-core/schemes/escrow\";\nimport type { Hex } from \"viem\";\nimport { z } from \"zod\";\n\nimport type { CoreSdkReadAdapter } from \"./onchain/core-sdk-read.js\";\nimport type { ExchangeReader } from \"./onchain/verify-exchange.js\";\n\n/**\n * Minimal signing surface needed by `signFullOffer`. Structurally\n * compatible with viem's `Account` (in particular `LocalAccount` from\n * `privateKeyToAccount`), but kept narrow so consumers can plug in\n * HSM- / KMS- / ERC-1271-backed signers without depending on viem's\n * internal account types.\n */\nexport interface SellerSigner {\n /** Address that the EIP-712 signature must recover to (`creator` in `BosonOfferRef`). */\n readonly address: Address;\n /** EIP-712 typed-data signer. Accepts the same shape viem's `signTypedData` does. */\n signTypedData: (params: {\n domain: Record<string, unknown>;\n types: Record<string, readonly { name: string; type: string }[]>;\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n}\n\n/**\n * Per-server configuration. Validated by `x402bServerConfigSchema` at\n * `createX402bServer` time so bad config fails fast at boot rather than\n * later inside a 402 response.\n */\nexport interface X402bServerConfig {\n /** CAIP-2 EVM network the server advertises (e.g. `eip155:8453`). */\n network: EvmNetwork;\n /** EVM chain id matching `network` — passed straight to the EIP-712 builder's salt. */\n chainId: number;\n /** Address of the Boson Diamond — the EIP-712 `verifyingContract` and the wire-level `escrowAddress`. */\n escrow: Address;\n /** Seller signer (signs the FullOffer EIP-712 typed-data). */\n signer: SellerSigner;\n /** Facilitator service the server forwards meta-tx envelopes to. The URL is also advertised in `nextActions[].endpoints.facilitator`. */\n facilitator: { url: string };\n /** Per-seller channel + endpoint registry consumed by `deriveNextActions`. */\n channelRegistry: ChannelRegistry;\n /**\n * Reader the convenience handlers use to verify the post-settle /\n * post-perform-action exchange state. Required at runtime when any\n * write handler is invoked; the `signOffer` / `buildPaymentRequirements`\n * read-only paths don't touch it. See `./onchain/verify-exchange.ts`\n * for the interface.\n */\n exchangeReader?: ExchangeReader;\n /**\n * URL of the Boson Protocol subgraph for this network. Used by the\n * read-only `available-funds` handler and the address→entityId\n * resolver shared with `withdraw-funds`. Optional at config time\n * (legacy commit/redeem handlers don't need it); required at runtime\n * by `handlers.withdrawFunds` / `handlers.getAvailableFunds`.\n */\n subgraphUrl?: string;\n /**\n * Pre-built read-only core-sdk client. If omitted, the server\n * constructs one internally from `subgraphUrl` + `escrow` + `chainId`\n * with a throwing `Web3LibAdapter` stub. Provide your own for tests\n * or when you want to share a single core-sdk instance with the\n * rest of your service.\n */\n coreSdkRead?: CoreSdkReadAdapter;\n /**\n * Server-side store of the fulfillment option ids advertised for\n * each Flow A exchange (keyed by `exchangeId`). Populated from the\n * original `PaymentRequirements` after commit verification and read\n * at redeem time so the buyer's redeem-time fulfillment choice\n * cannot switch to a channel the offer never advertised.\n *\n * Optional in the config: when omitted, `createX402bServer` wires up\n * an in-memory `Map`. Hosts running multiple instances should plug\n * in their own cross-process `Map`-shaped backing store.\n */\n exchangeFulfillmentOptionStore?: Map<string, readonly string[]>;\n /**\n * Pending fulfillment updates that reached REDEEMED on-chain but\n * failed the server-side `channel.onCommit(...)` upsert. The commit\n * handler records Flow B updates here before attempting the channel\n * write; the redeem handler does the same for Flow A. Both delete the\n * record on success and leave it behind with the error message on\n * failure so the host can replay/reconcile out of band.\n */\n fulfillmentRecoveryStore?: Map<string, FulfillmentRecoveryEntry>;\n /**\n * Fulfillment channels the server accepts at redeem time when the\n * client re-submits delivery data. Structurally a subset of\n * `@bosonprotocol/x402-fulfillment`'s `FulfillmentChannel` — only\n * `id`, `validate`, and `onCommit` are read here, so existing\n * channel instances pass through directly. Required iff a host\n * wants to accept redeem-time fulfillment updates; absent means\n * redeem requests carrying `fulfillment` are rejected with\n * `FULFILLMENT_CHANNELS_NOT_CONFIGURED`.\n */\n fulfillmentChannels?: readonly RedeemFulfillmentChannel[];\n}\n\n/**\n * Minimal structural slice of `FulfillmentChannel` the redeem\n * handler needs. Kept inline so `@bosonprotocol/x402-server` does\n * not depend on `@bosonprotocol/x402-fulfillment` (avoids a hard\n * coupling between the resource-server SDK and a specific channel\n * package); any real channel implementation is type-compatible.\n */\nexport interface RedeemFulfillmentChannel {\n readonly id: string;\n validate(data: Record<string, unknown> | null): { ok: true } | { ok: false; reason: string };\n onCommit(exchangeId: string, data: Record<string, unknown> | null): Promise<void>;\n}\n\nexport interface FulfillmentRecoveryEntry {\n exchangeId: string;\n option: string;\n data: Record<string, unknown> | null;\n redeemer: Address;\n recordedAt: number;\n error?: string;\n}\n\nconst httpUrlSchema = z\n .string()\n .url()\n .refine((url) => url.startsWith(\"http://\") || url.startsWith(\"https://\"), {\n message: \"must be an http(s) URL\",\n });\n\nconst sellerSignerSchema = z\n .object({\n address: addressSchema,\n // `SellerSigner.signTypedData` is typed `Promise<Hex>` in the TS\n // interface — tighten the zod return wrapper to match so a signer\n // that resolves to a non-hex string fails loudly at call time\n // rather than silently producing a bad `BosonOfferRef.sellerSig`.\n signTypedData: z.function().args(z.unknown()).returns(z.promise(hexSchema)),\n })\n .passthrough();\n\nconst exchangeReaderShallowSchema = z\n .object({\n read: z.function().args(z.string()).returns(z.unknown()),\n })\n .passthrough();\n\nconst coreSdkReadShallowSchema = z\n .object({\n getFunds: z.function().args(z.unknown()).returns(z.unknown()),\n getSellersByAddress: z.function().args(z.unknown()).returns(z.unknown()),\n getBuyers: z.function().args(z.unknown()).returns(z.unknown()),\n })\n .passthrough();\n\nconst fulfillmentChannelShallowSchema = z\n .object({\n id: z.string().min(1),\n validate: z.function(),\n onCommit: z.function(),\n })\n .passthrough();\n\n/**\n * zod validator for `X402bServerConfig`. Shallow on the signer +\n * exchange reader (viem account types bring their own structural\n * validators; the user-supplied reader impl is structurally typed);\n * strict on the scalar fields we own here, and on the channel\n * registry via `@bosonprotocol/x402-actions`.\n */\nexport const x402bServerConfigSchema = z\n .object({\n network: evmNetworkSchema,\n chainId: z.number().int().positive(),\n escrow: addressSchema,\n signer: sellerSignerSchema,\n facilitator: z\n .object({\n url: httpUrlSchema,\n })\n .strict(),\n channelRegistry: channelRegistryZodSchema,\n exchangeReader: exchangeReaderShallowSchema.optional(),\n subgraphUrl: httpUrlSchema.optional(),\n coreSdkRead: coreSdkReadShallowSchema.optional(),\n exchangeFulfillmentOptionStore: z.instanceof(Map).optional(),\n fulfillmentRecoveryStore: z.instanceof(Map).optional(),\n fulfillmentChannels: z\n .array(fulfillmentChannelShallowSchema)\n .superRefine((channels, ctx) => {\n // Duplicate ids would let one channel silently shadow another\n // (the redeem handler picks via `find(c => c.id === option)`).\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n for (const c of channels) {\n if (seen.has(c.id)) duplicates.add(c.id);\n seen.add(c.id);\n }\n if (duplicates.size > 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `fulfillmentChannels has duplicate id(s): ${[...duplicates].join(\", \")}`,\n });\n }\n })\n .optional(),\n })\n .strict()\n .superRefine((cfg, ctx) => {\n // CAIP-2 `eip155:<chainId>` carries the chainId; assert it matches\n // the explicit `chainId` field so the EIP-712 salt and the\n // wire-level network advertisement agree. Catches the easy\n // copy-paste mistake of pairing `eip155:8453` with `chainId: 1`.\n const networkChainId = Number(cfg.network.split(\":\")[1]);\n if (networkChainId !== cfg.chainId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"chainId\"],\n message: `chainId (${cfg.chainId}) must match network (${cfg.network})`,\n });\n }\n });\n\n/**\n * Cross-field invariant: `config.escrow` and\n * `config.channelRegistry.escrow` must agree — the Diamond address is\n * the same on both sides. Run this after `x402bServerConfigSchema.parse`.\n */\nexport function assertChannelRegistryEscrowMatch(config: X402bServerConfig): void {\n if (config.escrow.toLowerCase() !== config.channelRegistry.escrow.toLowerCase()) {\n throw new Error(\n `x402-server config: escrow (${config.escrow}) does not match channelRegistry.escrow (${config.channelRegistry.escrow})`,\n );\n }\n}\n","// Minimal read-only adapter over `@bosonprotocol/core-sdk` used by the\n// `withdraw-funds` and `available-funds` handlers.\n//\n// The full `CoreSDK` type pulls in a lot of surface area (every facet,\n// every signing helper) — none of which the read paths need. Narrowing\n// it to a structural interface keeps the server's dependency\n// footprint small for consumers that just want to expose the read\n// endpoints (and lets tests pass a hand-rolled stub without\n// constructing a real CoreSDK).\n\nimport type { CoreSDK } from \"@bosonprotocol/core-sdk\";\n\n/** Funds entity returned by `coreSdk.getFunds` — narrowed to the fields the handler reshapes. */\nexport interface CoreSdkFundsEntity {\n id?: string;\n accountId: string;\n availableAmount: string;\n token: {\n address: string;\n decimals: string;\n symbol: string;\n name: string;\n };\n}\n\n/** Seller entity returned by `coreSdk.getSellersByAddress` — only the id is consumed. */\nexport interface CoreSdkSellerEntity {\n id: string;\n}\n\n/** Buyer entity returned by `coreSdk.getBuyers` — only the id is consumed. */\nexport interface CoreSdkBuyerEntity {\n id: string;\n}\n\n/**\n * The subset of `CoreSDK` the read-only handlers actually use. Both the\n * real `CoreSDK` and a hand-rolled stub for tests satisfy this shape.\n */\nexport interface CoreSdkReadAdapter {\n getFunds(queryVars: { fundsFilter: { accountId: string } }): Promise<CoreSdkFundsEntity[]>;\n getSellersByAddress(address: string): Promise<CoreSdkSellerEntity[]>;\n getBuyers(queryVars: { buyersFilter: { wallet: string } }): Promise<CoreSdkBuyerEntity[]>;\n}\n\n/**\n * Cast a full `CoreSDK` to the narrowed adapter shape. Structural-only;\n * does not capture or wrap anything.\n */\nexport function asCoreSdkReadAdapter(coreSdk: CoreSDK): CoreSdkReadAdapter {\n return coreSdk as unknown as CoreSdkReadAdapter;\n}\n","// `createX402bServer` — the per-server factory. Wires the 402\n// challenge builder + FullOffer signer (PR 1), and the convenience\n// handlers (commit, commit-and-redeem, redeem, complete, dispute/*,\n// withdraw-funds, available-funds) over the facilitator HTTP client +\n// configured `ExchangeReader` and read-only core-sdk client.\n\nimport { CoreSDK } from \"@bosonprotocol/core-sdk\";\nimport type { UnsignedFullOffer } from \"@bosonprotocol/x402-core/eip712\";\nimport type {\n BosonOfferRef,\n EscrowPaymentRequirements,\n} from \"@bosonprotocol/x402-core/schemes/escrow\";\n\nimport { createReadOnlyWeb3LibStub } from \"./onchain/web3lib-read-stub.js\";\n\nimport { buildPaymentRequirements } from \"./challenge/build-requirements.js\";\nimport { signFullOffer } from \"./challenge/sign-full-offer.js\";\nimport {\n assertChannelRegistryEscrowMatch,\n x402bServerConfigSchema,\n type FulfillmentRecoveryEntry,\n type X402bServerConfig,\n} from \"./config.js\";\nimport { createFacilitatorClient, type FacilitatorClient } from \"./facilitator/client.js\";\nimport {\n handleCommit,\n handleCommitAndRedeem,\n handleComplete,\n handleDisputeEscalate,\n handleDisputeRaise,\n handleDisputeResolve,\n handleDisputeRetract,\n handleGetAvailableFunds,\n handleRedeem,\n handleWithdrawFunds,\n type AvailableFundsBody,\n type AvailableFundsQuery,\n type CommitHandlerInput,\n type CommitOk,\n type HandlerResult,\n type PerformActionInput,\n type PerformActionOk,\n type PlainHandlerResult,\n type RedeemHandlerInput,\n type WithdrawFundsInput,\n type WithdrawFundsOk,\n} from \"./handlers/index.js\";\nimport { stampFacilitatorEndpoints } from \"./internal/facilitator-endpoints.js\";\nimport { asCoreSdkReadAdapter, type CoreSdkReadAdapter } from \"./onchain/core-sdk-read.js\";\nimport type { ExchangeReader } from \"./onchain/verify-exchange.js\";\n\n/** Per-offer inputs for `server.buildPaymentRequirements` — everything the offer-level args carry, minus the per-server context the factory already holds. */\nexport interface BuildRequirementsInput {\n /** Already-signed offer reference, or `{ unsigned }` to have the server sign it. */\n offer: BosonOfferRef | { unsigned: UnsignedFullOffer };\n asset: string;\n amount: string;\n tokenAuthStrategies: readonly (\"none\" | \"erc3009\" | \"permit\" | \"permit2\")[];\n recipientId: string;\n maxTimeoutSeconds: number;\n fulfillment?: import(\"@bosonprotocol/x402-core/schemes/escrow\").FulfillmentRequirements;\n}\n\nexport interface X402bServer {\n readonly config: X402bServerConfig;\n readonly facilitator: FacilitatorClient;\n\n /** Sign an unsigned FullOffer with the configured seller signer. */\n signOffer(unsigned: UnsignedFullOffer): Promise<BosonOfferRef>;\n /** Build a 402 `EscrowPaymentRequirements`. */\n buildPaymentRequirements(input: BuildRequirementsInput): Promise<EscrowPaymentRequirements>;\n\n /** Convenience handlers — pure, framework-agnostic. The express adapter (PR 5) maps them to routes. */\n readonly handlers: {\n commit(input: CommitHandlerInput): Promise<HandlerResult<CommitOk>>;\n commitAndRedeem(input: CommitHandlerInput): Promise<HandlerResult<CommitOk>>;\n redeem(input: RedeemHandlerInput): Promise<HandlerResult<PerformActionOk>>;\n complete(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeRaise(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeResolve(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeRetract(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeEscalate(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n withdrawFunds(input: WithdrawFundsInput): Promise<PlainHandlerResult<WithdrawFundsOk>>;\n getAvailableFunds(query: AvailableFundsQuery): Promise<PlainHandlerResult<AvailableFundsBody>>;\n };\n}\n\nfunction withFacilitatorEndpoints(\n requirements: EscrowPaymentRequirements,\n facilitatorUrl: string,\n): EscrowPaymentRequirements {\n return {\n ...requirements,\n actions: {\n ...requirements.actions,\n next: stampFacilitatorEndpoints(requirements.actions.next, facilitatorUrl),\n },\n };\n}\n\n/**\n * Validate a config and return a `X402bServer` whose methods are\n * bound to the validated context. Throws synchronously (`ZodError`)\n * on bad config or (`Error`) on the escrow / channel-registry escrow\n * mismatch.\n */\nexport function createX402bServer(config: X402bServerConfig): X402bServer {\n const validated = x402bServerConfigSchema.parse(config) as X402bServerConfig;\n assertChannelRegistryEscrowMatch(validated);\n\n const facilitator = createFacilitatorClient({ url: validated.facilitator.url });\n // Default to a fresh in-memory store when the host doesn't supply\n // one. Single shared reference for the lifetime of this server — so\n // commit-time writes and redeem-time reads observe the same Map.\n const exchangeFulfillmentOptionStore: Map<string, readonly string[]> =\n validated.exchangeFulfillmentOptionStore ?? new Map();\n const fulfillmentRecoveryStore: Map<string, FulfillmentRecoveryEntry> =\n validated.fulfillmentRecoveryStore ?? new Map();\n validated.exchangeFulfillmentOptionStore = exchangeFulfillmentOptionStore;\n validated.fulfillmentRecoveryStore = fulfillmentRecoveryStore;\n\n const signOffer = (unsigned: UnsignedFullOffer): Promise<BosonOfferRef> =>\n signFullOffer({\n fullOffer: unsigned,\n signer: validated.signer,\n escrow: validated.escrow,\n chainId: validated.chainId,\n });\n\n const requireReader = async (action: string): Promise<ExchangeReader> => {\n if (validated.exchangeReader === undefined) {\n throw new Error(\n `x402-server: handlers.${action}() requires \\`exchangeReader\\` in config (post-settle state verification step).`,\n );\n }\n return validated.exchangeReader;\n };\n\n // Lazy-memoised read-only core-sdk. The construction itself is cheap\n // but happens on every `handlers.withdrawFunds()` /\n // `handlers.getAvailableFunds()` call — caching the adapter keeps the\n // hot path allocation-free and shares one subgraph client across\n // requests. `validated.coreSdkRead`, when supplied by the host, is\n // already shared.\n let cachedCoreSdkRead: CoreSdkReadAdapter | undefined;\n const requireCoreSdkRead = (action: string): CoreSdkReadAdapter => {\n if (validated.coreSdkRead !== undefined) return validated.coreSdkRead;\n if (cachedCoreSdkRead !== undefined) return cachedCoreSdkRead;\n if (validated.subgraphUrl === undefined) {\n throw new Error(\n `x402-server: handlers.${action}() requires either \\`coreSdkRead\\` or \\`subgraphUrl\\` in config (subgraph read step).`,\n );\n }\n cachedCoreSdkRead = asCoreSdkReadAdapter(\n new CoreSDK({\n web3Lib: createReadOnlyWeb3LibStub(),\n subgraphUrl: validated.subgraphUrl,\n protocolDiamond: validated.escrow,\n chainId: validated.chainId,\n }),\n );\n return cachedCoreSdkRead;\n };\n\n return {\n config: validated,\n facilitator,\n signOffer,\n async buildPaymentRequirements(input) {\n const offer = \"unsigned\" in input.offer ? await signOffer(input.offer.unsigned) : input.offer;\n const requirements = buildPaymentRequirements({\n offer,\n asset: input.offer && \"unsigned\" in input.offer ? input.asset : input.asset,\n amount: input.amount,\n tokenAuthStrategies: input.tokenAuthStrategies,\n recipientId: input.recipientId,\n maxTimeoutSeconds: input.maxTimeoutSeconds,\n ...(input.fulfillment !== undefined ? { fulfillment: input.fulfillment } : {}),\n network: validated.network,\n escrow: validated.escrow,\n channelRegistry: validated.channelRegistry,\n });\n return withFacilitatorEndpoints(requirements, validated.facilitator.url);\n },\n handlers: {\n commit: async (input) =>\n handleCommit(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"commit\"),\n fulfillmentRecoveryStore,\n exchangeFulfillmentOptionStore,\n }),\n commitAndRedeem: async (input) =>\n handleCommitAndRedeem(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"commitAndRedeem\"),\n fulfillmentRecoveryStore,\n exchangeFulfillmentOptionStore,\n }),\n redeem: async (input) =>\n handleRedeem(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"redeem\"),\n exchangeFulfillmentOptionStore,\n fulfillmentRecoveryStore,\n }),\n complete: async (input) =>\n handleComplete(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"complete\"),\n }),\n disputeRaise: async (input) =>\n handleDisputeRaise(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeRaise\"),\n }),\n disputeResolve: async (input) =>\n handleDisputeResolve(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeResolve\"),\n }),\n disputeRetract: async (input) =>\n handleDisputeRetract(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeRetract\"),\n }),\n disputeEscalate: async (input) =>\n handleDisputeEscalate(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeEscalate\"),\n }),\n withdrawFunds: async (input) =>\n handleWithdrawFunds(input, {\n config: validated,\n facilitator,\n coreSdkRead: requireCoreSdkRead(\"withdrawFunds\"),\n }),\n getAvailableFunds: async (query) =>\n handleGetAvailableFunds(query, {\n coreSdkRead: requireCoreSdkRead(\"getAvailableFunds\"),\n }),\n },\n };\n}\n","// Encoder for the `X-PAYMENT-RESPONSE` header. The base x402 spec uses\n// base64-of-JSON for `X-PAYMENT-RESPONSE`, and the buyer SDK's\n// `parsePaymentResponse` ([client/src/response.ts]) decodes it the\n// same way. This helper is the inverse — give it the success body and\n// it produces the header value.\n//\n// The header is best-effort metadata that lets the client read\n// `exchangeId` (and any future scheme-specific fields) without parsing\n// the full JSON body. We pass the body through verbatim so the wire\n// shape is identical to the response body; consumers stay free to\n// branch on either.\n\n/**\n * Base64-encode the success-response body for the `X-PAYMENT-RESPONSE`\n * header. The companion decoder lives in\n * `@bosonprotocol/x402-client`'s `parsePaymentResponse`.\n */\nexport function encodeXPaymentResponse(body: unknown): string {\n const json = JSON.stringify(body);\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(json, \"utf8\").toString(\"base64\");\n }\n // Node ships `Buffer`; the browser fallback exists for completeness so\n // a non-Node integrator (Workers, Deno) can reuse this helper.\n const bytes = new TextEncoder().encode(json);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/** Canonical header name — exported so adapters share one spelling. */\nexport const X_PAYMENT_RESPONSE_HEADER = \"X-PAYMENT-RESPONSE\" as const;\n"]}
1
+ {"version":3,"sources":["../../src/onchain/web3lib-read-stub.ts","../../src/store.ts","../../src/config.ts","../../src/onchain/core-sdk-read.ts","../../src/concurrency.ts","../../src/health.ts","../../src/server.ts","../../src/internal/x-payment-response.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Minimal throwing `Web3LibAdapter` for the server's read-only\n// `CoreSDK` instance. The funds-subgraph and accounts-subgraph helpers\n// (`getFunds`, `getSellersByAddress`, `getBuyers`) never touch the\n// adapter at runtime, but `new CoreSDK({...})` requires one in its\n// constructor. Each method throws so any future leak into a non-read\n// path is loud rather than silent.\n\nimport type { Web3LibAdapter } from \"@bosonprotocol/common\";\n\nconst TAG = \"x402-server:read\";\n\nfunction unreachable(method: string): Error {\n return new Error(\n `${TAG}: stub Web3LibAdapter.${method}() should never be called from the read-only ` +\n `CoreSDK instance. If you see this, a non-subgraph code path leaked through.`,\n );\n}\n\nexport function createReadOnlyWeb3LibStub(): Web3LibAdapter {\n return {\n uuid: `${TAG}:stub`,\n getSignerAddress: () => Promise.reject(unreachable(\"getSignerAddress\")),\n isSignerContract: () => Promise.reject(unreachable(\"isSignerContract\")),\n getChainId: () => Promise.reject(unreachable(\"getChainId\")),\n getBalance: () => Promise.reject(unreachable(\"getBalance\")),\n estimateGas: () => Promise.reject(unreachable(\"estimateGas\")),\n sendTransaction: () => Promise.reject(unreachable(\"sendTransaction\")),\n call: () => Promise.reject(unreachable(\"call\")),\n send: () => Promise.reject(unreachable(\"send\")),\n getTransactionReceipt: () => Promise.reject(unreachable(\"getTransactionReceipt\")),\n getCurrentTimeMs: () => Promise.reject(unreachable(\"getCurrentTimeMs\")),\n };\n}\n","// Async key/value store contract for server-side per-exchange state\n// (fulfillment option policy + recovery queue). Map-shaped on purpose\n// so an in-memory `Map` wraps via `mapAsStore` and Redis/Postgres\n// back-ends implement four methods.\n//\n// The defaults wired up by `createX402bServer` use `mapAsStore(new Map())`\n// so dev / single-process deployments need no extra plumbing; hosts\n// running multiple instances or who need to survive a restart plug in\n// their own implementation.\n\n/**\n * Minimal async key/value store. `get` / `set` / `delete` are the\n * hot-path handler operations; `entries` is consumed by the\n * recovery-inspection surface (`recovery.list`) and stays optional in\n * spirit by being a method on the same interface — wrapping a `Map`\n * via `mapAsStore` makes all four trivial.\n */\nexport interface Store<V> {\n get(key: string): Promise<V | undefined>;\n set(key: string, value: V): Promise<void>;\n delete(key: string): Promise<void>;\n entries(): AsyncIterable<readonly [string, V]>;\n}\n\n/**\n * Wrap an in-memory `Map` as a `Store<V>`. The adapter is intentionally\n * cheap — no copies, no locking — so single-process tests and dev\n * deployments pay zero overhead versus the previous direct-`Map`\n * shape.\n */\nexport function mapAsStore<V>(m: Map<string, V>): Store<V> {\n return {\n async get(key) {\n return m.get(key);\n },\n async set(key, value) {\n m.set(key, value);\n },\n async delete(key) {\n m.delete(key);\n },\n async *entries() {\n for (const e of m.entries()) yield e;\n },\n };\n}\n\n/**\n * Structural type-guard for the `Store<V>` shape. Used by\n * `x402bServerConfigSchema` to validate host-supplied stores without\n * locking the contract to `Map` (the previous `z.instanceof(Map)`\n * accepted only the concrete `Map` class).\n */\nexport function isStore(value: unknown): value is Store<unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.get === \"function\" &&\n typeof v.set === \"function\" &&\n typeof v.delete === \"function\" &&\n typeof v.entries === \"function\"\n );\n}\n","// X402bServerConfig — the per-server context passed to\n// `createX402bServer`. The config holds everything that doesn't vary\n// per request: the network + escrow address, the seller's signer, the\n// facilitator URL (for both the future HTTP client and the public\n// advertisement embedded in `nextActions[].endpoints.facilitator`),\n// and the channel registry consumed by `deriveNextActions`.\n//\n// Per-offer values (price, asset, fulfillment, etc.) come in through\n// the per-request `buildPaymentRequirements` call instead — see\n// `./challenge/build-requirements.ts`.\n\nimport { channelRegistryZodSchema, type ChannelRegistry } from \"@bosonprotocol/x402-actions\";\nimport {\n addressSchema,\n evmNetworkSchema,\n hexSchema,\n type Address,\n type EvmNetwork,\n} from \"@bosonprotocol/x402-core/schemes/escrow\";\nimport type { Hex } from \"viem\";\nimport { z } from \"zod\";\n\nimport type { CoreSdkReadAdapter } from \"./onchain/core-sdk-read.js\";\nimport type { ExchangeReader } from \"./onchain/verify-exchange.js\";\nimport { isStore, type Store } from \"./store.js\";\nimport type { FacilitatorRetryOptions } from \"./facilitator/client.js\";\nimport type { Logger } from \"./logger.js\";\n\n/**\n * Minimal signing surface needed by `signFullOffer`. Structurally\n * compatible with viem's `Account` (in particular `LocalAccount` from\n * `privateKeyToAccount`), but kept narrow so consumers can plug in\n * HSM- / KMS- / ERC-1271-backed signers without depending on viem's\n * internal account types.\n */\nexport interface SellerSigner {\n /** Address that the EIP-712 signature must recover to (`creator` in `BosonOfferRef`). */\n readonly address: Address;\n /** EIP-712 typed-data signer. Accepts the same shape viem's `signTypedData` does. */\n signTypedData: (params: {\n domain: Record<string, unknown>;\n types: Record<string, readonly { name: string; type: string }[]>;\n primaryType: string;\n message: Record<string, unknown>;\n }) => Promise<Hex>;\n}\n\n/**\n * Per-server configuration. Validated by `x402bServerConfigSchema` at\n * `createX402bServer` time so bad config fails fast at boot rather than\n * later inside a 402 response.\n */\nexport interface X402bServerConfig {\n /** CAIP-2 EVM network the server advertises (e.g. `eip155:8453`). */\n network: EvmNetwork;\n /** EVM chain id matching `network` — passed straight to the EIP-712 builder's salt. */\n chainId: number;\n /** Address of the Boson Diamond — the EIP-712 `verifyingContract` and the wire-level `escrowAddress`. */\n escrow: Address;\n /** Seller signer (signs the FullOffer EIP-712 typed-data). */\n signer: SellerSigner;\n /**\n * Facilitator service the server forwards meta-tx envelopes to. The\n * URL is also advertised in `nextActions[].endpoints.facilitator`.\n *\n * `timeoutMs`, `retry`, and `idempotencyKey` tune the HTTP client at\n * `./facilitator/client.ts`. Defaults: 30 s timeout; 3 attempts at\n * 0 / 200 / 400 ms; idempotency key sourced from `crypto.randomUUID()`\n * on every `/settle` call.\n */\n facilitator: {\n url: string;\n timeoutMs?: number;\n retry?: FacilitatorRetryOptions;\n idempotencyKey?: () => string;\n };\n /** Per-seller channel + endpoint registry consumed by `deriveNextActions`. */\n channelRegistry: ChannelRegistry;\n /**\n * Reader the convenience handlers use to verify the post-settle /\n * post-perform-action exchange state. Required at runtime when any\n * write handler is invoked; the `signOffer` / `buildPaymentRequirements`\n * read-only paths don't touch it. See `./onchain/verify-exchange.ts`\n * for the interface.\n */\n exchangeReader?: ExchangeReader;\n /**\n * URL of the Boson Protocol subgraph for this network. Used by the\n * read-only `available-funds` handler and the address→entityId\n * resolver shared with `withdraw-funds`. Optional at config time\n * (legacy commit/redeem handlers don't need it); required at runtime\n * by `handlers.withdrawFunds` / `handlers.getAvailableFunds`.\n */\n subgraphUrl?: string;\n /**\n * Pre-built read-only core-sdk client. If omitted, the server\n * constructs one internally from `subgraphUrl` + `escrow` + `chainId`\n * with a throwing `Web3LibAdapter` stub. Provide your own for tests\n * or when you want to share a single core-sdk instance with the\n * rest of your service.\n */\n coreSdkRead?: CoreSdkReadAdapter;\n /**\n * Server-side store of the fulfillment option ids advertised for\n * each Flow A exchange (keyed by `exchangeId`). Populated from the\n * original `PaymentRequirements` after commit verification and read\n * at redeem time so the buyer's redeem-time fulfillment choice\n * cannot switch to a channel the offer never advertised.\n *\n * Optional in the config: when omitted, `createX402bServer` wires up\n * an in-memory `Map` via `mapAsStore`. Single-process / dev\n * deployments need no extra plumbing; hosts running multiple\n * instances or who need to survive a restart MUST supply their own\n * `Store` implementation (Redis, Postgres, etc.) — otherwise the\n * Flow A redeem-time option-policy check is silently bypassed after\n * a restart because the in-memory `Map` is empty.\n */\n exchangeFulfillmentOptionStore?: Store<readonly string[]>;\n /**\n * Pending fulfillment work that reached REDEEMED on-chain but did\n * not complete server-side. Tracks both the `channel.onCommit(...)`\n * upsert and the `channel.onFulfill(...)` delivery dispatch — see\n * `FulfillmentRecoveryEntry.phase` for which step each entry left\n * behind. The commit handler records Flow B entries; the redeem\n * handler records Flow A. Each step deletes the entry on success\n * and re-records it with the error message on failure so the host\n * can replay/reconcile out of band.\n *\n * Same persistence story as `exchangeFulfillmentOptionStore`:\n * defaults to in-memory `Map`; production hosts MUST supply a\n * persistent `Store` or lose the recovery queue on every restart —\n * the on-chain voucher is irreversibly REDEEMED in that window and\n * the buyer's delivery payload becomes unrecoverable.\n */\n fulfillmentRecoveryStore?: Store<FulfillmentRecoveryEntry>;\n /**\n * Fulfillment channels the server accepts at redeem time when the\n * client re-submits delivery data. Structurally a subset of\n * `@bosonprotocol/x402-fulfillment`'s `FulfillmentChannel` — only\n * `id`, `validate`, and `onCommit` are read here, so existing\n * channel instances pass through directly. Required iff a host\n * wants to accept redeem-time fulfillment updates; absent means\n * redeem requests carrying `fulfillment` are rejected with\n * `FULFILLMENT_CHANNELS_NOT_CONFIGURED`.\n */\n fulfillmentChannels?: readonly RedeemFulfillmentChannel[];\n /**\n * Optional structured logger. Threaded through the handlers + the\n * facilitator HTTP client; events emitted include recovery-store\n * writes, channel-`onCommit` failures, facilitator retry attempts,\n * and boot diagnostics. Defaults to a no-op so the SDK is silent\n * unless the host opts in.\n */\n logger?: Logger;\n /**\n * Operational mode. Default `\"development\"` accepts everything the\n * type system allows. `\"production\"` adds a boot-time `superRefine`\n * that requires:\n *\n * - `exchangeReader` (post-settle state verification is non-optional)\n * - one of `coreSdkRead` / `subgraphUrl` (withdraw / available-funds\n * require a read client)\n * - `exchangeFulfillmentOptionStore` (otherwise the Flow A redeem-time\n * option gate silently relaxes after a restart)\n * - `fulfillmentRecoveryStore` (otherwise post-settle channel-onCommit\n * failures lose their replay handle)\n *\n * Without `mode: \"production\"`, those fields default at runtime; a\n * misconfigured deploy boots clean and only explodes on the first\n * request. `mode: \"production\"` makes the misconfiguration a synchronous\n * `ZodError` at `createX402bServer` time instead.\n */\n mode?: \"development\" | \"production\";\n}\n\n/**\n * Result of a channel's `onFulfill` dispatch. Mirrors\n * `@bosonprotocol/x402-fulfillment`'s `FulfillmentResult` (kept inline so\n * this SDK doesn't depend on that package — see `RedeemFulfillmentChannel`).\n *\n * - `inline` — the resource itself (the server base64-encodes `body` for\n * the JSON wire response; see `serializeFulfillmentResult`).\n * - `async` — delivered out-of-band; an optional `pointer` (e.g.\n * `ipfs://…`, the buyer's webhook `https://…`) is surfaced to the caller.\n */\nexport type FulfillmentResult =\n | { kind: \"inline\"; body: Uint8Array; contentType: string }\n | { kind: \"async\"; pointer?: string };\n\n/**\n * Minimal structural slice of `FulfillmentChannel` the redeem\n * handler needs. Kept inline so `@bosonprotocol/x402-server` does\n * not depend on `@bosonprotocol/x402-fulfillment` (avoids a hard\n * coupling between the resource-server SDK and a specific channel\n * package); any real channel implementation is type-compatible.\n */\nexport interface RedeemFulfillmentChannel {\n readonly id: string;\n validate(data: Record<string, unknown> | null): { ok: true } | { ok: false; reason: string };\n onCommit(exchangeId: string, data: Record<string, unknown> | null): Promise<void>;\n /**\n * Dispatch delivery once the on-chain release is confirmed (REDEEMED).\n * Optional: when present, the redeem / atomic-commit-and-redeem handlers\n * invoke it after `onCommit` persists the buyer's target, and surface\n * the result on the 200 response. A host that delivers out-of-band via\n * its own worker can omit it — persistence (`onCommit`) still runs.\n * Real `@bosonprotocol/x402-fulfillment` channels always implement it.\n */\n onFulfill?(exchangeId: string): Promise<FulfillmentResult>;\n}\n\nexport interface FulfillmentRecoveryEntry {\n exchangeId: string;\n option: string;\n data: Record<string, unknown> | null;\n redeemer: Address;\n recordedAt: number;\n /**\n * Which lifecycle step left this entry behind:\n * - `\"commit\"` — `channel.onCommit(...)` was pending / failed\n * (the server's delivery-target store was not updated).\n * - `\"delivery\"` — `onCommit` persisted, but `channel.onFulfill(...)`\n * was pending / failed (the buyer's webhook POST / IPFS upload\n * still needs dispatch).\n * A single recovery worker can dispatch the right retry step by\n * branching on this field.\n */\n phase: \"commit\" | \"delivery\";\n error?: string;\n}\n\nconst httpUrlSchema = z\n .string()\n .url()\n .refine((url) => url.startsWith(\"http://\") || url.startsWith(\"https://\"), {\n message: \"must be an http(s) URL\",\n });\n\nconst sellerSignerSchema = z\n .object({\n address: addressSchema,\n // `SellerSigner.signTypedData` is typed `Promise<Hex>` in the TS\n // interface — tighten the zod return wrapper to match so a signer\n // that resolves to a non-hex string fails loudly at call time\n // rather than silently producing a bad `BosonOfferRef.sellerSig`.\n signTypedData: z.function().args(z.unknown()).returns(z.promise(hexSchema)),\n })\n .passthrough();\n\nconst exchangeReaderShallowSchema = z\n .object({\n read: z.function().args(z.string()).returns(z.unknown()),\n })\n .passthrough();\n\nconst coreSdkReadShallowSchema = z\n .object({\n getFunds: z.function().args(z.unknown()).returns(z.unknown()),\n getSellersByAddress: z.function().args(z.unknown()).returns(z.unknown()),\n getBuyers: z.function().args(z.unknown()).returns(z.unknown()),\n })\n .passthrough();\n\nconst fulfillmentChannelShallowSchema = z\n .object({\n id: z.string().min(1),\n validate: z.function(),\n onCommit: z.function(),\n // Optional delivery dispatch — present on real channels, omitted by\n // hosts that deliver out-of-band.\n onFulfill: z.function().optional(),\n })\n .passthrough();\n\nconst asyncStoreSchema = <T>(): z.ZodType<Store<T>> =>\n z.custom<Store<T>>(isStore, {\n message: \"must implement the async Store<V> interface (get/set/delete/entries)\",\n });\n\n/**\n * zod validator for `X402bServerConfig`. Shallow on the signer +\n * exchange reader (viem account types bring their own structural\n * validators; the user-supplied reader impl is structurally typed);\n * strict on the scalar fields we own here, and on the channel\n * registry via `@bosonprotocol/x402-actions`.\n */\nexport const x402bServerConfigSchema = z\n .object({\n network: evmNetworkSchema,\n chainId: z.number().int().positive(),\n escrow: addressSchema,\n signer: sellerSignerSchema,\n facilitator: z\n .object({\n url: httpUrlSchema,\n timeoutMs: z.number().int().positive().optional(),\n retry: z\n .object({\n attempts: z.number().int().positive(),\n backoffMs: z.number().int().nonnegative(),\n })\n .strict()\n .optional(),\n idempotencyKey: z.function().args().returns(z.string()).optional(),\n })\n .strict(),\n channelRegistry: channelRegistryZodSchema,\n exchangeReader: exchangeReaderShallowSchema.optional(),\n subgraphUrl: httpUrlSchema.optional(),\n coreSdkRead: coreSdkReadShallowSchema.optional(),\n exchangeFulfillmentOptionStore: asyncStoreSchema<readonly string[]>().optional(),\n fulfillmentRecoveryStore: asyncStoreSchema<FulfillmentRecoveryEntry>().optional(),\n logger: z\n .object({\n debug: z.function(),\n info: z.function(),\n warn: z.function(),\n error: z.function(),\n })\n .passthrough()\n .optional(),\n fulfillmentChannels: z\n .array(fulfillmentChannelShallowSchema)\n .superRefine((channels, ctx) => {\n // Duplicate ids would let one channel silently shadow another\n // (the redeem handler picks via `find(c => c.id === option)`).\n const seen = new Set<string>();\n const duplicates = new Set<string>();\n for (const c of channels) {\n if (seen.has(c.id)) duplicates.add(c.id);\n seen.add(c.id);\n }\n if (duplicates.size > 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `fulfillmentChannels has duplicate id(s): ${[...duplicates].join(\", \")}`,\n });\n }\n })\n .optional(),\n mode: z.enum([\"development\", \"production\"]).optional(),\n })\n .strict()\n .superRefine((cfg, ctx) => {\n // CAIP-2 `eip155:<chainId>` carries the chainId; assert it matches\n // the explicit `chainId` field so the EIP-712 salt and the\n // wire-level network advertisement agree. Catches the easy\n // copy-paste mistake of pairing `eip155:8453` with `chainId: 1`.\n const networkChainId = Number(cfg.network.split(\":\")[1]);\n if (networkChainId !== cfg.chainId) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"chainId\"],\n message: `chainId (${cfg.chainId}) must match network (${cfg.network})`,\n });\n }\n\n // Production mode tightens the optional fields that defaulted at\n // runtime in development. Each missing prerequisite becomes a\n // synchronous ZodError at `createX402bServer` rather than a runtime\n // throw on the first request.\n if (cfg.mode === \"production\") {\n if (cfg.exchangeReader === undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"exchangeReader\"],\n message: \"required when mode is 'production' (post-settle state verification)\",\n });\n }\n if (cfg.coreSdkRead === undefined && cfg.subgraphUrl === undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"subgraphUrl\"],\n message:\n \"one of `coreSdkRead` or `subgraphUrl` is required when mode is 'production' (read client for withdraw / available-funds)\",\n });\n }\n if (cfg.exchangeFulfillmentOptionStore === undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"exchangeFulfillmentOptionStore\"],\n message:\n \"required when mode is 'production'; without a persistent store the Flow A redeem-time option gate silently relaxes after a restart\",\n });\n }\n if (cfg.fulfillmentRecoveryStore === undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"fulfillmentRecoveryStore\"],\n message:\n \"required when mode is 'production'; without a persistent store, post-settle channel-onCommit failures lose their replay handle\",\n });\n }\n }\n });\n\n/**\n * Cross-field invariant: `config.escrow` and\n * `config.channelRegistry.escrow` must agree — the Diamond address is\n * the same on both sides. Run this after `x402bServerConfigSchema.parse`.\n */\nexport function assertChannelRegistryEscrowMatch(config: X402bServerConfig): void {\n if (config.escrow.toLowerCase() !== config.channelRegistry.escrow.toLowerCase()) {\n throw new Error(\n `x402-server config: escrow (${config.escrow}) does not match channelRegistry.escrow (${config.channelRegistry.escrow})`,\n );\n }\n}\n","// Minimal read-only adapter over `@bosonprotocol/core-sdk` used by the\n// `withdraw-funds` and `available-funds` handlers.\n//\n// The full `CoreSDK` type pulls in a lot of surface area (every facet,\n// every signing helper) — none of which the read paths need. Narrowing\n// it to a structural interface keeps the server's dependency\n// footprint small for consumers that just want to expose the read\n// endpoints (and lets tests pass a hand-rolled stub without\n// constructing a real CoreSDK).\n\nimport type { CoreSDK } from \"@bosonprotocol/core-sdk\";\n\n/** Funds entity returned by `coreSdk.getFunds` — narrowed to the fields the handler reshapes. */\nexport interface CoreSdkFundsEntity {\n id?: string;\n accountId: string;\n availableAmount: string;\n token: {\n address: string;\n decimals: string;\n symbol: string;\n name: string;\n };\n}\n\n/** Seller entity returned by `coreSdk.getSellersByAddress` — only the id is consumed. */\nexport interface CoreSdkSellerEntity {\n id: string;\n}\n\n/** Buyer entity returned by `coreSdk.getBuyers` — only the id is consumed. */\nexport interface CoreSdkBuyerEntity {\n id: string;\n}\n\n/**\n * The subset of `CoreSDK` the read-only handlers actually use. Both the\n * real `CoreSDK` and a hand-rolled stub for tests satisfy this shape.\n */\nexport interface CoreSdkReadAdapter {\n getFunds(queryVars: { fundsFilter: { accountId: string } }): Promise<CoreSdkFundsEntity[]>;\n getSellersByAddress(address: string): Promise<CoreSdkSellerEntity[]>;\n getBuyers(queryVars: { buyersFilter: { wallet: string } }): Promise<CoreSdkBuyerEntity[]>;\n}\n\n/**\n * Cast a full `CoreSDK` to the narrowed adapter shape. Structural-only;\n * does not capture or wrap anything.\n */\nexport function asCoreSdkReadAdapter(coreSdk: CoreSDK): CoreSdkReadAdapter {\n return coreSdk as unknown as CoreSdkReadAdapter;\n}\n","// Per-key async mutex for exchange-scoped handlers. Two concurrent\n// `redeem(exchangeId=X)` (or dispute/*, complete) requests would both\n// pass the facilitator round-trip and race the post-settle\n// channel.onCommit / store writes — channel adapters are only\n// implicitly expected to be idempotent. The mutex serializes them so\n// only one handler holds the exchange at a time within this process.\n//\n// Server-instance-local only. Multi-instance hosts rely on the\n// idempotency-key + on-chain state checks for cross-process safety;\n// the local mutex covers the single-process race that the new async\n// `Store<V>` contract intentionally exposes (commit-time writes and\n// redeem-time reads can interleave when the store is async).\n\nexport interface KeyedMutex<K> {\n /**\n * Run `fn` once any previously-queued work for `key` has settled.\n * Successive callers for the same `key` queue in FIFO order; callers\n * for different keys run independently.\n *\n * `fn`'s resolution and rejection are surfaced to the caller\n * directly — the mutex itself never alters the return value or\n * masks errors.\n */\n runExclusive<T>(key: K, fn: () => Promise<T>): Promise<T>;\n}\n\nexport function createKeyedMutex<K>(): KeyedMutex<K> {\n const chains = new Map<K, Promise<unknown>>();\n return {\n runExclusive<T>(key: K, fn: () => Promise<T>): Promise<T> {\n const prev = chains.get(key) ?? Promise.resolve();\n // `then(fn, fn)` runs fn regardless of the prior chain's outcome —\n // a previous fn rejecting must not pin the key forever.\n const run: Promise<T> = prev.then(fn, fn);\n const tracked: Promise<unknown> = run.catch(() => undefined);\n chains.set(key, tracked);\n // Clean up the chain once *this* tail completes. Identity check\n // guards against deleting a later caller's chain entry.\n tracked.then(() => {\n if (chains.get(key) === tracked) chains.delete(key);\n });\n return run;\n },\n };\n}\n","// Health-check helper bound to a configured server. Probes the\n// facilitator's `/healthz` endpoint and a cheap subgraph read; hosts\n// mount the resulting `healthCheck()` behind whatever framework-level\n// `/healthz` / `/readyz` route they use. Framework-free on purpose —\n// the SDK doesn't dictate Express vs Hono vs Lambda.\n\nimport type { CoreSdkReadAdapter } from \"./onchain/core-sdk-read.js\";\nimport type { FacilitatorClient } from \"./facilitator/client.js\";\n\n/**\n * Per-dependency health status.\n *\n * - `\"ok\"` — last probe succeeded\n * - `\"down\"` — last probe threw or returned a non-2xx\n * - `\"n/a\"` — dependency isn't configured (subgraph is optional —\n * commit/redeem-only servers don't have one). For the subgraph\n * probe, `\"n/a\"` means **neither** `coreSdkRead` nor `subgraphUrl`\n * was supplied; a configured `subgraphUrl` is materialised on the\n * first probe so it always reports `\"ok\"` / `\"down\"`.\n */\nexport type HealthState = \"ok\" | \"down\" | \"n/a\";\n\nexport interface HealthCheckResult {\n facilitator: HealthState;\n subgraph: HealthState;\n}\n\n/** Build a `healthCheck()` function bound to a facilitator client + optional read client. */\nexport function createHealthCheck(deps: {\n facilitator: FacilitatorClient;\n coreSdkRead?: CoreSdkReadAdapter | (() => CoreSdkReadAdapter | undefined);\n}): () => Promise<HealthCheckResult> {\n return async () => {\n const facilitator: HealthState = (await probe(() => deps.facilitator.healthCheck()))\n ? \"ok\"\n : \"down\";\n\n // Resolve the read client through the factory variant inside a\n // try/catch so a synchronous throw (e.g. a lazy initializer that\n // can't reach its subgraph) reports \"down\" instead of rejecting\n // the whole health check. A factory that legitimately returns\n // `undefined` maps to \"n/a\" — `createX402bServer`'s factory only\n // returns `undefined` when neither `coreSdkRead` nor `subgraphUrl`\n // is configured.\n let readClient: CoreSdkReadAdapter | undefined;\n let readClientFailed = false;\n if (typeof deps.coreSdkRead === \"function\") {\n try {\n readClient = deps.coreSdkRead();\n } catch {\n readClientFailed = true;\n }\n } else {\n readClient = deps.coreSdkRead;\n }\n const subgraph: HealthState = readClientFailed\n ? \"down\"\n : readClient === undefined\n ? \"n/a\"\n : (await probe(() => readClient.getSellersByAddress(ZERO_ADDRESS_PROBE)))\n ? \"ok\"\n : \"down\";\n\n return { facilitator, subgraph };\n };\n}\n\nasync function probe(fn: () => Promise<unknown>): Promise<boolean> {\n try {\n await fn();\n return true;\n } catch {\n return false;\n }\n}\n\n// Cheap subgraph probe query — `getSellersByAddress(0x0)` returns an\n// empty array on a healthy subgraph, throws on a downed indexer.\nconst ZERO_ADDRESS_PROBE = \"0x0000000000000000000000000000000000000000\";\n","// `createX402bServer` — the per-server factory. Wires the 402\n// challenge builder + FullOffer signer (PR 1), and the convenience\n// handlers (commit, commit-and-redeem, redeem, complete, dispute/*,\n// withdraw-funds, available-funds) over the facilitator HTTP client +\n// configured `ExchangeReader` and read-only core-sdk client.\n\nimport { CoreSDK } from \"@bosonprotocol/core-sdk\";\nimport type { UnsignedFullOffer } from \"@bosonprotocol/x402-core/eip712\";\nimport type {\n BosonOfferRef,\n EscrowPaymentRequirements,\n} from \"@bosonprotocol/x402-core/schemes/escrow\";\n\nimport { createReadOnlyWeb3LibStub } from \"./onchain/web3lib-read-stub.js\";\n\nimport { buildPaymentRequirements } from \"./challenge/build-requirements.js\";\nimport { signFullOffer } from \"./challenge/sign-full-offer.js\";\nimport {\n assertChannelRegistryEscrowMatch,\n x402bServerConfigSchema,\n type FulfillmentRecoveryEntry,\n type X402bServerConfig,\n} from \"./config.js\";\nimport { createFacilitatorClient, type FacilitatorClient } from \"./facilitator/client.js\";\nimport {\n handleCommit,\n handleCommitAndRedeem,\n handleComplete,\n handleDisputeEscalate,\n handleDisputeRaise,\n handleDisputeResolve,\n handleDisputeRetract,\n handleGetAvailableFunds,\n handleRedeem,\n handleWithdrawFunds,\n type AvailableFundsBody,\n type AvailableFundsQuery,\n type CommitHandlerInput,\n type CommitOk,\n type HandlerResult,\n type PerformActionInput,\n type PerformActionOk,\n type PlainHandlerResult,\n type RedeemHandlerInput,\n type WithdrawFundsInput,\n type WithdrawFundsOk,\n} from \"./handlers/index.js\";\nimport { stampFacilitatorEndpoints } from \"./internal/facilitator-endpoints.js\";\nimport { asCoreSdkReadAdapter, type CoreSdkReadAdapter } from \"./onchain/core-sdk-read.js\";\nimport type { ExchangeReader } from \"./onchain/verify-exchange.js\";\nimport { mapAsStore, type Store } from \"./store.js\";\nimport { createKeyedMutex } from \"./concurrency.js\";\nimport { noopLogger, type Logger } from \"./logger.js\";\nimport { createHealthCheck, type HealthCheckResult } from \"./health.js\";\n\n/** Per-offer inputs for `server.buildPaymentRequirements` — everything the offer-level args carry, minus the per-server context the factory already holds. */\nexport interface BuildRequirementsInput {\n /** Already-signed offer reference, or `{ unsigned }` to have the server sign it. */\n offer: BosonOfferRef | { unsigned: UnsignedFullOffer };\n asset: string;\n amount: string;\n tokenAuthStrategies: readonly (\"none\" | \"erc3009\" | \"permit\" | \"permit2\")[];\n recipientId: string;\n maxTimeoutSeconds: number;\n fulfillment?: import(\"@bosonprotocol/x402-core/schemes/escrow\").FulfillmentRequirements;\n}\n\n/**\n * Result of a single `recovery.replay(exchangeId)` call. `{ ok: true }`\n * means the channel adapter's `onCommit(...)` succeeded and the recovery\n * entry has been deleted; `{ ok: false, reason }` leaves the entry in\n * place and reports the failure cause.\n */\nexport type RecoveryReplayResult = { ok: true } | { ok: false; reason: string };\n\n/**\n * Operator surface for inspecting and replaying the deferred-fulfillment\n * recovery store. The handlers record an entry when a post-settle\n * `channel.onCommit(...)` fails or is missing an adapter; the entries\n * sit until the host replays them out-of-band. This API exposes the\n * inspection + replay primitives so a host doesn't need to hold the\n * raw Map reference itself.\n */\nexport interface RecoveryApi {\n /** Snapshot of all pending recovery entries. */\n list(): Promise<readonly FulfillmentRecoveryEntry[]>;\n /**\n * Re-run the channel step that was pending when the entry was\n * recorded. Branches on `entry.phase`:\n * - `\"commit\"` → re-runs `channel.onCommit(exchangeId, entry.data)`.\n * - `\"delivery\"` → re-runs `channel.onFulfill(exchangeId)` (the\n * prior `onCommit` already persisted).\n * Deletes the entry on success; leaves it (with an updated `error`\n * field) on failure. A `\"delivery\"` entry whose channel has no\n * `onFulfill` returns `{ ok: false }` with the entry retained.\n */\n replay(exchangeId: string): Promise<RecoveryReplayResult>;\n}\n\nexport interface X402bServer {\n readonly config: X402bServerConfig;\n readonly facilitator: FacilitatorClient;\n\n /** Sign an unsigned FullOffer with the configured seller signer. */\n signOffer(unsigned: UnsignedFullOffer): Promise<BosonOfferRef>;\n /** Build a 402 `EscrowPaymentRequirements`. */\n buildPaymentRequirements(input: BuildRequirementsInput): Promise<EscrowPaymentRequirements>;\n\n /** Convenience handlers — pure, framework-agnostic. The express adapter (PR 5) maps them to routes. */\n readonly handlers: {\n commit(input: CommitHandlerInput): Promise<HandlerResult<CommitOk>>;\n commitAndRedeem(input: CommitHandlerInput): Promise<HandlerResult<CommitOk>>;\n redeem(input: RedeemHandlerInput): Promise<HandlerResult<PerformActionOk>>;\n complete(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeRaise(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeResolve(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeRetract(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n disputeEscalate(input: PerformActionInput): Promise<HandlerResult<PerformActionOk>>;\n withdrawFunds(input: WithdrawFundsInput): Promise<PlainHandlerResult<WithdrawFundsOk>>;\n getAvailableFunds(query: AvailableFundsQuery): Promise<PlainHandlerResult<AvailableFundsBody>>;\n };\n\n /**\n * Operator API for the deferred-fulfillment recovery queue. See\n * `RecoveryApi` and `docs/boson-impl-05-server-sdk.md` for the\n * operator runbook.\n */\n readonly recovery: RecoveryApi;\n\n /**\n * Liveness probe — pings the facilitator's `/healthz` and (if a\n * subgraph / read client is configured) a cheap subgraph read. Hosts\n * mount this behind whatever `/healthz` / `/readyz` route their\n * framework uses.\n */\n healthCheck(): Promise<HealthCheckResult>;\n}\n\nfunction withFacilitatorEndpoints(\n requirements: EscrowPaymentRequirements,\n facilitatorUrl: string,\n): EscrowPaymentRequirements {\n return {\n ...requirements,\n actions: {\n ...requirements.actions,\n next: stampFacilitatorEndpoints(requirements.actions.next, facilitatorUrl),\n },\n };\n}\n\n/**\n * Validate a config and return a `X402bServer` whose methods are\n * bound to the validated context. Throws synchronously (`ZodError`)\n * on bad config or (`Error`) on the escrow / channel-registry escrow\n * mismatch.\n */\nexport function createX402bServer(config: X402bServerConfig): X402bServer {\n const validated = x402bServerConfigSchema.parse(config) as X402bServerConfig;\n assertChannelRegistryEscrowMatch(validated);\n\n const logger: Logger = validated.logger ?? noopLogger;\n logger.info(\"x402-server: createX402bServer\", {\n network: validated.network,\n chainId: validated.chainId,\n escrow: validated.escrow,\n facilitatorUrl: validated.facilitator.url,\n });\n const facilitator = createFacilitatorClient({\n url: validated.facilitator.url,\n logger,\n ...(validated.facilitator.timeoutMs !== undefined\n ? { timeoutMs: validated.facilitator.timeoutMs }\n : {}),\n ...(validated.facilitator.retry !== undefined ? { retry: validated.facilitator.retry } : {}),\n ...(validated.facilitator.idempotencyKey !== undefined\n ? { idempotencyKey: validated.facilitator.idempotencyKey }\n : {}),\n });\n\n // Serialize the exchange-keyed handlers (redeem / complete / dispute*)\n // per `exchangeId`. Two concurrent redeems on the same exchange would\n // otherwise both pass the facilitator round-trip and race the\n // post-settle channel.onCommit + store writes. Process-local only —\n // multi-instance hosts rely on the new idempotency-key + on-chain\n // state checks for cross-process safety.\n const exchangeMutex = createKeyedMutex<string>();\n // Default to a fresh in-memory store when the host doesn't supply\n // one. Single shared reference for the lifetime of this server — so\n // commit-time writes and redeem-time reads observe the same backing\n // state. `mapAsStore` keeps single-process / dev deployments free of\n // extra wiring; multi-instance / restart-surviving hosts plug in\n // their own `Store` impl (Redis, Postgres, …).\n const exchangeFulfillmentOptionStore: Store<readonly string[]> =\n validated.exchangeFulfillmentOptionStore ?? mapAsStore(new Map<string, readonly string[]>());\n const fulfillmentRecoveryStore: Store<FulfillmentRecoveryEntry> =\n validated.fulfillmentRecoveryStore ?? mapAsStore(new Map<string, FulfillmentRecoveryEntry>());\n validated.exchangeFulfillmentOptionStore = exchangeFulfillmentOptionStore;\n validated.fulfillmentRecoveryStore = fulfillmentRecoveryStore;\n\n const signOffer = (unsigned: UnsignedFullOffer): Promise<BosonOfferRef> =>\n signFullOffer({\n fullOffer: unsigned,\n signer: validated.signer,\n escrow: validated.escrow,\n chainId: validated.chainId,\n });\n\n const requireReader = async (action: string): Promise<ExchangeReader> => {\n if (validated.exchangeReader === undefined) {\n throw new Error(\n `x402-server: handlers.${action}() requires \\`exchangeReader\\` in config (post-settle state verification step).`,\n );\n }\n return validated.exchangeReader;\n };\n\n // Lazy-memoised read-only core-sdk. The construction itself is cheap\n // but happens on every `handlers.withdrawFunds()` /\n // `handlers.getAvailableFunds()` call — caching the adapter keeps the\n // hot path allocation-free and shares one subgraph client across\n // requests (and the health-check probe). `validated.coreSdkRead`,\n // when supplied by the host, is already shared.\n let cachedCoreSdkRead: CoreSdkReadAdapter | undefined;\n const getOrCreateCoreSdkRead = (): CoreSdkReadAdapter | undefined => {\n if (validated.coreSdkRead !== undefined) return validated.coreSdkRead;\n if (cachedCoreSdkRead !== undefined) return cachedCoreSdkRead;\n if (validated.subgraphUrl === undefined) return undefined;\n cachedCoreSdkRead = asCoreSdkReadAdapter(\n new CoreSDK({\n web3Lib: createReadOnlyWeb3LibStub(),\n subgraphUrl: validated.subgraphUrl,\n protocolDiamond: validated.escrow,\n chainId: validated.chainId,\n }),\n );\n return cachedCoreSdkRead;\n };\n const requireCoreSdkRead = (action: string): CoreSdkReadAdapter => {\n const client = getOrCreateCoreSdkRead();\n if (client === undefined) {\n throw new Error(\n `x402-server: handlers.${action}() requires either \\`coreSdkRead\\` or \\`subgraphUrl\\` in config (subgraph read step).`,\n );\n }\n return client;\n };\n\n const recovery: RecoveryApi = {\n async list() {\n // Snapshot at call time via the Store's async iterator so callers\n // iterate a stable view even if a handler concurrently mutates\n // the store.\n const entries: FulfillmentRecoveryEntry[] = [];\n for await (const [, value] of fulfillmentRecoveryStore.entries()) {\n entries.push(value);\n }\n return entries;\n },\n async replay(exchangeId) {\n const entry = await fulfillmentRecoveryStore.get(exchangeId);\n if (entry === undefined) {\n return { ok: false, reason: `no pending recovery entry for exchangeId '${exchangeId}'` };\n }\n const channels = validated.fulfillmentChannels ?? [];\n const channel = channels.find((c) => c.id === entry.option);\n if (channel === undefined) {\n const reason = `no channel adapter is registered for option '${entry.option}'`;\n await fulfillmentRecoveryStore.set(exchangeId, { ...entry, error: reason });\n logger.warn(\"x402-server: recovery replay failed (no adapter)\", {\n exchangeId,\n option: entry.option,\n });\n return { ok: false, reason };\n }\n // Branch on the phase the entry was recorded with. `commit`\n // entries failed `onCommit`; `delivery` entries persisted but\n // failed `onFulfill`, so re-running `onCommit` would silently\n // skip the still-pending delivery dispatch.\n if (entry.phase === \"delivery\") {\n if (channel.onFulfill === undefined) {\n const reason = `channel '${entry.option}' has no onFulfill; cannot replay delivery phase`;\n await fulfillmentRecoveryStore.set(exchangeId, { ...entry, error: reason });\n logger.warn(\"x402-server: recovery replay failed (no onFulfill)\", {\n exchangeId,\n option: entry.option,\n });\n return { ok: false, reason };\n }\n try {\n await channel.onFulfill(exchangeId);\n await fulfillmentRecoveryStore.delete(exchangeId);\n logger.info(\"x402-server: recovery replay succeeded\", {\n exchangeId,\n option: entry.option,\n phase: entry.phase,\n });\n return { ok: true };\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n await fulfillmentRecoveryStore.set(exchangeId, { ...entry, error: reason });\n logger.warn(\"x402-server: recovery replay failed (channel error)\", {\n exchangeId,\n option: entry.option,\n phase: entry.phase,\n error: reason,\n });\n return { ok: false, reason };\n }\n }\n try {\n await channel.onCommit(exchangeId, entry.data);\n await fulfillmentRecoveryStore.delete(exchangeId);\n logger.info(\"x402-server: recovery replay succeeded\", {\n exchangeId,\n option: entry.option,\n phase: entry.phase,\n });\n return { ok: true };\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n await fulfillmentRecoveryStore.set(exchangeId, { ...entry, error: reason });\n logger.warn(\"x402-server: recovery replay failed (channel error)\", {\n exchangeId,\n option: entry.option,\n phase: entry.phase,\n error: reason,\n });\n return { ok: false, reason };\n }\n },\n };\n\n const healthCheck = createHealthCheck({\n facilitator,\n // Materialise the lazy `subgraphUrl`-backed read client on first\n // probe so a configured subgraph is actually checked (reporting\n // `\"ok\"` / `\"down\"` rather than `\"n/a\"`). Only the\n // \"no `coreSdkRead` AND no `subgraphUrl`\" case maps to `\"n/a\"`.\n coreSdkRead: () => getOrCreateCoreSdkRead(),\n });\n\n return {\n config: validated,\n facilitator,\n signOffer,\n recovery,\n healthCheck,\n async buildPaymentRequirements(input) {\n const offer = \"unsigned\" in input.offer ? await signOffer(input.offer.unsigned) : input.offer;\n const requirements = buildPaymentRequirements({\n offer,\n asset: input.offer && \"unsigned\" in input.offer ? input.asset : input.asset,\n amount: input.amount,\n tokenAuthStrategies: input.tokenAuthStrategies,\n recipientId: input.recipientId,\n maxTimeoutSeconds: input.maxTimeoutSeconds,\n ...(input.fulfillment !== undefined ? { fulfillment: input.fulfillment } : {}),\n network: validated.network,\n escrow: validated.escrow,\n channelRegistry: validated.channelRegistry,\n });\n return withFacilitatorEndpoints(requirements, validated.facilitator.url);\n },\n handlers: {\n commit: async (input) =>\n handleCommit(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"commit\"),\n fulfillmentRecoveryStore,\n exchangeFulfillmentOptionStore,\n logger,\n }),\n commitAndRedeem: async (input) =>\n handleCommitAndRedeem(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"commitAndRedeem\"),\n fulfillmentRecoveryStore,\n exchangeFulfillmentOptionStore,\n logger,\n }),\n redeem: async (input) =>\n exchangeMutex.runExclusive(input.exchangeId, async () =>\n handleRedeem(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"redeem\"),\n exchangeFulfillmentOptionStore,\n fulfillmentRecoveryStore,\n logger,\n }),\n ),\n complete: async (input) =>\n exchangeMutex.runExclusive(input.exchangeId, async () =>\n handleComplete(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"complete\"),\n logger,\n }),\n ),\n disputeRaise: async (input) =>\n exchangeMutex.runExclusive(input.exchangeId, async () =>\n handleDisputeRaise(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeRaise\"),\n logger,\n }),\n ),\n disputeResolve: async (input) =>\n exchangeMutex.runExclusive(input.exchangeId, async () =>\n handleDisputeResolve(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeResolve\"),\n logger,\n }),\n ),\n disputeRetract: async (input) =>\n exchangeMutex.runExclusive(input.exchangeId, async () =>\n handleDisputeRetract(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeRetract\"),\n logger,\n }),\n ),\n disputeEscalate: async (input) =>\n exchangeMutex.runExclusive(input.exchangeId, async () =>\n handleDisputeEscalate(input, {\n config: validated,\n facilitator,\n exchangeReader: await requireReader(\"disputeEscalate\"),\n logger,\n }),\n ),\n withdrawFunds: async (input) =>\n handleWithdrawFunds(input, {\n config: validated,\n facilitator,\n coreSdkRead: requireCoreSdkRead(\"withdrawFunds\"),\n }),\n getAvailableFunds: async (query) =>\n handleGetAvailableFunds(query, {\n coreSdkRead: requireCoreSdkRead(\"getAvailableFunds\"),\n }),\n },\n };\n}\n","// Encoder for the `X-PAYMENT-RESPONSE` header. The base x402 spec uses\n// base64-of-JSON for `X-PAYMENT-RESPONSE`, and the buyer SDK's\n// `parsePaymentResponse` ([client/src/response.ts]) decodes it the\n// same way. This helper is the inverse — give it the success body and\n// it produces the header value.\n//\n// The header is best-effort metadata that lets the client read\n// `exchangeId` (and any future scheme-specific fields) without parsing\n// the full JSON body. We pass the body through verbatim so the wire\n// shape is identical to the response body; consumers stay free to\n// branch on either.\n\n/**\n * Base64-encode the success-response body for the `X-PAYMENT-RESPONSE`\n * header. The companion decoder lives in\n * `@bosonprotocol/x402-client`'s `parsePaymentResponse`.\n */\nexport function encodeXPaymentResponse(body: unknown): string {\n const json = JSON.stringify(body);\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(json, \"utf8\").toString(\"base64\");\n }\n // Node ships `Buffer`; the browser fallback exists for completeness so\n // a non-Node integrator (Workers, Deno) can reuse this helper.\n const bytes = new TextEncoder().encode(json);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/** Canonical header name — exported so adapters share one spelling. */\nexport const X_PAYMENT_RESPONSE_HEADER = \"X-PAYMENT-RESPONSE\" as const;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bosonprotocol/x402-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0-alpha-0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Framework-agnostic x402 resource-server SDK for the Boson Protocol escrow scheme — 402 challenge builder and FullOffer signer hook.",
6
6
  "repository": {
@@ -70,8 +70,8 @@
70
70
  "zod": "^3.24.2",
71
71
  "@bosonprotocol/x402-actions": "^0.2.0",
72
72
  "@bosonprotocol/x402-evm": "^0.2.0",
73
- "@bosonprotocol/x402-core": "^0.2.0",
74
- "@bosonprotocol/x402-facilitator": "^1.0.0"
73
+ "@bosonprotocol/x402-facilitator": "^1.0.0",
74
+ "@bosonprotocol/x402-core": "^0.2.1"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@types/node": "^20.17.10",
@@ -1,36 +0,0 @@
1
- import { FacilitatorVerifyInput, FacilitatorVerifyResult, FacilitatorSettleInput, FacilitatorSettleResult, FacilitatorPerformActionInput, FacilitatorPerformActionResult } from '@bosonprotocol/x402-facilitator';
2
-
3
- type FetchLike = (input: string, init?: {
4
- method?: string;
5
- headers?: Record<string, string>;
6
- body?: string;
7
- }) => Promise<{
8
- ok: boolean;
9
- status: number;
10
- text: () => Promise<string>;
11
- json?: () => Promise<unknown>;
12
- }>;
13
- interface CreateFacilitatorClientOptions {
14
- /** Base URL of the facilitator service (no trailing slash needed). */
15
- url: string;
16
- /** Optional `fetch` override — defaults to the global `fetch`. Useful for tests + non-`fetch` runtimes. */
17
- fetch?: FetchLike;
18
- /** Optional headers attached to every request — e.g. an `Authorization` for hosted facilitators. */
19
- headers?: Record<string, string>;
20
- }
21
- interface FacilitatorClient {
22
- verify(input: FacilitatorVerifyInput): Promise<FacilitatorVerifyResult>;
23
- settle(input: FacilitatorSettleInput): Promise<FacilitatorSettleResult>;
24
- performAction(input: FacilitatorPerformActionInput): Promise<FacilitatorPerformActionResult>;
25
- }
26
- /**
27
- * Construct a typed HTTP client for the facilitator. The returned
28
- * methods stringify the input as JSON and POST to the matching path
29
- * on the configured URL. Bodies matching the well-formed result shape
30
- * (whether HTTP 2xx success or HTTP 400 domain rejection) are returned
31
- * verbatim; transport failures (network, non-JSON body,
32
- * schema-mismatched body) raise `FacilitatorHttpError`.
33
- */
34
- declare function createFacilitatorClient(opts: CreateFacilitatorClientOptions): FacilitatorClient;
35
-
36
- export { type CreateFacilitatorClientOptions as C, type FacilitatorClient as F, type FetchLike as a, createFacilitatorClient as c };
@@ -1,124 +0,0 @@
1
- import { FacilitatorHttpError } from './chunk-PU5Y7FZG.js';
2
-
3
- // src/facilitator/client.ts
4
- function createFacilitatorClient(opts) {
5
- const fetchImpl = opts.fetch ?? globalThis.fetch;
6
- if (fetchImpl === void 0) {
7
- throw new Error(
8
- "createFacilitatorClient: no `fetch` implementation available. Pass `opts.fetch` explicitly."
9
- );
10
- }
11
- const baseUrl = opts.url.replace(/\/+$/, "");
12
- const baseHeaders = { "content-type": "application/json", ...opts.headers ?? {} };
13
- const post = async (path, body, validate) => {
14
- let res;
15
- try {
16
- res = await fetchImpl(`${baseUrl}${path}`, {
17
- method: "POST",
18
- headers: baseHeaders,
19
- body: JSON.stringify(body)
20
- });
21
- } catch (cause) {
22
- throw new FacilitatorHttpError(`facilitator network error (${path})`, {
23
- code: "NETWORK_ERROR",
24
- cause
25
- });
26
- }
27
- let text;
28
- try {
29
- text = await res.text();
30
- } catch (cause) {
31
- throw new FacilitatorHttpError(`facilitator response body could not be read (${path})`, {
32
- code: "BAD_RESPONSE_BODY",
33
- status: res.status,
34
- cause
35
- });
36
- }
37
- let parsed;
38
- try {
39
- parsed = text.length === 0 ? null : JSON.parse(text);
40
- } catch (cause) {
41
- throw new FacilitatorHttpError(`facilitator returned non-JSON body (${path})`, {
42
- code: "BAD_RESPONSE_BODY",
43
- status: res.status,
44
- cause
45
- });
46
- }
47
- if (!res.ok) {
48
- if (res.status === 400 && isFailureBranch(parsed) && validate(parsed)) {
49
- return parsed;
50
- }
51
- const facilitatorCode = extractFacilitatorCode(parsed);
52
- throw new FacilitatorHttpError(
53
- `facilitator HTTP ${res.status} (${path}): ${reasonString(parsed) ?? text}`,
54
- {
55
- code: "BAD_HTTP_STATUS",
56
- status: res.status,
57
- ...facilitatorCode !== void 0 ? { facilitatorCode } : {}
58
- }
59
- );
60
- }
61
- if (!validate(parsed)) {
62
- throw new FacilitatorHttpError(`facilitator returned unexpected body shape (${path})`, {
63
- code: "BAD_RESPONSE_BODY",
64
- status: res.status
65
- });
66
- }
67
- return parsed;
68
- };
69
- return {
70
- verify: (input) => post("/verify", input, isVerifyResult),
71
- settle: (input) => post("/settle", input, isSettleResult),
72
- performAction: (input) => post(
73
- `/perform-action?action=${encodeURIComponent(input.action)}`,
74
- input,
75
- isPerformActionResult
76
- )
77
- };
78
- }
79
- function isObject(v) {
80
- return v !== null && typeof v === "object";
81
- }
82
- function isFailureBranch(v) {
83
- return isObject(v) && v.ok === false && typeof v.code === "string" && typeof v.reason === "string";
84
- }
85
- function isVerifyResult(parsed) {
86
- if (!isObject(parsed)) return false;
87
- if (parsed.ok === true) return true;
88
- return isFailureBranch(parsed);
89
- }
90
- function isSettleResult(parsed) {
91
- if (!isObject(parsed)) return false;
92
- if (parsed.ok === true) {
93
- return typeof parsed.exchangeId === "string" && typeof parsed.txHash === "string";
94
- }
95
- return isFailureBranch(parsed);
96
- }
97
- function isPerformActionResult(parsed) {
98
- if (!isObject(parsed)) return false;
99
- if (parsed.ok === true) {
100
- if (typeof parsed.txHash !== "string") return false;
101
- if (parsed.newExchangeState !== void 0 && typeof parsed.newExchangeState !== "string") {
102
- return false;
103
- }
104
- if (parsed.newDisputeState !== void 0 && typeof parsed.newDisputeState !== "string") {
105
- return false;
106
- }
107
- return true;
108
- }
109
- return isFailureBranch(parsed);
110
- }
111
- function extractFacilitatorCode(body) {
112
- if (body === null || typeof body !== "object") return void 0;
113
- const code = body.code;
114
- return typeof code === "string" ? code : void 0;
115
- }
116
- function reasonString(body) {
117
- if (body === null || typeof body !== "object") return void 0;
118
- const reason = body.reason;
119
- return typeof reason === "string" ? reason : void 0;
120
- }
121
-
122
- export { createFacilitatorClient };
123
- //# sourceMappingURL=chunk-EAKQ4EFZ.js.map
124
- //# sourceMappingURL=chunk-EAKQ4EFZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/facilitator/client.ts"],"names":[],"mappings":"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","file":"chunk-EAKQ4EFZ.js","sourcesContent":["// HTTP client for the Boson facilitator service. The facilitator runs\n// as a remote process implementing the three endpoints in\n// docs/boson-impl-07-facilitator.md (`/verify`, `/settle`,\n// `/perform-action?action=<action>`); this module wraps `fetch` with the typed\n// request/response shapes exported by `@bosonprotocol/x402-facilitator`.\n//\n// Domain results (`{ ok: true, ... }` or `{ ok: false, code, reason }`)\n// are returned verbatim — both shapes are answers the caller branches\n// on. The facilitator-express adapter emits domain failures over HTTP\n// 400 (so curl users still see a 4xx), but the wire body is still a\n// well-formed result; we recognise that shape on HTTP 400 responses and\n// hand it back rather than throwing. HTTP-transport failures (network\n// down, non-JSON body, schema-mismatched body) throw\n// `FacilitatorHttpError` so the composition layer can distinguish\n// \"facilitator said no\" from \"we couldn't reach the facilitator\".\n\nimport type {\n FacilitatorErrorCode,\n FacilitatorPerformActionInput,\n FacilitatorPerformActionResult,\n FacilitatorSettleInput,\n FacilitatorSettleResult,\n FacilitatorVerifyInput,\n FacilitatorVerifyResult,\n} from \"@bosonprotocol/x402-facilitator\";\n\nimport { FacilitatorHttpError } from \"./errors.js\";\n\nexport type FetchLike = (\n input: string,\n init?: { method?: string; headers?: Record<string, string>; body?: string },\n) => Promise<{\n ok: boolean;\n status: number;\n text: () => Promise<string>;\n json?: () => Promise<unknown>;\n}>;\n\nexport interface CreateFacilitatorClientOptions {\n /** Base URL of the facilitator service (no trailing slash needed). */\n url: string;\n /** Optional `fetch` override — defaults to the global `fetch`. Useful for tests + non-`fetch` runtimes. */\n fetch?: FetchLike;\n /** Optional headers attached to every request — e.g. an `Authorization` for hosted facilitators. */\n headers?: Record<string, string>;\n}\n\nexport interface FacilitatorClient {\n verify(input: FacilitatorVerifyInput): Promise<FacilitatorVerifyResult>;\n settle(input: FacilitatorSettleInput): Promise<FacilitatorSettleResult>;\n performAction(input: FacilitatorPerformActionInput): Promise<FacilitatorPerformActionResult>;\n}\n\n/**\n * Construct a typed HTTP client for the facilitator. The returned\n * methods stringify the input as JSON and POST to the matching path\n * on the configured URL. Bodies matching the well-formed result shape\n * (whether HTTP 2xx success or HTTP 400 domain rejection) are returned\n * verbatim; transport failures (network, non-JSON body,\n * schema-mismatched body) raise `FacilitatorHttpError`.\n */\nexport function createFacilitatorClient(opts: CreateFacilitatorClientOptions): FacilitatorClient {\n const fetchImpl = opts.fetch ?? (globalThis.fetch as FetchLike | undefined);\n if (fetchImpl === undefined) {\n throw new Error(\n \"createFacilitatorClient: no `fetch` implementation available. Pass `opts.fetch` explicitly.\",\n );\n }\n const baseUrl = opts.url.replace(/\\/+$/, \"\");\n const baseHeaders = { \"content-type\": \"application/json\", ...(opts.headers ?? {}) };\n\n const post = async <Req, Res>(\n path: string,\n body: Req,\n validate: (parsed: unknown) => parsed is Res,\n ): Promise<Res> => {\n let res: Awaited<ReturnType<FetchLike>>;\n try {\n res = await fetchImpl(`${baseUrl}${path}`, {\n method: \"POST\",\n headers: baseHeaders,\n body: JSON.stringify(body),\n });\n } catch (cause) {\n throw new FacilitatorHttpError(`facilitator network error (${path})`, {\n code: \"NETWORK_ERROR\",\n cause,\n });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (cause) {\n throw new FacilitatorHttpError(`facilitator response body could not be read (${path})`, {\n code: \"BAD_RESPONSE_BODY\",\n status: res.status,\n cause,\n });\n }\n\n let parsed: unknown;\n try {\n parsed = text.length === 0 ? null : JSON.parse(text);\n } catch (cause) {\n throw new FacilitatorHttpError(`facilitator returned non-JSON body (${path})`, {\n code: \"BAD_RESPONSE_BODY\",\n status: res.status,\n cause,\n });\n }\n\n if (!res.ok) {\n // The facilitator-express adapter returns domain failures as\n // HTTP 400 with the `{ok:false, code, reason}` body. Detect that\n // shape and surface it as the typed result — every endpoint's\n // `Res` union includes the same `{ok:false, code, reason}`\n // variant, so the cast through `validate` (which also accepts\n // that shape) preserves type-safety. Any other non-2xx status is\n // a genuine transport failure even if its body happens to look\n // like a facilitator result.\n if (res.status === 400 && isFailureBranch(parsed) && validate(parsed)) {\n return parsed;\n }\n const facilitatorCode = extractFacilitatorCode(parsed);\n throw new FacilitatorHttpError(\n `facilitator HTTP ${res.status} (${path}): ${reasonString(parsed) ?? text}`,\n {\n code: \"BAD_HTTP_STATUS\",\n status: res.status,\n ...(facilitatorCode !== undefined ? { facilitatorCode } : {}),\n },\n );\n }\n\n if (!validate(parsed)) {\n throw new FacilitatorHttpError(`facilitator returned unexpected body shape (${path})`, {\n code: \"BAD_RESPONSE_BODY\",\n status: res.status,\n });\n }\n return parsed;\n };\n\n return {\n verify: (input) =>\n post<FacilitatorVerifyInput, FacilitatorVerifyResult>(\"/verify\", input, isVerifyResult),\n settle: (input) =>\n post<FacilitatorSettleInput, FacilitatorSettleResult>(\"/settle\", input, isSettleResult),\n performAction: (input) =>\n post<FacilitatorPerformActionInput, FacilitatorPerformActionResult>(\n `/perform-action?action=${encodeURIComponent(input.action)}`,\n input,\n isPerformActionResult,\n ),\n };\n}\n\n// --- Response-shape type guards ----------------------------------------\n//\n// A buggy or malicious facilitator could return any 2xx JSON; without a\n// runtime check, `parsed as Res` would silently slip an unexpected shape\n// past the type system and the convenience handlers (PR 4) would\n// dereference fields that aren't there. These guards mirror the\n// discriminated unions in `@bosonprotocol/x402-facilitator`'s types and\n// fail any response that doesn't fit — surfaced as\n// `BAD_RESPONSE_BODY` so the caller treats it as a transport-layer\n// failure rather than a domain answer.\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === \"object\";\n}\n\n/**\n * Failure branch is identical across all three endpoints. Accepts\n * `unknown` so the non-2xx path can pre-check the parsed body without\n * narrowing first.\n */\nfunction isFailureBranch(v: unknown): v is { ok: false; code: string; reason: string } {\n return (\n isObject(v) && v.ok === false && typeof v.code === \"string\" && typeof v.reason === \"string\"\n );\n}\n\nfunction isVerifyResult(parsed: unknown): parsed is FacilitatorVerifyResult {\n if (!isObject(parsed)) return false;\n if (parsed.ok === true) return true; // `{ ok: true }` carries no further fields\n return isFailureBranch(parsed);\n}\n\nfunction isSettleResult(parsed: unknown): parsed is FacilitatorSettleResult {\n if (!isObject(parsed)) return false;\n if (parsed.ok === true) {\n return typeof parsed.exchangeId === \"string\" && typeof parsed.txHash === \"string\";\n }\n return isFailureBranch(parsed);\n}\n\nfunction isPerformActionResult(parsed: unknown): parsed is FacilitatorPerformActionResult {\n if (!isObject(parsed)) return false;\n if (parsed.ok === true) {\n if (typeof parsed.txHash !== \"string\") return false;\n // Entity-keyed actions (e.g. `boson-withdrawFunds`) return just\n // `{ ok: true, txHash }` — no exchange state transition. Accept\n // that shape; only require `newExchangeState` when present.\n if (parsed.newExchangeState !== undefined && typeof parsed.newExchangeState !== \"string\") {\n return false;\n }\n if (parsed.newDisputeState !== undefined && typeof parsed.newDisputeState !== \"string\") {\n return false;\n }\n return true;\n }\n return isFailureBranch(parsed);\n}\n\nfunction extractFacilitatorCode(body: unknown): FacilitatorErrorCode | undefined {\n if (body === null || typeof body !== \"object\") return undefined;\n const code = (body as { code?: unknown }).code;\n return typeof code === \"string\" ? (code as FacilitatorErrorCode) : undefined;\n}\n\nfunction reasonString(body: unknown): string | undefined {\n if (body === null || typeof body !== \"object\") return undefined;\n const reason = (body as { reason?: unknown }).reason;\n return typeof reason === \"string\" ? reason : undefined;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/facilitator/errors.ts"],"names":[],"mappings":";AAqBO,IAAM,oBAAA,GAAN,cAAmC,KAAA,CAAM;AAAA,EAM9C,WAAA,CACE,SACA,IAAA,EAMA;AACA,IAAA,KAAA,CAAM,OAAA,EAAS,KAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,IAAA,CAAK,KAAA,EAAM,GAAI,MAAS,CAAA;AAC3E,IAAA,IAAA,CAAK,IAAA,GAAO,sBAAA;AACZ,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA;AACjB,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,MAAA,EAAW,IAAA,CAAK,SAAS,IAAA,CAAK,MAAA;AAClD,IAAA,IAAI,IAAA,CAAK,eAAA,KAAoB,MAAA,EAAW,IAAA,CAAK,kBAAkB,IAAA,CAAK,eAAA;AAAA,EACtE;AACF","file":"chunk-PU5Y7FZG.js","sourcesContent":["// Typed error class for HTTP-level facilitator failures. Distinct from\n// the `{ ok: false, code }` shape the facilitator itself returns —\n// those are domain errors and surface in the typed result. This class\n// is thrown only when the HTTP transport fails (network error,\n// non-2xx response with an unparseable body, etc.).\n\nimport type { FacilitatorErrorCode } from \"@bosonprotocol/x402-facilitator\";\n\n/**\n * Stable, x402-server-side codes for HTTP-transport failures.\n * Distinct from the facilitator-side `FacilitatorErrorCode` enum so\n * callers can branch on \"the facilitator answered with X\" vs \"we\n * never reached the facilitator\".\n */\nexport type FacilitatorHttpErrorCode =\n | \"NETWORK_ERROR\"\n | \"BAD_HTTP_STATUS\"\n | \"BAD_RESPONSE_BODY\"\n | \"TIMEOUT\";\n\n/** Network- or transport-layer failure when calling the facilitator. */\nexport class FacilitatorHttpError extends Error {\n readonly code: FacilitatorHttpErrorCode;\n readonly status?: number;\n /** Original facilitator-side error code, if the body parsed cleanly. */\n readonly facilitatorCode?: FacilitatorErrorCode;\n\n constructor(\n message: string,\n init: {\n code: FacilitatorHttpErrorCode;\n status?: number;\n facilitatorCode?: FacilitatorErrorCode;\n cause?: unknown;\n },\n ) {\n super(message, init.cause !== undefined ? { cause: init.cause } : undefined);\n this.name = \"FacilitatorHttpError\";\n this.code = init.code;\n if (init.status !== undefined) this.status = init.status;\n if (init.facilitatorCode !== undefined) this.facilitatorCode = init.facilitatorCode;\n }\n}\n"]}