@okxweb3/app-x402-core 0.1.2 → 0.2.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.
Files changed (57) hide show
  1. package/dist/cjs/OKXFacilitatorClient-Bqyw9fzj.d.ts +69 -0
  2. package/dist/cjs/client/index.d.ts +1 -1
  3. package/dist/cjs/client/index.js +34 -0
  4. package/dist/cjs/client/index.js.map +1 -1
  5. package/dist/cjs/facilitator/index.d.ts +2 -2
  6. package/dist/cjs/facilitator/index.js +166 -4
  7. package/dist/cjs/facilitator/index.js.map +1 -1
  8. package/dist/cjs/http/index.d.ts +5 -3
  9. package/dist/cjs/http/index.js +1241 -7
  10. package/dist/cjs/http/index.js.map +1 -1
  11. package/dist/cjs/index-2gWfiUbK.d.ts +713 -0
  12. package/dist/cjs/index.d.ts +2 -2
  13. package/dist/cjs/index.js +166 -4
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/{mechanisms-sojpSwWW.d.ts → mechanisms-LhI9qkRo.d.ts} +509 -1
  16. package/dist/cjs/server/index.d.ts +4 -2
  17. package/dist/cjs/server/index.js +1256 -7
  18. package/dist/cjs/server/index.js.map +1 -1
  19. package/dist/cjs/subscription/index.d.ts +3 -0
  20. package/dist/cjs/subscription/index.js +600 -0
  21. package/dist/cjs/subscription/index.js.map +1 -0
  22. package/dist/cjs/types/index.d.ts +1 -1
  23. package/dist/cjs/utils/index.d.ts +1 -1
  24. package/dist/cjs/{x402HTTPResourceServer-CcsAkcgI.d.ts → x402HTTPResourceServer-B0mXzV8r.d.ts} +114 -1
  25. package/dist/esm/OKXFacilitatorClient-z-cCE5Db.d.mts +69 -0
  26. package/dist/esm/chunk-4KASWSSY.mjs +257 -0
  27. package/dist/esm/chunk-4KASWSSY.mjs.map +1 -0
  28. package/dist/esm/chunk-CKXR4QVD.mjs +274 -0
  29. package/dist/esm/chunk-CKXR4QVD.mjs.map +1 -0
  30. package/dist/esm/{chunk-XBQG2CDV.mjs → chunk-EYS4TWVA.mjs} +617 -9
  31. package/dist/esm/chunk-EYS4TWVA.mjs.map +1 -0
  32. package/dist/esm/client/index.d.mts +1 -1
  33. package/dist/esm/client/index.mjs +3 -2
  34. package/dist/esm/client/index.mjs.map +1 -1
  35. package/dist/esm/facilitator/index.d.mts +2 -2
  36. package/dist/esm/facilitator/index.mjs +2 -1
  37. package/dist/esm/facilitator/index.mjs.map +1 -1
  38. package/dist/esm/http/index.d.mts +5 -3
  39. package/dist/esm/http/index.mjs +3 -2
  40. package/dist/esm/index-DKbqlTu_.d.mts +713 -0
  41. package/dist/esm/index.d.mts +2 -2
  42. package/dist/esm/index.mjs +2 -1
  43. package/dist/esm/{mechanisms-sojpSwWW.d.mts → mechanisms-LhI9qkRo.d.mts} +509 -1
  44. package/dist/esm/server/index.d.mts +4 -2
  45. package/dist/esm/server/index.mjs +3 -2
  46. package/dist/esm/subscription/index.d.mts +3 -0
  47. package/dist/esm/subscription/index.mjs +309 -0
  48. package/dist/esm/subscription/index.mjs.map +1 -0
  49. package/dist/esm/types/index.d.mts +1 -1
  50. package/dist/esm/utils/index.d.mts +1 -1
  51. package/dist/esm/{x402HTTPResourceServer-DBeutKxq.d.mts → x402HTTPResourceServer-56Tq3Jup.d.mts} +114 -1
  52. package/package.json +12 -1
  53. package/dist/cjs/OKXFacilitatorClient-BvyQB1QM.d.ts +0 -59
  54. package/dist/esm/OKXFacilitatorClient-D5E3LX50.d.mts +0 -59
  55. package/dist/esm/chunk-O3IYMTNT.mjs +0 -118
  56. package/dist/esm/chunk-O3IYMTNT.mjs.map +0 -1
  57. package/dist/esm/chunk-XBQG2CDV.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/http/index.ts","../../../src/utils/index.ts","../../../src/types/facilitator.ts","../../../src/schemas/index.ts","../../../src/http/httpFacilitatorClient.ts","../../../src/facilitator/OKXFacilitatorClient.ts","../../../src/index.ts","../../../src/server/x402ResourceServer.ts","../../../src/http/x402HTTPResourceServer.ts","../../../src/http/x402HTTPClient.ts"],"sourcesContent":["import { SettleResponse } from \"../types\";\nimport { PaymentPayload, PaymentRequired } from \"../types/payments\";\nimport { Base64EncodedRegex, safeBase64Decode, safeBase64Encode } from \"../utils\";\n\n// HTTP Methods that typically use query parameters\nexport type QueryParamMethods = \"GET\" | \"HEAD\" | \"DELETE\";\n\n// HTTP Methods that typically use request body\nexport type BodyMethods = \"POST\" | \"PUT\" | \"PATCH\";\n\n/**\n * Encodes a payment payload as a base64 header value.\n *\n * @param paymentPayload - The payment payload to encode\n * @returns Base64 encoded string representation of the payment payload\n */\nexport function encodePaymentSignatureHeader(paymentPayload: PaymentPayload): string {\n return safeBase64Encode(JSON.stringify(paymentPayload));\n}\n\n/**\n * Decodes a base64 payment signature header into a payment payload.\n *\n * @param paymentSignatureHeader - The base64 encoded payment signature header\n * @returns The decoded payment payload\n */\nexport function decodePaymentSignatureHeader(paymentSignatureHeader: string): PaymentPayload {\n if (!Base64EncodedRegex.test(paymentSignatureHeader)) {\n throw new Error(\"Invalid payment signature header\");\n }\n return JSON.parse(safeBase64Decode(paymentSignatureHeader)) as PaymentPayload;\n}\n\n/**\n * Encodes a payment required object as a base64 header value.\n *\n * @param paymentRequired - The payment required object to encode\n * @returns Base64 encoded string representation of the payment required object\n */\nexport function encodePaymentRequiredHeader(paymentRequired: PaymentRequired): string {\n return safeBase64Encode(JSON.stringify(paymentRequired));\n}\n\n/**\n * Decodes a base64 payment required header into a payment required object.\n *\n * @param paymentRequiredHeader - The base64 encoded payment required header\n * @returns The decoded payment required object\n */\nexport function decodePaymentRequiredHeader(paymentRequiredHeader: string): PaymentRequired {\n if (!Base64EncodedRegex.test(paymentRequiredHeader)) {\n throw new Error(\"Invalid payment required header\");\n }\n return JSON.parse(safeBase64Decode(paymentRequiredHeader)) as PaymentRequired;\n}\n\n/**\n * Encodes a payment response as a base64 header value.\n *\n * @param paymentResponse - The payment response to encode\n * @returns Base64 encoded string representation of the payment response\n */\nexport function encodePaymentResponseHeader(paymentResponse: SettleResponse): string {\n return safeBase64Encode(JSON.stringify(paymentResponse));\n}\n\n/**\n * Decodes a base64 payment response header into a settle response.\n *\n * @param paymentResponseHeader - The base64 encoded payment response header\n * @returns The decoded settle response\n */\nexport function decodePaymentResponseHeader(paymentResponseHeader: string): SettleResponse {\n if (!Base64EncodedRegex.test(paymentResponseHeader)) {\n throw new Error(\"Invalid payment response header\");\n }\n return JSON.parse(safeBase64Decode(paymentResponseHeader)) as SettleResponse;\n}\n\n// Export HTTP service and types\nexport {\n x402HTTPResourceServer,\n HTTPAdapter,\n HTTPRequestContext,\n HTTPTransportContext,\n HTTPResponseInstructions,\n HTTPProcessResult,\n PaywallConfig,\n PaywallProvider,\n PaymentOption,\n RouteConfig,\n RoutesConfig,\n CompiledRoute,\n DynamicPayTo,\n DynamicPrice,\n UnpaidResponseBody,\n HTTPResponseBody,\n SettlementFailedResponseBody,\n ProcessSettleResultResponse,\n ProcessSettleSuccessResponse,\n ProcessSettleFailureResponse,\n RouteValidationError,\n RouteConfigurationError,\n ProtectedRequestHook,\n OnSettlementTimeoutHook,\n} from \"./x402HTTPResourceServer\";\nexport {\n HTTPFacilitatorClient,\n FacilitatorClient,\n FacilitatorConfig,\n} from \"./httpFacilitatorClient\";\nexport { FacilitatorResponseError, getFacilitatorResponseError } from \"../types\";\nexport { x402HTTPClient, PaymentRequiredContext, PaymentRequiredHook } from \"./x402HTTPClient\";\n","import { Network } from \"../types\";\n\n/**\n * Scheme data structure for facilitator storage\n */\nexport interface SchemeData<T> {\n facilitator: T;\n networks: Set<Network>;\n pattern: Network;\n}\n\nexport const findSchemesByNetwork = <T>(\n map: Map<string, Map<string, T>>,\n network: Network,\n): Map<string, T> | undefined => {\n // Direct match first\n let implementationsByScheme = map.get(network);\n\n if (!implementationsByScheme) {\n // Try pattern matching for registered network patterns\n for (const [registeredNetworkPattern, implementations] of map.entries()) {\n // Convert the registered network pattern to a regex\n // e.g., \"eip155:*\" becomes /^eip155:.*$/\n const pattern = registeredNetworkPattern\n .replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\") // Escape special regex chars except *\n .replace(/\\\\\\*/g, \".*\"); // Replace escaped * with .*\n\n const regex = new RegExp(`^${pattern}$`);\n\n if (regex.test(network)) {\n implementationsByScheme = implementations;\n break;\n }\n }\n }\n\n return implementationsByScheme;\n};\n\nexport const findByNetworkAndScheme = <T>(\n map: Map<string, Map<string, T>>,\n scheme: string,\n network: Network,\n): T | undefined => {\n return findSchemesByNetwork(map, network)?.get(scheme);\n};\n\n/**\n * Finds a facilitator by scheme and network using pattern matching.\n * Works with new SchemeData storage structure.\n *\n * @param schemeMap - Map of scheme names to SchemeData\n * @param scheme - The scheme to find\n * @param network - The network to match against\n * @returns The facilitator if found, undefined otherwise\n */\nexport const findFacilitatorBySchemeAndNetwork = <T>(\n schemeMap: Map<string, SchemeData<T>>,\n scheme: string,\n network: Network,\n): T | undefined => {\n const schemeData = schemeMap.get(scheme);\n if (!schemeData) return undefined;\n\n // Check if network is in the stored networks set\n if (schemeData.networks.has(network)) {\n return schemeData.facilitator;\n }\n\n // Try pattern matching\n const patternRegex = new RegExp(\"^\" + schemeData.pattern.replace(\"*\", \".*\") + \"$\");\n if (patternRegex.test(network)) {\n return schemeData.facilitator;\n }\n\n return undefined;\n};\n\nexport const Base64EncodedRegex = /^[A-Za-z0-9+/]*={0,2}$/;\n\n/**\n * Encodes a string to base64 format\n *\n * @param data - The string to be encoded to base64\n * @returns The base64 encoded string\n */\nexport function safeBase64Encode(data: string): string {\n if (typeof globalThis !== \"undefined\" && typeof globalThis.btoa === \"function\") {\n const bytes = new TextEncoder().encode(data);\n const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join(\"\");\n return globalThis.btoa(binaryString);\n }\n return Buffer.from(data, \"utf8\").toString(\"base64\");\n}\n\n/**\n * Decodes a base64 string back to its original format\n *\n * @param data - The base64 encoded string to be decoded\n * @returns The decoded string in UTF-8 format\n */\nexport function safeBase64Decode(data: string): string {\n if (typeof globalThis !== \"undefined\" && typeof globalThis.atob === \"function\") {\n const binaryString = globalThis.atob(data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder(\"utf-8\");\n return decoder.decode(bytes);\n }\n return Buffer.from(data, \"base64\").toString(\"utf-8\");\n}\n\n/**\n * Deep equality comparison for payment requirements\n * Uses a normalized JSON.stringify for consistent comparison\n *\n * @param obj1 - First object to compare\n * @param obj2 - Second object to compare\n * @returns True if objects are deeply equal\n */\nexport function deepEqual(obj1: unknown, obj2: unknown): boolean {\n // Normalize and stringify both objects for comparison\n // This handles nested objects, arrays, and different property orders\n const normalize = (obj: unknown): string => {\n // Handle primitives and null/undefined\n if (obj === null || obj === undefined) return JSON.stringify(obj);\n if (typeof obj !== \"object\") return JSON.stringify(obj);\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return JSON.stringify(\n obj.map(item =>\n typeof item === \"object\" && item !== null ? JSON.parse(normalize(item)) : item,\n ),\n );\n }\n\n // Handle objects - sort keys and recursively normalize values\n const sorted: Record<string, unknown> = {};\n Object.keys(obj as Record<string, unknown>)\n .sort()\n .forEach(key => {\n const value = (obj as Record<string, unknown>)[key];\n sorted[key] =\n typeof value === \"object\" && value !== null ? JSON.parse(normalize(value)) : value;\n });\n return JSON.stringify(sorted);\n };\n\n try {\n return normalize(obj1) === normalize(obj2);\n } catch {\n // Fallback to simple comparison if normalization fails\n return JSON.stringify(obj1) === JSON.stringify(obj2);\n }\n}\n","import { PaymentPayload, PaymentRequirements } from \"./payments\";\nimport { Network } from \"./\";\n\nexport type VerifyRequest = {\n x402Version: number;\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n};\n\nexport type VerifyResponse = {\n isValid: boolean;\n invalidReason?: string;\n invalidMessage?: string;\n payer?: string;\n extensions?: Record<string, unknown>;\n};\n\nexport type SettleRequest = {\n x402Version: number;\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n};\n\nexport type SettleResponse = {\n success: boolean;\n /** OKX extension: pending (async, Seller trusts Facilitator), success (immediate), timeout (on-chain timed out) */\n status?: \"pending\" | \"success\" | \"timeout\";\n errorReason?: string;\n errorMessage?: string;\n payer?: string;\n transaction: string;\n network: Network;\n /** Actual amount settled in atomic token units. Present for schemes like `upto` where settlement amount may differ from the authorized maximum. */\n amount?: string;\n extensions?: Record<string, unknown>;\n};\n\nexport type SupportedKind = {\n x402Version: number;\n scheme: string;\n network: Network;\n extra?: Record<string, unknown>;\n};\n\nexport type SupportedResponse = {\n kinds: SupportedKind[];\n extensions: string[];\n signers: Record<string, string[]>; // CAIP family pattern → Signer addresses\n};\n\n/**\n * Response from `GET /settle/status?txHash=...`.\n * OKX extension: query on-chain settlement status by transaction hash.\n */\nexport type SettleStatusResponse = {\n success: boolean;\n status?: \"pending\" | \"success\" | \"failed\";\n errorReason?: string;\n errorMessage?: string;\n payer?: string;\n transaction?: string;\n network?: Network;\n};\n\n/**\n * Error thrown when payment verification fails.\n */\nexport class VerifyError extends Error {\n readonly invalidReason?: string;\n readonly invalidMessage?: string;\n readonly payer?: string;\n readonly statusCode: number;\n\n /**\n * Creates a VerifyError from a failed verification response.\n *\n * @param statusCode - HTTP status code from the facilitator\n * @param response - The verify response containing error details\n */\n constructor(statusCode: number, response: VerifyResponse) {\n const reason = response.invalidReason || \"unknown reason\";\n const message = response.invalidMessage;\n super(message ? `${reason}: ${message}` : reason);\n this.name = \"VerifyError\";\n this.statusCode = statusCode;\n this.invalidReason = response.invalidReason;\n this.invalidMessage = response.invalidMessage;\n this.payer = response.payer;\n }\n}\n\n/**\n * Error thrown when payment settlement fails.\n */\nexport class SettleError extends Error {\n readonly errorReason?: string;\n readonly errorMessage?: string;\n readonly payer?: string;\n readonly transaction: string;\n readonly network: Network;\n readonly statusCode: number;\n\n /**\n * Creates a SettleError from a failed settlement response.\n *\n * @param statusCode - HTTP status code from the facilitator\n * @param response - The settle response containing error details\n */\n constructor(statusCode: number, response: SettleResponse) {\n const reason = response.errorReason || \"unknown reason\";\n const message = response.errorMessage;\n super(message ? `${reason}: ${message}` : reason);\n this.name = \"SettleError\";\n this.statusCode = statusCode;\n this.errorReason = response.errorReason;\n this.errorMessage = response.errorMessage;\n this.payer = response.payer;\n this.transaction = response.transaction;\n this.network = response.network;\n }\n}\n\n/**\n * Error thrown when a facilitator returns malformed success payload data.\n */\nexport class FacilitatorResponseError extends Error {\n /**\n * Creates a FacilitatorResponseError for malformed facilitator responses.\n *\n * @param message - The boundary error message\n */\n constructor(message: string) {\n super(message);\n this.name = \"FacilitatorResponseError\";\n }\n}\n\n/**\n * Walks an error cause chain to find the first facilitator response error.\n *\n * @param error - The thrown value to inspect\n * @returns The nested facilitator response error, if present\n */\nexport function getFacilitatorResponseError(error: unknown): FacilitatorResponseError | null {\n let current = error;\n\n while (current instanceof Error) {\n if (current instanceof FacilitatorResponseError) {\n return current;\n }\n current = current.cause;\n }\n\n return null;\n}\n","import { z } from \"zod\";\n\n// ============================================================================\n// Reusable Primitive Schemas\n// ============================================================================\n\n/**\n * Non-empty string schema - a string with at least one character.\n * Used for required string fields that cannot be empty.\n */\nexport const NonEmptyString = z.string().min(1);\nexport type NonEmptyString = z.infer<typeof NonEmptyString>;\n\n/**\n * Any record schema - an object with unknown keys and values.\n * Used for scheme-specific payloads and other extensible objects.\n */\nexport const Any = z.record(z.unknown());\nexport type Any = z.infer<typeof Any>;\n\n/**\n * Optional any record schema - an optional object with unknown keys and values.\n * Used for optional extension fields like `extra` and `extensions`.\n */\nexport const OptionalAny = z.record(z.unknown()).optional().nullable();\nexport type OptionalAny = z.infer<typeof OptionalAny>;\n\n// ============================================================================\n// Network Schemas\n// ============================================================================\n\n/**\n * Network identifier schema - CAIP-2 format validation.\n * Requires minimum length of 3 and a colon separator (e.g., \"eip155:196\", \"eip155:196\").\n */\nexport const NetworkSchema = z\n .string()\n .min(3)\n .refine(val => val.includes(\":\"), {\n message: \"Network must be in CAIP-2 format (e.g., 'eip155:196')\",\n });\nexport type Network = z.infer<typeof NetworkSchema>;\n\n// ============================================================================\n// Shared Schemas\n// ============================================================================\n\n/**\n * ResourceInfo schema for V2 - describes the protected resource.\n */\nexport const ResourceInfoSchema = z.object({\n url: NonEmptyString,\n description: z.string().optional(),\n mimeType: z.string().optional(),\n});\nexport type ResourceInfo = z.infer<typeof ResourceInfoSchema>;\n\n// ============================================================================\n// Payment Schemas\n// ============================================================================\n\n/**\n * PaymentRequirements schema.\n */\nexport const PaymentRequirementsSchema = z.object({\n scheme: NonEmptyString,\n network: NetworkSchema,\n amount: NonEmptyString,\n asset: NonEmptyString,\n payTo: NonEmptyString,\n maxTimeoutSeconds: z.number().positive(),\n extra: OptionalAny,\n});\nexport type PaymentRequirements = z.infer<typeof PaymentRequirementsSchema>;\n\n/**\n * PaymentRequired (402 response) schema.\n * Contains payment requirements when a resource requires payment.\n */\nexport const PaymentRequiredSchema = z.object({\n x402Version: z.literal(2),\n error: z.string().optional(),\n resource: ResourceInfoSchema,\n accepts: z.array(PaymentRequirementsSchema).min(1),\n extensions: OptionalAny,\n});\nexport type PaymentRequired = z.infer<typeof PaymentRequiredSchema>;\n\n/**\n * PaymentPayload schema.\n * Contains the payment data sent by the client.\n */\nexport const PaymentPayloadSchema = z.object({\n x402Version: z.literal(2),\n resource: ResourceInfoSchema.optional(),\n accepted: PaymentRequirementsSchema,\n payload: Any,\n extensions: OptionalAny,\n});\nexport type PaymentPayload = z.infer<typeof PaymentPayloadSchema>;\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validates a PaymentRequired object (V1 or V2).\n *\n * @param value - The value to validate\n * @returns A result object with success status and data or error\n */\nexport function parsePaymentRequired(\n value: unknown,\n): z.SafeParseReturnType<unknown, PaymentRequired> {\n return PaymentRequiredSchema.safeParse(value);\n}\n\n/**\n * Validates a PaymentRequired object and throws on error.\n *\n * @param value - The value to validate\n * @returns The validated PaymentRequired\n * @throws ZodError if validation fails\n */\nexport function validatePaymentRequired(value: unknown): PaymentRequired {\n return PaymentRequiredSchema.parse(value);\n}\n\n/**\n * Type guard for PaymentRequired (V1 or V2).\n *\n * @param value - The value to check\n * @returns True if the value is a valid PaymentRequired\n */\nexport function isPaymentRequired(value: unknown): value is PaymentRequired {\n return PaymentRequiredSchema.safeParse(value).success;\n}\n\n/**\n * Validates a PaymentRequirements object (V1 or V2).\n *\n * @param value - The value to validate\n * @returns A result object with success status and data or error\n */\nexport function parsePaymentRequirements(\n value: unknown,\n): z.SafeParseReturnType<unknown, PaymentRequirements> {\n return PaymentRequirementsSchema.safeParse(value);\n}\n\n/**\n * Validates a PaymentRequirements object and throws on error.\n *\n * @param value - The value to validate\n * @returns The validated PaymentRequirements\n * @throws ZodError if validation fails\n */\nexport function validatePaymentRequirements(value: unknown): PaymentRequirements {\n return PaymentRequirementsSchema.parse(value);\n}\n\n/**\n * Type guard for PaymentRequirements (V1 or V2).\n *\n * @param value - The value to check\n * @returns True if the value is a valid PaymentRequirements\n */\nexport function isPaymentRequirements(value: unknown): value is PaymentRequirements {\n return PaymentRequirementsSchema.safeParse(value).success;\n}\n\n/**\n * Validates a PaymentPayload object (V1 or V2).\n *\n * @param value - The value to validate\n * @returns A result object with success status and data or error\n */\nexport function parsePaymentPayload(\n value: unknown,\n): z.SafeParseReturnType<unknown, PaymentPayload> {\n return PaymentPayloadSchema.safeParse(value);\n}\n\n/**\n * Validates a PaymentPayload object and throws on error.\n *\n * @param value - The value to validate\n * @returns The validated PaymentPayload\n * @throws ZodError if validation fails\n */\nexport function validatePaymentPayload(value: unknown): PaymentPayload {\n return PaymentPayloadSchema.parse(value);\n}\n\n/**\n * Type guard for PaymentPayload (V1 or V2).\n *\n * @param value - The value to check\n * @returns True if the value is a valid PaymentPayload\n */\nexport function isPaymentPayload(value: unknown): value is PaymentPayload {\n return PaymentPayloadSchema.safeParse(value).success;\n}\n\n// ============================================================================\n// Re-export zod for convenience\n// ============================================================================\n\nexport { z } from \"zod\";\n","import { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport {\n VerifyResponse,\n SettleResponse,\n SettleStatusResponse,\n SupportedResponse,\n VerifyError,\n SettleError,\n FacilitatorResponseError,\n} from \"../types/facilitator\";\nimport { z } from \"../schemas\";\n\nconst DEFAULT_FACILITATOR_URL = \"https://web3.okx.com/facilitator\";\n\nexport interface FacilitatorConfig {\n url?: string;\n createAuthHeaders?: () => Promise<{\n verify: Record<string, string>;\n settle: Record<string, string>;\n supported: Record<string, string>;\n }>;\n}\n\n/**\n * Interface for facilitator clients\n * Can be implemented for HTTP-based or local facilitators\n */\nexport interface FacilitatorClient {\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentPayload - The payment to verify\n * @param paymentRequirements - The requirements to verify against\n * @returns Verification response\n */\n verify(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<VerifyResponse>;\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentPayload - The payment to settle\n * @param paymentRequirements - The requirements for settlement\n * @returns Settlement response\n */\n settle(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<SettleResponse>;\n\n /**\n * Get supported payment kinds and extensions from the facilitator\n *\n * @returns Supported payment kinds and extensions\n */\n getSupported(): Promise<SupportedResponse>;\n\n /**\n * Query on-chain settlement status by transaction hash.\n * OKX extension: used for timeout recovery polling.\n *\n * @param txHash - The transaction hash to query\n * @returns Settlement status response\n */\n getSettleStatus?(txHash: string): Promise<SettleStatusResponse>;\n}\n\n/** Number of retries for getSupported() on 429 rate limit errors */\nconst GET_SUPPORTED_RETRIES = 3;\n/** Base delay in ms for exponential backoff on retries */\nconst GET_SUPPORTED_RETRY_DELAY_MS = 1000;\n\nconst verifyResponseSchema: z.ZodType<VerifyResponse, z.ZodTypeDef, unknown> = z.object({\n isValid: z.boolean(),\n invalidReason: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n invalidMessage: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n payer: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n extensions: z\n .record(z.string(), z.unknown())\n .nullish()\n .transform(v => v ?? undefined),\n});\n\nconst settleResponseSchema: z.ZodType<SettleResponse, z.ZodTypeDef, unknown> = z.object({\n success: z.boolean(),\n // OKX extension: pending (async), success (immediate), timeout (on-chain timed out)\n status: z\n .enum([\"pending\", \"success\", \"timeout\"])\n .nullish()\n .transform(v => v ?? undefined)\n .optional(),\n errorReason: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n errorMessage: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n payer: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n transaction: z.string(),\n network: z.custom<SettleResponse[\"network\"]>(value => typeof value === \"string\"),\n amount: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n extensions: z\n .record(z.string(), z.unknown())\n .nullish()\n .transform(v => v ?? undefined),\n});\n\nconst supportedKindSchema: z.ZodType<SupportedResponse[\"kinds\"][number], z.ZodTypeDef, unknown> =\n z.object({\n x402Version: z.number(),\n scheme: z.string(),\n network: z.custom<SupportedResponse[\"kinds\"][number][\"network\"]>(\n value => typeof value === \"string\",\n ),\n extra: z\n .record(z.string(), z.unknown())\n .nullish()\n .transform(v => v ?? undefined),\n });\n\nconst supportedResponseSchema: z.ZodType<SupportedResponse, z.ZodTypeDef, unknown> = z.object({\n kinds: z.array(supportedKindSchema),\n extensions: z.array(z.string()).default([]),\n signers: z.record(z.string(), z.array(z.string())).default({}),\n});\n\n/**\n * Produces a compact excerpt of a facilitator response body for error messages.\n *\n * @param text - The raw response body text\n * @param limit - The maximum number of characters to include\n * @returns A normalized excerpt suitable for logs and thrown errors\n */\nfunction responseExcerpt(text: string, limit: number = 200): string {\n const compact = text.trim().replace(/\\s+/g, \" \");\n if (!compact) {\n return \"<empty response>\";\n }\n\n if (compact.length <= limit) {\n return compact;\n }\n\n return `${compact.slice(0, limit - 3)}...`;\n}\n\n/**\n * Parses and validates a successful facilitator response body.\n *\n * @param response - The HTTP response returned by the facilitator\n * @param schema - The schema used to validate the response payload\n * @param operation - The facilitator operation name for error reporting\n * @returns The validated facilitator payload\n */\nasync function parseSuccessResponse<T>(\n response: Response,\n schema: z.ZodType<T, z.ZodTypeDef, unknown>,\n operation: string,\n): Promise<T> {\n const text = await response.text();\n\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new FacilitatorResponseError(\n `Facilitator ${operation} returned invalid JSON: ${responseExcerpt(text)}`,\n );\n }\n\n const parsed = schema.safeParse(data);\n if (!parsed.success) {\n throw new FacilitatorResponseError(\n `Facilitator ${operation} returned invalid data: ${responseExcerpt(text)}`,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * HTTP-based client for interacting with x402 facilitator services\n * Handles HTTP communication with facilitator endpoints\n */\nexport class HTTPFacilitatorClient implements FacilitatorClient {\n readonly url: string;\n private readonly _createAuthHeaders?: FacilitatorConfig[\"createAuthHeaders\"];\n\n /**\n * Creates a new HTTPFacilitatorClient instance.\n *\n * @param config - Configuration options for the facilitator client\n */\n constructor(config?: FacilitatorConfig) {\n this.url = config?.url || DEFAULT_FACILITATOR_URL;\n this._createAuthHeaders = config?.createAuthHeaders;\n }\n\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentPayload - The payment to verify\n * @param paymentRequirements - The requirements to verify against\n * @returns Verification response\n */\n async verify(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"verify\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n const response = await fetch(`${this.url}/verify`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n x402Version: paymentPayload.x402Version,\n paymentPayload: this.toJsonSafe(paymentPayload),\n paymentRequirements: this.toJsonSafe(paymentRequirements),\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(`Facilitator verify failed (${response.status}): ${responseExcerpt(text)}`);\n }\n\n if (typeof data === \"object\" && data !== null && \"isValid\" in data) {\n throw new VerifyError(response.status, data as VerifyResponse);\n }\n\n throw new Error(\n `Facilitator verify failed (${response.status}): ${responseExcerpt(JSON.stringify(data))}`,\n );\n }\n\n return parseSuccessResponse(response, verifyResponseSchema, \"verify\");\n }\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentPayload - The payment to settle\n * @param paymentRequirements - The requirements for settlement\n * @returns Settlement response\n */\n async settle(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"settle\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n const response = await fetch(`${this.url}/settle`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n x402Version: paymentPayload.x402Version,\n paymentPayload: this.toJsonSafe(paymentPayload),\n paymentRequirements: this.toJsonSafe(paymentRequirements),\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(`Facilitator settle failed (${response.status}): ${responseExcerpt(text)}`);\n }\n\n if (typeof data === \"object\" && data !== null && \"success\" in data) {\n throw new SettleError(response.status, data as SettleResponse);\n }\n\n throw new Error(\n `Facilitator settle failed (${response.status}): ${responseExcerpt(JSON.stringify(data))}`,\n );\n }\n\n return parseSuccessResponse(response, settleResponseSchema, \"settle\");\n }\n\n /**\n * Get supported payment kinds and extensions from the facilitator.\n * Retries with exponential backoff on 429 rate limit errors.\n *\n * @returns Supported payment kinds and extensions\n */\n async getSupported(): Promise<SupportedResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"supported\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < GET_SUPPORTED_RETRIES; attempt++) {\n const response = await fetch(`${this.url}/supported`, {\n method: \"GET\",\n headers,\n });\n\n if (response.ok) {\n return parseSuccessResponse(response, supportedResponseSchema, \"supported\");\n }\n\n const errorText = await response.text().catch(() => response.statusText);\n lastError = new Error(\n `Facilitator getSupported failed (${response.status}): ${responseExcerpt(errorText)}`,\n );\n\n // Retry on 429 rate limit errors with exponential backoff\n if (response.status === 429 && attempt < GET_SUPPORTED_RETRIES - 1) {\n const delay = GET_SUPPORTED_RETRY_DELAY_MS * Math.pow(2, attempt);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n throw lastError;\n }\n\n throw lastError ?? new Error(\"Facilitator getSupported failed after retries\");\n }\n\n /**\n * Query on-chain settlement status by transaction hash.\n *\n * @param txHash - The transaction hash to query\n * @returns Settlement status response\n */\n async getSettleStatus(txHash: string): Promise<SettleStatusResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"settle/status\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n const response = await fetch(`${this.url}/settle/status?txHash=${encodeURIComponent(txHash)}`, {\n method: \"GET\",\n headers,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => response.statusText);\n throw new Error(\n `Facilitator getSettleStatus failed (${response.status}): ${responseExcerpt(text)}`,\n );\n }\n\n const json = (await response.json()) as SettleStatusResponse;\n return json;\n }\n\n /**\n * Creates authentication headers for a specific path.\n *\n * @param path - The path to create authentication headers for (e.g., \"verify\", \"settle\", \"supported\")\n * @returns An object containing the authentication headers for the specified path\n */\n async createAuthHeaders(path: string): Promise<{\n headers: Record<string, string>;\n }> {\n if (this._createAuthHeaders) {\n const authHeaders = (await this._createAuthHeaders()) as Record<\n string,\n Record<string, string>\n >;\n return {\n headers: authHeaders[path] ?? {},\n };\n }\n return {\n headers: {},\n };\n }\n\n /**\n * Helper to convert objects to JSON-safe format.\n * Handles BigInt and other non-JSON types.\n *\n * @param obj - The object to convert\n * @returns The JSON-safe representation of the object\n */\n private toJsonSafe(obj: unknown): unknown {\n return JSON.parse(\n JSON.stringify(obj, (_, value) => (typeof value === \"bigint\" ? value.toString() : value)),\n );\n }\n}\n","import crypto from \"node:crypto\";\nimport type { FacilitatorClient } from \"../http/httpFacilitatorClient.js\";\nimport type {\n VerifyResponse,\n SettleResponse,\n SettleStatusResponse,\n SupportedResponse,\n} from \"../types/facilitator.js\";\nimport type { PaymentPayload, PaymentRequirements } from \"../types/payments.js\";\n\nexport interface OKXConfig {\n apiKey: string;\n secretKey: string;\n passphrase: string;\n baseUrl?: string;\n /**\n * OKX exact-scheme extension: when true, the settle call tells the facilitator to\n * wait for on-chain confirmation before responding (syncSettle=true in request body).\n * The facilitator then returns status=\"success\" directly (no polling needed).\n * When false (default), the facilitator responds with status=\"pending\" immediately.\n */\n syncSettle?: boolean;\n}\n\n/**\n * OKX facilitator client implementing the FacilitatorClient interface.\n * Uses HMAC-SHA256 signing per OKX REST API authentication spec.\n */\nexport class OKXFacilitatorClient implements FacilitatorClient {\n private config: Required<Omit<OKXConfig, \"syncSettle\">> & Pick<OKXConfig, \"syncSettle\">;\n\n /**\n *\n * @param config\n */\n constructor(config: OKXConfig) {\n this.config = {\n baseUrl: \"https://web3.okx.com\",\n ...config,\n };\n }\n\n /**\n *\n * @param method\n * @param path\n * @param body\n */\n private createHeaders(method: string, path: string, body?: string): Record<string, string> {\n const timestamp = new Date().toISOString();\n const prehash = timestamp + method + path + (body ?? \"\");\n const sign = crypto\n .createHmac(\"sha256\", this.config.secretKey)\n .update(prehash)\n .digest(\"base64\");\n\n return {\n \"OK-ACCESS-KEY\": this.config.apiKey,\n \"OK-ACCESS-SIGN\": sign,\n \"OK-ACCESS-TIMESTAMP\": timestamp,\n \"OK-ACCESS-PASSPHRASE\": this.config.passphrase,\n \"Content-Type\": \"application/json\",\n };\n }\n\n /**\n *\n */\n async getSupported(): Promise<SupportedResponse> {\n const path = \"/api/v6/pay/x402/supported\";\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) throw new Error(`OKX getSupported failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n // OKX API wraps responses in { code, data, msg } envelope\n const data = (json.data ?? json) as SupportedResponse;\n return data;\n }\n\n /**\n *\n * @param payload\n * @param requirements\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const path = \"/api/v6/pay/x402/verify\";\n const body = JSON.stringify({\n x402Version: 2,\n paymentPayload: payload,\n paymentRequirements: requirements,\n });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX verify failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n const data = (json.data ?? json) as VerifyResponse;\n return data;\n }\n\n /**\n *\n * @param payload\n * @param requirements\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const path = \"/api/v6/pay/x402/settle\";\n // Include OKX-extension syncSettle field when configured:\n // syncSettle=true → facilitator waits for on-chain confirmation, returns status=\"success\"\n // syncSettle=false → facilitator returns immediately with status=\"pending\" (default)\n const bodyObj: Record<string, unknown> = {\n x402Version: 2,\n paymentPayload: payload,\n paymentRequirements: requirements,\n };\n if (this.config.syncSettle !== undefined) {\n bodyObj.syncSettle = this.config.syncSettle;\n }\n const body = JSON.stringify(bodyObj);\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX settle failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n const data = (json.data ?? json) as SettleResponse;\n return data;\n }\n\n /**\n * Query on-chain settlement status by transaction hash.\n *\n * @param txHash - The transaction hash to query\n * @returns Settlement status response\n */\n async getSettleStatus(txHash: string): Promise<SettleStatusResponse> {\n const path = `/api/v6/pay/x402/settle/status?txHash=${encodeURIComponent(txHash)}`;\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) throw new Error(`OKX getSettleStatus failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n const data = (json.data ?? json) as SettleStatusResponse;\n return data;\n }\n}\n","export const x402Version = 2;\nexport { OKXFacilitatorClient } from \"./facilitator/OKXFacilitatorClient\";\nexport type { OKXConfig } from \"./facilitator/OKXFacilitatorClient\";","import {\n SettleError,\n SettleResponse,\n SettleStatusResponse,\n VerifyResponse,\n SupportedResponse,\n SupportedKind,\n} from \"../types/facilitator\";\nimport {\n PaymentPayload,\n PaymentRequirements,\n PaymentRequired,\n ResourceInfo,\n} from \"../types/payments\";\nimport { SchemeNetworkServer } from \"../types/mechanisms\";\nimport { Price, Network, ResourceServerExtension, VerifyError } from \"../types\";\nimport { deepEqual, findByNetworkAndScheme } from \"../utils\";\nimport { FacilitatorClient, HTTPFacilitatorClient } from \"../http/httpFacilitatorClient\";\nimport { x402Version } from \"..\";\n\n/** Default poll interval for settle/status queries (1 second). */\nexport const DEFAULT_POLL_INTERVAL_MS = 1_000;\n\n/** Default poll deadline for settle/status queries (5 seconds). */\nexport const DEFAULT_POLL_DEADLINE_MS = 5_000;\n\n/** Result of polling `GET /settle/status`. */\nexport type PollResult = \"success\" | \"failed\" | \"timeout\";\n\n/**\n * Configuration for a protected resource\n * Only contains payment-specific configuration, not resource metadata\n */\nexport interface ResourceConfig {\n scheme: string;\n payTo: string; // Payment recipient address\n price: Price;\n network: Network;\n maxTimeoutSeconds?: number;\n extra?: Record<string, unknown>; // Scheme-specific additional data\n}\n\n/**\n * Lifecycle Hook Context Interfaces\n */\n\nexport interface PaymentRequiredContext {\n requirements: PaymentRequirements[];\n resourceInfo: ResourceInfo;\n error?: string;\n paymentRequiredResponse: PaymentRequired;\n transportContext?: unknown;\n}\n\nexport interface VerifyContext {\n paymentPayload: PaymentPayload;\n requirements: PaymentRequirements;\n}\n\nexport interface VerifyResultContext extends VerifyContext {\n result: VerifyResponse;\n}\n\nexport interface VerifyFailureContext extends VerifyContext {\n error: Error;\n}\n\nexport interface SettleContext {\n paymentPayload: PaymentPayload;\n requirements: PaymentRequirements;\n}\n\nexport interface SettleResultContext extends SettleContext {\n result: SettleResponse;\n transportContext?: unknown;\n}\n\nexport interface SettleFailureContext extends SettleContext {\n error: Error;\n}\n\n/**\n * Lifecycle Hook Type Definitions\n */\n\nexport type BeforeVerifyHook = (\n context: VerifyContext,\n) => Promise<void | { abort: true; reason: string; message?: string }>;\n\nexport type AfterVerifyHook = (context: VerifyResultContext) => Promise<void>;\n\nexport type OnVerifyFailureHook = (\n context: VerifyFailureContext,\n) => Promise<void | { recovered: true; result: VerifyResponse }>;\n\nexport type BeforeSettleHook = (\n context: SettleContext,\n) => Promise<void | { abort: true; reason: string; message?: string }>;\n\nexport type AfterSettleHook = (context: SettleResultContext) => Promise<void>;\n\nexport type OnSettleFailureHook = (\n context: SettleFailureContext,\n) => Promise<void | { recovered: true; result: SettleResponse }>;\n\n/**\n * Optional overrides for settlement parameters.\n * Used to support partial settlement (e.g., upto scheme billing by actual usage).\n *\n * Note: Overriding the amount to a value different from the agreed-upon\n * `PaymentRequirements.amount` is only valid in schemes that explicitly support\n * partial settlement, such as the `upto` scheme. Using this with standard\n * x402 schemes (e.g., `exact`) will likely cause settlement verification to fail.\n */\nexport interface SettlementOverrides {\n /**\n * Amount to settle. Supports three formats:\n *\n * - **Raw atomic units** — e.g., `\"1000\"` settles exactly 1000 atomic units.\n * - **Percent** — e.g., `\"50%\"` settles 50% of `PaymentRequirements.amount`.\n * Supports up to two decimal places (e.g., `\"33.33%\"`). The result is floored\n * to the nearest atomic unit.\n * - **Dollar price** — e.g., `\"$0.05\"` converts a USD-denominated price to\n * atomic units. Uses `PaymentRequirements.extra.decimals` if set; otherwise\n * defaults to 6 (standard for USDC stablecoins). The result is rounded to\n * the nearest atomic unit.\n *\n * The resolved amount must be <= the authorized maximum in `PaymentRequirements`.\n *\n * Note: Setting this to an amount other than `PaymentRequirements.amount` is\n * only valid in schemes that support partial settlement, such as `upto`.\n */\n amount?: string;\n}\n\n/**\n * Resolves a settlement override amount string to a final atomic-unit string.\n *\n * Supports three input formats (see {@link SettlementOverrides.amount}):\n * - Raw atomic units: `\"1000\"`\n * - Percent of `PaymentRequirements.amount`: `\"50%\"`\n * - Dollar price: `\"$0.05\"` (uses `requirements.extra.decimals` or defaults to 6)\n *\n * @param rawAmount - The override amount string (e.g., `\"1000\"`, `\"50%\"`, `\"$0.05\"`)\n * @param requirements - The payment requirements containing the base amount and token decimals\n * @returns The resolved amount as an atomic-unit string\n */\nexport function resolveSettlementOverrideAmount(\n rawAmount: string,\n requirements: PaymentRequirements,\n): string {\n // Percent format: \"50%\" or \"33.33%\"\n const percentMatch = rawAmount.match(/^(\\d+(?:\\.\\d{0,2})?)%$/);\n if (percentMatch) {\n const [intPart, decPart = \"\"] = percentMatch[1].split(\".\");\n const scaledPercent = BigInt(intPart) * 100n + BigInt(decPart.padEnd(2, \"0\").slice(0, 2));\n const base = BigInt(requirements.amount);\n return ((base * scaledPercent) / 10000n).toString();\n }\n\n // Dollar price format: \"$0.05\"\n const dollarMatch = rawAmount.match(/^\\$(\\d+(?:\\.\\d+)?)$/);\n if (dollarMatch) {\n const decimals =\n typeof requirements.extra?.decimals === \"number\" ? requirements.extra.decimals : 6;\n const dollars = parseFloat(dollarMatch[1]);\n return Math.round(dollars * 10 ** decimals).toString();\n }\n\n // Raw atomic units (existing behavior)\n return rawAmount;\n}\n\n/**\n * Core x402 protocol server for resource protection\n * Transport-agnostic implementation of the x402 payment protocol\n */\nexport class x402ResourceServer {\n private facilitatorClients: FacilitatorClient[];\n private registeredServerSchemes: Map<string, Map<string, SchemeNetworkServer>> = new Map();\n private supportedResponsesMap: Map<number, Map<string, Map<string, SupportedResponse>>> =\n new Map();\n private facilitatorClientsMap: Map<number, Map<string, Map<string, FacilitatorClient>>> =\n new Map();\n private registeredExtensions: Map<string, ResourceServerExtension> = new Map();\n\n private beforeVerifyHooks: BeforeVerifyHook[] = [];\n private afterVerifyHooks: AfterVerifyHook[] = [];\n private onVerifyFailureHooks: OnVerifyFailureHook[] = [];\n private beforeSettleHooks: BeforeSettleHook[] = [];\n private afterSettleHooks: AfterSettleHook[] = [];\n private onSettleFailureHooks: OnSettleFailureHook[] = [];\n\n /**\n * Creates a new x402ResourceServer instance.\n *\n * @param facilitatorClients - Optional facilitator client(s) for payment processing\n */\n constructor(facilitatorClients?: FacilitatorClient | FacilitatorClient[]) {\n // Normalize facilitator clients to array\n if (!facilitatorClients) {\n // No clients provided, create a default HTTP client\n this.facilitatorClients = [new HTTPFacilitatorClient()];\n } else if (Array.isArray(facilitatorClients)) {\n // Array of clients provided\n this.facilitatorClients =\n facilitatorClients.length > 0 ? facilitatorClients : [new HTTPFacilitatorClient()];\n } else {\n // Single client provided\n this.facilitatorClients = [facilitatorClients];\n }\n }\n\n /**\n * Register a scheme/network server implementation.\n *\n * @param network - The network identifier\n * @param server - The scheme/network server implementation\n * @returns The x402ResourceServer instance for chaining\n */\n register(network: Network, server: SchemeNetworkServer): x402ResourceServer {\n if (!this.registeredServerSchemes.has(network)) {\n this.registeredServerSchemes.set(network, new Map());\n }\n\n const serverByScheme = this.registeredServerSchemes.get(network)!;\n if (!serverByScheme.has(server.scheme)) {\n serverByScheme.set(server.scheme, server);\n }\n\n return this;\n }\n\n /**\n * Check if a scheme is registered for a given network.\n *\n * @param network - The network identifier\n * @param scheme - The payment scheme name\n * @returns True if the scheme is registered for the network, false otherwise\n */\n hasRegisteredScheme(network: Network, scheme: string): boolean {\n return !!findByNetworkAndScheme(this.registeredServerSchemes, scheme, network);\n }\n\n /**\n * Registers a resource service extension that can enrich extension declarations.\n *\n * @param extension - The extension to register\n * @returns The x402ResourceServer instance for chaining\n */\n registerExtension(extension: ResourceServerExtension): this {\n this.registeredExtensions.set(extension.key, extension);\n return this;\n }\n\n /**\n * Check if an extension is registered.\n *\n * @param key - The extension key\n * @returns True if the extension is registered\n */\n hasExtension(key: string): boolean {\n return this.registeredExtensions.has(key);\n }\n\n /**\n * Get all registered extensions.\n *\n * @returns Array of registered extensions\n */\n getExtensions(): ResourceServerExtension[] {\n return Array.from(this.registeredExtensions.values());\n }\n\n /**\n * Enriches declared extensions using registered extension hooks.\n *\n * @param declaredExtensions - Extensions declared on the route\n * @param transportContext - Transport-specific context (HTTP, A2A, MCP, etc.)\n * @returns Enriched extensions map\n */\n enrichExtensions(\n declaredExtensions: Record<string, unknown>,\n transportContext: unknown,\n ): Record<string, unknown> {\n const enriched: Record<string, unknown> = {};\n\n for (const [key, declaration] of Object.entries(declaredExtensions)) {\n const extension = this.registeredExtensions.get(key);\n\n if (extension?.enrichDeclaration) {\n enriched[key] = extension.enrichDeclaration(declaration, transportContext);\n } else {\n enriched[key] = declaration;\n }\n }\n\n return enriched;\n }\n\n /**\n * Register a hook to execute before payment verification.\n * Can abort verification by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onBeforeVerify(hook: BeforeVerifyHook): x402ResourceServer {\n this.beforeVerifyHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment verification.\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onAfterVerify(hook: AfterVerifyHook): x402ResourceServer {\n this.afterVerifyHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment verification fails.\n * Can recover from failure by returning { recovered: true, result: VerifyResponse }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onVerifyFailure(hook: OnVerifyFailureHook): x402ResourceServer {\n this.onVerifyFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute before payment settlement.\n * Can abort settlement by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onBeforeSettle(hook: BeforeSettleHook): x402ResourceServer {\n this.beforeSettleHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment settlement.\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onAfterSettle(hook: AfterSettleHook): x402ResourceServer {\n this.afterSettleHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment settlement fails.\n * Can recover from failure by returning { recovered: true, result: SettleResponse }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onSettleFailure(hook: OnSettleFailureHook): x402ResourceServer {\n this.onSettleFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Initialize by fetching supported kinds from all facilitators\n * Creates mappings for supported responses and facilitator clients\n * Earlier facilitators in the array get precedence\n */\n async initialize(): Promise<void> {\n // Clear existing mappings\n this.supportedResponsesMap.clear();\n this.facilitatorClientsMap.clear();\n let lastError: Error | undefined;\n\n // Fetch supported kinds from all facilitator clients\n // Process in order to give precedence to earlier facilitators\n for (const facilitatorClient of this.facilitatorClients) {\n try {\n const supported = await facilitatorClient.getSupported();\n\n // Process each supported kind (now flat array with version in each element)\n for (const kind of supported.kinds) {\n const x402Version = kind.x402Version;\n\n // Get or create version map for supported responses\n if (!this.supportedResponsesMap.has(x402Version)) {\n this.supportedResponsesMap.set(x402Version, new Map());\n }\n const responseVersionMap = this.supportedResponsesMap.get(x402Version)!;\n\n // Get or create version map for facilitator clients\n if (!this.facilitatorClientsMap.has(x402Version)) {\n this.facilitatorClientsMap.set(x402Version, new Map());\n }\n const clientVersionMap = this.facilitatorClientsMap.get(x402Version)!;\n\n // Get or create network map for responses\n if (!responseVersionMap.has(kind.network)) {\n responseVersionMap.set(kind.network, new Map());\n }\n const responseNetworkMap = responseVersionMap.get(kind.network)!;\n\n // Get or create network map for clients\n if (!clientVersionMap.has(kind.network)) {\n clientVersionMap.set(kind.network, new Map());\n }\n const clientNetworkMap = clientVersionMap.get(kind.network)!;\n\n // Only store if not already present (gives precedence to earlier facilitators)\n if (!responseNetworkMap.has(kind.scheme)) {\n responseNetworkMap.set(kind.scheme, supported);\n clientNetworkMap.set(kind.scheme, facilitatorClient);\n }\n }\n } catch (error) {\n lastError = error as Error;\n // Log error but continue with other facilitators\n console.warn(`Failed to fetch supported kinds from facilitator: ${error}`);\n }\n }\n\n if (this.supportedResponsesMap.size === 0) {\n throw lastError\n ? new Error(\n \"Failed to initialize: no supported payment kinds loaded from any facilitator.\",\n {\n cause: lastError,\n },\n )\n : new Error(\n \"Failed to initialize: no supported payment kinds loaded from any facilitator.\",\n );\n }\n }\n\n /**\n * Get supported kind for a specific version, network, and scheme\n *\n * @param x402Version - The x402 version\n * @param network - The network identifier\n * @param scheme - The payment scheme\n * @returns The supported kind or undefined if not found\n */\n getSupportedKind(\n x402Version: number,\n network: Network,\n scheme: string,\n ): SupportedKind | undefined {\n const versionMap = this.supportedResponsesMap.get(x402Version);\n if (!versionMap) return undefined;\n\n const supportedResponse = findByNetworkAndScheme(versionMap, scheme, network);\n if (!supportedResponse) return undefined;\n\n // Find the specific kind from the response (kinds are flat array with version in each element)\n return supportedResponse.kinds.find(\n kind =>\n kind.x402Version === x402Version && kind.network === network && kind.scheme === scheme,\n );\n }\n\n /**\n * Get facilitator extensions for a specific version, network, and scheme\n *\n * @param x402Version - The x402 version\n * @param network - The network identifier\n * @param scheme - The payment scheme\n * @returns The facilitator extensions or empty array if not found\n */\n getFacilitatorExtensions(x402Version: number, network: Network, scheme: string): string[] {\n const versionMap = this.supportedResponsesMap.get(x402Version);\n if (!versionMap) return [];\n\n const supportedResponse = findByNetworkAndScheme(versionMap, scheme, network);\n return supportedResponse?.extensions || [];\n }\n\n /**\n * Build payment requirements for a protected resource\n *\n * @param resourceConfig - Configuration for the protected resource\n * @returns Array of payment requirements\n */\n async buildPaymentRequirements(resourceConfig: ResourceConfig): Promise<PaymentRequirements[]> {\n const requirements: PaymentRequirements[] = [];\n\n // Find the matching server implementation\n const scheme = resourceConfig.scheme;\n const SchemeNetworkServer = findByNetworkAndScheme(\n this.registeredServerSchemes,\n scheme,\n resourceConfig.network,\n );\n\n if (!SchemeNetworkServer) {\n // Fallback to placeholder implementation if no server registered\n // TODO: Remove this fallback once implementations are registered\n console.warn(\n `No server implementation registered for scheme: ${scheme}, network: ${resourceConfig.network}`,\n );\n return requirements;\n }\n\n // Find the matching supported kind from facilitator\n const supportedKind = this.getSupportedKind(\n x402Version,\n resourceConfig.network,\n SchemeNetworkServer.scheme,\n );\n\n if (!supportedKind) {\n throw new Error(\n `Facilitator does not support ${SchemeNetworkServer.scheme} on ${resourceConfig.network}. ` +\n `Make sure to call initialize() to fetch supported kinds from facilitators.`,\n );\n }\n\n // Get facilitator extensions for this combination\n const facilitatorExtensions = this.getFacilitatorExtensions(\n x402Version,\n resourceConfig.network,\n SchemeNetworkServer.scheme,\n );\n\n // Parse the price using the scheme's price parser\n const parsedPrice = await SchemeNetworkServer.parsePrice(\n resourceConfig.price,\n resourceConfig.network,\n );\n\n // Build base payment requirements from resource config\n const baseRequirements: PaymentRequirements = {\n scheme: SchemeNetworkServer.scheme,\n network: resourceConfig.network,\n amount: parsedPrice.amount,\n asset: parsedPrice.asset,\n payTo: resourceConfig.payTo,\n maxTimeoutSeconds: resourceConfig.maxTimeoutSeconds || 300, // Default 5 minutes\n extra: {\n ...parsedPrice.extra,\n ...resourceConfig.extra, // Merge user-provided extra\n },\n };\n\n // Delegate to the implementation for scheme-specific enhancements\n // Note: enhancePaymentRequirements expects x402Version in the kind, so we add it back\n const requirement = await SchemeNetworkServer.enhancePaymentRequirements(\n baseRequirements,\n {\n ...supportedKind,\n x402Version,\n },\n facilitatorExtensions,\n );\n\n requirements.push(requirement);\n return requirements;\n }\n\n /**\n * Build payment requirements from multiple payment options\n * This method handles resolving dynamic payTo/price functions and builds requirements for each option\n *\n * @param paymentOptions - Array of payment options to convert\n * @param context - HTTP request context for resolving dynamic functions\n * @returns Array of payment requirements (one per option)\n */\n async buildPaymentRequirementsFromOptions<TContext = unknown>(\n paymentOptions: Array<{\n scheme: string;\n payTo: string | ((context: TContext) => string | Promise<string>);\n price: Price | ((context: TContext) => Price | Promise<Price>);\n network: Network;\n maxTimeoutSeconds?: number;\n extra?: Record<string, unknown>;\n }>,\n context: TContext,\n ): Promise<PaymentRequirements[]> {\n const allRequirements: PaymentRequirements[] = [];\n\n for (const option of paymentOptions) {\n // Resolve dynamic payTo and price if they are functions\n const resolvedPayTo =\n typeof option.payTo === \"function\" ? await option.payTo(context) : option.payTo;\n const resolvedPrice =\n typeof option.price === \"function\" ? await option.price(context) : option.price;\n\n const resourceConfig: ResourceConfig = {\n scheme: option.scheme,\n payTo: resolvedPayTo,\n price: resolvedPrice,\n network: option.network,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n extra: option.extra,\n };\n\n // Use existing buildPaymentRequirements for each option\n const requirements = await this.buildPaymentRequirements(resourceConfig);\n allRequirements.push(...requirements);\n }\n\n return allRequirements;\n }\n\n /**\n * Create a payment required response\n *\n * @param requirements - Payment requirements\n * @param resourceInfo - Resource information\n * @param error - Error message\n * @param extensions - Optional declared extensions (for per-key enrichment)\n * @param transportContext - Optional transport-specific context (e.g., HTTP request, MCP tool context)\n * @returns Payment required response object\n */\n async createPaymentRequiredResponse(\n requirements: PaymentRequirements[],\n resourceInfo: ResourceInfo,\n error?: string,\n extensions?: Record<string, unknown>,\n transportContext?: unknown,\n ): Promise<PaymentRequired> {\n // V2 response with resource at top level\n let response: PaymentRequired = {\n x402Version: 2,\n error,\n resource: resourceInfo,\n accepts: requirements as PaymentRequirements[],\n };\n\n // Add extensions if provided\n if (extensions && Object.keys(extensions).length > 0) {\n response.extensions = extensions;\n }\n\n // Let declared extensions add data to PaymentRequired response\n if (extensions) {\n for (const [key, declaration] of Object.entries(extensions)) {\n const extension = this.registeredExtensions.get(key);\n if (extension?.enrichPaymentRequiredResponse) {\n try {\n const context: PaymentRequiredContext = {\n requirements,\n resourceInfo,\n error,\n paymentRequiredResponse: response,\n transportContext,\n };\n const extensionData = await extension.enrichPaymentRequiredResponse(\n declaration,\n context,\n );\n if (extensionData !== undefined) {\n if (!response.extensions) {\n response.extensions = {};\n }\n response.extensions[key] = extensionData;\n }\n } catch (error) {\n console.error(\n `Error in enrichPaymentRequiredResponse hook for extension ${key}:`,\n error,\n );\n }\n }\n }\n }\n\n return response;\n }\n\n /**\n * Verify a payment against requirements\n *\n * @param paymentPayload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Verification response\n */\n async verifyPayment(\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const context: VerifyContext = {\n paymentPayload,\n requirements,\n };\n\n // Execute beforeVerify hooks\n for (const hook of this.beforeVerifyHooks) {\n try {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n return {\n isValid: false,\n invalidReason: result.reason,\n invalidMessage: result.message,\n };\n }\n } catch (error) {\n throw new VerifyError(400, {\n isValid: false,\n invalidReason: \"before_verify_hook_error\",\n invalidMessage: error instanceof Error ? error.message : \"\",\n });\n }\n }\n\n try {\n // Find the facilitator that supports this payment type\n const facilitatorClient = this.getFacilitatorClient(\n paymentPayload.x402Version,\n requirements.network,\n requirements.scheme,\n );\n\n let verifyResult: VerifyResponse;\n\n if (!facilitatorClient) {\n // Fallback: try all facilitators if no specific support found\n let lastError: Error | undefined;\n\n for (const client of this.facilitatorClients) {\n try {\n verifyResult = await client.verify(paymentPayload, requirements);\n break;\n } catch (error) {\n lastError = error as Error;\n }\n }\n\n if (!verifyResult!) {\n throw (\n lastError ||\n new Error(\n `No facilitator supports ${requirements.scheme} on ${requirements.network} for v${paymentPayload.x402Version}`,\n )\n );\n }\n } else {\n // Use the specific facilitator that supports this payment\n verifyResult = await facilitatorClient.verify(paymentPayload, requirements);\n }\n\n // Execute afterVerify hooks\n const resultContext: VerifyResultContext = {\n ...context,\n result: verifyResult,\n };\n\n for (const hook of this.afterVerifyHooks) {\n await hook(resultContext);\n }\n\n return verifyResult;\n } catch (error) {\n const failureContext: VerifyFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onVerifyFailure hooks\n for (const hook of this.onVerifyFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.result;\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Settle a verified payment\n *\n * @param paymentPayload - The payment payload to settle\n * @param requirements - The payment requirements\n * @param declaredExtensions - Optional declared extensions (for per-key enrichment)\n * @param transportContext - Optional transport-specific context (e.g., HTTP request/response, MCP tool context)\n * @param settlementOverrides - Optional overrides for settlement parameters (e.g., partial settlement amount)\n * @returns Settlement response\n */\n async settlePayment(\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n declaredExtensions?: Record<string, unknown>,\n transportContext?: unknown,\n settlementOverrides?: SettlementOverrides,\n ): Promise<SettleResponse> {\n // Apply settlement overrides (e.g., partial settlement for upto scheme)\n let effectiveRequirements = requirements;\n if (settlementOverrides?.amount !== undefined) {\n effectiveRequirements = {\n ...requirements,\n amount: resolveSettlementOverrideAmount(settlementOverrides.amount, requirements),\n };\n }\n\n const context: SettleContext = {\n paymentPayload,\n requirements: effectiveRequirements,\n };\n\n // Execute beforeSettle hooks\n for (const hook of this.beforeSettleHooks) {\n try {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n throw new SettleError(400, {\n success: false,\n errorReason: result.reason,\n errorMessage: result.message,\n transaction: \"\",\n network: requirements.network,\n });\n }\n } catch (error) {\n if (error instanceof SettleError) {\n throw error;\n }\n throw new SettleError(400, {\n success: false,\n errorReason: \"before_settle_hook_error\",\n errorMessage: error instanceof Error ? error.message : \"\",\n transaction: \"\",\n network: requirements.network,\n });\n }\n }\n\n try {\n // Find the facilitator that supports this payment type\n const facilitatorClient = this.getFacilitatorClient(\n paymentPayload.x402Version,\n effectiveRequirements.network,\n effectiveRequirements.scheme,\n );\n\n let settleResult: SettleResponse;\n\n if (!facilitatorClient) {\n // Fallback: try all facilitators if no specific support found\n let lastError: Error | undefined;\n\n for (const client of this.facilitatorClients) {\n try {\n settleResult = await client.settle(paymentPayload, effectiveRequirements);\n break;\n } catch (error) {\n lastError = error as Error;\n }\n }\n\n if (!settleResult!) {\n throw (\n lastError ||\n new Error(\n `No facilitator supports ${effectiveRequirements.scheme} on ${effectiveRequirements.network} for v${paymentPayload.x402Version}`,\n )\n );\n }\n } else {\n // Use the specific facilitator that supports this payment\n settleResult = await facilitatorClient.settle(paymentPayload, effectiveRequirements);\n }\n\n // Execute afterSettle hooks\n const resultContext: SettleResultContext = {\n ...context,\n result: settleResult,\n transportContext,\n };\n\n for (const hook of this.afterSettleHooks) {\n await hook(resultContext);\n }\n\n // Let declared extensions add data to settlement response\n if (declaredExtensions) {\n for (const [key, declaration] of Object.entries(declaredExtensions)) {\n const extension = this.registeredExtensions.get(key);\n if (extension?.enrichSettlementResponse) {\n try {\n const extensionData = await extension.enrichSettlementResponse(\n declaration,\n resultContext,\n );\n if (extensionData !== undefined) {\n if (!settleResult.extensions) {\n settleResult.extensions = {};\n }\n settleResult.extensions[key] = extensionData;\n }\n } catch (error) {\n console.error(`Error in enrichSettlementResponse hook for extension ${key}:`, error);\n }\n }\n }\n }\n\n return settleResult;\n } catch (error) {\n const failureContext: SettleFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onSettleFailure hooks\n for (const hook of this.onSettleFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.result;\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Find matching payment requirements for a payment\n *\n * @param availableRequirements - Array of available payment requirements\n * @param paymentPayload - The payment payload\n * @returns Matching payment requirements or undefined\n */\n findMatchingRequirements(\n availableRequirements: PaymentRequirements[],\n paymentPayload: PaymentPayload,\n ): PaymentRequirements | undefined {\n // Match by accepted requirements.\n // Per OKX spec, buyers may inject scheme-specific fields into accepted.extra\n // (e.g., sessionCert for aggr_deferred) that are not present in the server's\n // original PaymentRequirements. We use a superset check: all server-declared\n // fields must match, but accepted.extra may contain additional buyer fields.\n return availableRequirements.find(serverReq => {\n const { extra: serverExtra, ...serverBase } = serverReq;\n const { extra: buyerExtra, ...buyerBase } = paymentPayload.accepted ?? {};\n if (!deepEqual(serverBase, buyerBase)) return false;\n // Both have no extra — match\n if (!serverExtra && !buyerExtra) return true;\n // Server has no extra requirements — buyer may add whatever it wants\n if (!serverExtra) return true;\n // Server requires extra but buyer provided none — no match\n if (!buyerExtra) return false;\n // All server-required extra fields must match in buyer's accepted.extra\n for (const [key, value] of Object.entries(serverExtra)) {\n if (!deepEqual((buyerExtra as Record<string, unknown>)[key], value)) return false;\n }\n return true;\n });\n }\n\n /**\n * Process a payment request\n *\n * @param paymentPayload - Optional payment payload if provided\n * @param resourceConfig - Configuration for the protected resource\n * @param resourceInfo - Information about the resource being accessed\n * @param extensions - Optional extensions to include in the response\n * @returns Processing result\n */\n async processPaymentRequest(\n paymentPayload: PaymentPayload | null,\n resourceConfig: ResourceConfig,\n resourceInfo: ResourceInfo,\n extensions?: Record<string, unknown>,\n ): Promise<{\n success: boolean;\n requiresPayment?: PaymentRequired;\n verificationResult?: VerifyResponse;\n settlementResult?: SettleResponse;\n error?: string;\n }> {\n const requirements = await this.buildPaymentRequirements(resourceConfig);\n\n if (!paymentPayload) {\n return {\n success: false,\n requiresPayment: await this.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n \"Payment required\",\n extensions,\n ),\n };\n }\n\n // Find matching requirements\n const matchingRequirements = this.findMatchingRequirements(requirements, paymentPayload);\n if (!matchingRequirements) {\n return {\n success: false,\n requiresPayment: await this.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n \"No matching payment requirements found\",\n extensions,\n ),\n };\n }\n\n // Verify payment\n const verificationResult = await this.verifyPayment(paymentPayload, matchingRequirements);\n if (!verificationResult.isValid) {\n return {\n success: false,\n error: verificationResult.invalidReason,\n verificationResult,\n };\n }\n\n // Payment verified, ready for settlement\n return {\n success: true,\n verificationResult,\n };\n }\n\n /**\n * Poll `GET /settle/status` until a terminal state is reached or deadline expires.\n *\n * Used when settle returns `status=\"timeout\"` (exact + syncSettle=true).\n * Mirrors Rust: `X402ResourceServer::poll_settle_status`.\n *\n * @param txHash - Transaction hash to query\n * @param paymentPayload - The payment payload (used to find the correct facilitator client)\n * @param requirements - The payment requirements (used to find the correct facilitator client)\n * @param pollDeadlineMs - Max time to poll in ms (default 5000)\n * @returns Poll result: \"success\", \"failed\", or \"timeout\"\n */\n async pollSettleStatus(\n txHash: string,\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n pollDeadlineMs: number = DEFAULT_POLL_DEADLINE_MS,\n ): Promise<PollResult> {\n const facilitatorClient =\n this.getFacilitatorClient(\n paymentPayload.x402Version,\n requirements.network,\n requirements.scheme,\n ) ?? this.facilitatorClients[0];\n\n if (!facilitatorClient?.getSettleStatus) {\n return \"timeout\";\n }\n\n const deadline = Date.now() + pollDeadlineMs;\n\n while (Date.now() < deadline) {\n try {\n const resp: SettleStatusResponse = await facilitatorClient.getSettleStatus(txHash);\n if (!resp.success) {\n return \"failed\";\n }\n if (resp.status === \"success\") {\n return \"success\";\n }\n // status=\"pending\" or unknown → continue polling\n } catch {\n // API error → continue polling if still within deadline\n }\n\n // Wait before next poll, but don't exceed deadline\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await new Promise(resolve =>\n setTimeout(resolve, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)),\n );\n }\n return \"timeout\";\n }\n\n /**\n * Get facilitator client for a specific version, network, and scheme\n *\n * @param x402Version - The x402 version\n * @param network - The network identifier\n * @param scheme - The payment scheme\n * @returns The facilitator client or undefined if not found\n */\n private getFacilitatorClient(\n x402Version: number,\n network: Network,\n scheme: string,\n ): FacilitatorClient | undefined {\n const versionMap = this.facilitatorClientsMap.get(x402Version);\n if (!versionMap) return undefined;\n\n // Use findByNetworkAndScheme for pattern matching\n return findByNetworkAndScheme(versionMap, scheme, network);\n }\n}\n\nexport default x402ResourceServer;\n","import { x402ResourceServer, SettlementOverrides, DEFAULT_POLL_DEADLINE_MS } from \"../server\";\nimport {\n decodePaymentSignatureHeader,\n encodePaymentRequiredHeader,\n encodePaymentResponseHeader,\n} from \".\";\nimport {\n PaymentPayload,\n PaymentRequired,\n SettleResponse,\n SettleError,\n FacilitatorResponseError,\n Price,\n Network,\n PaymentRequirements,\n} from \"../types\";\nimport { x402Version } from \"..\";\n\nexport const SETTLEMENT_OVERRIDES_HEADER = \"settlement-overrides\";\n\n/**\n * Framework-agnostic HTTP adapter interface\n * Implementations provide framework-specific HTTP operations\n */\nexport interface HTTPAdapter {\n getHeader(name: string): string | undefined;\n getMethod(): string;\n getPath(): string;\n getUrl(): string;\n getAcceptHeader(): string;\n getUserAgent(): string;\n\n /**\n * Get query parameters from the request URL\n *\n * @returns Record of query parameter key-value pairs\n */\n getQueryParams?(): Record<string, string | string[]>;\n\n /**\n * Get a specific query parameter by name\n *\n * @param name - The query parameter name\n * @returns The query parameter value(s) or undefined\n */\n getQueryParam?(name: string): string | string[] | undefined;\n\n /**\n * Get the parsed request body\n * Framework adapters should parse JSON/form data appropriately\n *\n * @returns The parsed request body\n */\n getBody?(): unknown;\n}\n\n/**\n * Paywall configuration for HTML responses\n */\nexport interface PaywallConfig {\n appName?: string;\n appLogo?: string;\n sessionTokenEndpoint?: string;\n currentUrl?: string;\n testnet?: boolean;\n}\n\n/**\n * Paywall provider interface for generating HTML\n */\nexport interface PaywallProvider {\n generateHtml(paymentRequired: PaymentRequired, config?: PaywallConfig): string;\n}\n\n/**\n * Dynamic payTo function that receives HTTP request context\n */\nexport type DynamicPayTo = (context: HTTPRequestContext) => string | Promise<string>;\n\n/**\n * Dynamic price function that receives HTTP request context\n */\nexport type DynamicPrice = (context: HTTPRequestContext) => Price | Promise<Price>;\n\n/**\n * Result of response body callbacks containing content type and body.\n */\nexport interface HTTPResponseBody {\n /**\n * The content type for the response (e.g., 'application/json', 'text/plain').\n */\n contentType: string;\n\n /**\n * The response body to include in the 402 response.\n */\n body: unknown;\n}\n\n/**\n * Dynamic function to generate a custom response for unpaid requests.\n * Receives the HTTP request context and returns the content type and body to include in the 402 response.\n */\nexport type UnpaidResponseBody = (\n context: HTTPRequestContext,\n) => HTTPResponseBody | Promise<HTTPResponseBody>;\n\n/**\n * Dynamic function to generate a custom response for settlement failures.\n * Receives the HTTP request context and settle failure result, returns the content type and body.\n */\nexport type SettlementFailedResponseBody = (\n context: HTTPRequestContext,\n settleResult: Omit<ProcessSettleFailureResponse, \"response\">,\n) => HTTPResponseBody | Promise<HTTPResponseBody>;\n\n/**\n * A single payment option for a route\n * Represents one way a client can pay for access to the resource\n */\nexport interface PaymentOption {\n scheme: string;\n payTo: string | DynamicPayTo;\n price: Price | DynamicPrice;\n network: Network;\n maxTimeoutSeconds?: number;\n extra?: Record<string, unknown>;\n}\n\n/**\n * Route configuration for HTTP endpoints\n *\n * The 'accepts' field defines payment options for the route.\n * Can be a single PaymentOption or an array of PaymentOptions for multiple payment methods.\n */\nexport interface RouteConfig {\n // Payment option(s): single or array\n accepts: PaymentOption | PaymentOption[];\n\n // HTTP-specific metadata\n resource?: string;\n description?: string;\n mimeType?: string;\n customPaywallHtml?: string;\n\n /**\n * Optional callback to generate a custom response for unpaid API requests.\n * This allows servers to return preview data, error messages, or other content\n * when a request lacks payment.\n *\n * For browser requests (Accept: text/html), the paywall HTML takes precedence.\n * This callback is only used for API clients.\n *\n * If not provided, defaults to { contentType: 'application/json', body: {} }.\n *\n * @param context - The HTTP request context\n * @returns An object containing both contentType and body for the 402 response\n */\n unpaidResponseBody?: UnpaidResponseBody;\n\n /**\n * Optional callback to generate a custom response for settlement failures.\n * If not provided, defaults to { contentType: 'application/json', body: {} }.\n *\n * @param context - The HTTP request context\n * @param settleResult - The settlement failure result\n * @returns An object containing both contentType and body for the 402 response\n */\n settlementFailedResponseBody?: SettlementFailedResponseBody;\n\n // Extensions\n extensions?: Record<string, unknown>;\n}\n\n/**\n * Routes configuration - maps path patterns to route configs\n */\nexport type RoutesConfig = Record<string, RouteConfig> | RouteConfig;\n\n/**\n * Hook that runs on every request to a protected route, before payment processing.\n * Can grant access without payment, deny the request, or continue to payment flow.\n *\n * @returns\n * - `void` - Continue to payment processing (default behavior)\n * - `{ grantAccess: true }` - Grant access without requiring payment\n * - `{ abort: true; reason: string }` - Deny the request (returns 403)\n */\nexport type ProtectedRequestHook = (\n context: HTTPRequestContext,\n routeConfig: RouteConfig,\n) => Promise<void | { grantAccess: true } | { abort: true; reason: string }>;\n\n/**\n * Compiled route for efficient matching\n */\nexport interface CompiledRoute {\n verb: string;\n regex: RegExp;\n config: RouteConfig;\n pattern: string;\n}\n\n/**\n * HTTP request context that encapsulates all request data\n */\nexport interface HTTPRequestContext {\n adapter: HTTPAdapter;\n path: string;\n method: string;\n paymentHeader?: string;\n routePattern?: string;\n}\n\n/**\n * HTTP transport context contains both request context and optional response data.\n */\nexport interface HTTPTransportContext {\n /** The HTTP request context */\n request: HTTPRequestContext;\n /** The response body buffer */\n responseBody?: Buffer;\n /** Response headers set by the route handler (used for settlement overrides) */\n responseHeaders?: Record<string, string>;\n}\n\n/**\n * HTTP response instructions for the framework middleware\n */\nexport interface HTTPResponseInstructions {\n status: number;\n headers: Record<string, string>;\n body?: unknown; // e.g. Paywall for web browser requests, but could be any other type\n isHtml?: boolean; // e.g. if body is a paywall, then isHtml is true\n}\n\n/**\n * Result of processing an HTTP request for payment\n */\nexport type HTTPProcessResult =\n | { type: \"no-payment-required\" }\n | {\n type: \"payment-verified\";\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n declaredExtensions?: Record<string, unknown>;\n }\n | { type: \"payment-error\"; response: HTTPResponseInstructions };\n\n/**\n * Result of processSettlement\n */\nexport type ProcessSettleSuccessResponse = SettleResponse & {\n success: true;\n headers: Record<string, string>;\n requirements: PaymentRequirements;\n};\n\nexport type ProcessSettleFailureResponse = SettleResponse & {\n success: false;\n errorReason: string;\n errorMessage?: string;\n headers: Record<string, string>;\n response: HTTPResponseInstructions;\n};\n\nexport type ProcessSettleResultResponse =\n | ProcessSettleSuccessResponse\n | ProcessSettleFailureResponse;\n\n/**\n * Represents a validation error for a specific route's payment configuration.\n */\nexport interface RouteValidationError {\n /** The route pattern (e.g., \"GET /api/weather\") */\n routePattern: string;\n /** The payment scheme that failed validation */\n scheme: string;\n /** The network that failed validation */\n network: Network;\n /** The type of validation failure */\n reason: \"missing_scheme\" | \"missing_facilitator\";\n /** Human-readable error message */\n message: string;\n}\n\n/**\n * Error thrown when route configuration validation fails.\n */\nexport class RouteConfigurationError extends Error {\n /** The validation errors that caused this exception */\n public readonly errors: RouteValidationError[];\n\n /**\n * Creates a new RouteConfigurationError with the given validation errors.\n *\n * @param errors - The validation errors that caused this exception.\n */\n constructor(errors: RouteValidationError[]) {\n const message = `x402 Route Configuration Errors:\\n${errors.map(e => ` - ${e.message}`).join(\"\\n\")}`;\n super(message);\n this.name = \"RouteConfigurationError\";\n this.errors = errors;\n }\n}\n\n/**\n * Hook called when the facilitator returns status=\"timeout\".\n * Receives the tx hash and network so the server can verify on-chain.\n * Return { confirmed: true } to deliver the resource; { confirmed: false } to return 402.\n */\nexport type OnSettlementTimeoutHook = (\n txHash: string,\n network: string,\n) => Promise<{ confirmed: boolean }>;\n\n/**\n * HTTP-enhanced x402 resource server\n * Provides framework-agnostic HTTP protocol handling\n */\nexport class x402HTTPResourceServer {\n private ResourceServer: x402ResourceServer;\n private compiledRoutes: CompiledRoute[] = [];\n private routesConfig: RoutesConfig;\n private paywallProvider?: PaywallProvider;\n private protectedRequestHooks: ProtectedRequestHook[] = [];\n private timeoutRecoveryHook?: OnSettlementTimeoutHook;\n private pollDeadlineMs: number = DEFAULT_POLL_DEADLINE_MS;\n\n /**\n * Creates a new x402HTTPResourceServer instance.\n *\n * @param ResourceServer - The core x402ResourceServer instance to use\n * @param routes - Route configuration for payment-protected endpoints\n */\n constructor(ResourceServer: x402ResourceServer, routes: RoutesConfig) {\n this.ResourceServer = ResourceServer;\n this.routesConfig = routes;\n\n // Handle both single route and multiple routes\n const normalizedRoutes =\n typeof routes === \"object\" && !(\"accepts\" in routes)\n ? (routes as Record<string, RouteConfig>)\n : { \"*\": routes as RouteConfig };\n\n for (const [pattern, config] of Object.entries(normalizedRoutes)) {\n const parsed = this.parseRoutePattern(pattern);\n this.compiledRoutes.push({\n verb: parsed.verb,\n regex: parsed.regex,\n config,\n pattern: parsed.path,\n });\n }\n }\n\n /**\n * Get the underlying x402ResourceServer instance.\n *\n * @returns The underlying x402ResourceServer instance\n */\n get server(): x402ResourceServer {\n return this.ResourceServer;\n }\n\n /**\n * Get the routes configuration.\n *\n * @returns The routes configuration\n */\n get routes(): RoutesConfig {\n return this.routesConfig;\n }\n\n /**\n * Initialize the HTTP resource server.\n *\n * This method initializes the underlying resource server (fetching facilitator support)\n * and then validates that all route payment configurations have corresponding\n * registered schemes and facilitator support.\n *\n * @throws RouteConfigurationError if any route's payment options don't have\n * corresponding registered schemes or facilitator support\n *\n * @example\n * ```typescript\n * const httpServer = new x402HTTPResourceServer(server, routes);\n * await httpServer.initialize();\n * ```\n */\n async initialize(): Promise<void> {\n // First, initialize the underlying resource server (fetches facilitator support)\n await this.ResourceServer.initialize();\n\n // Then validate route configuration\n const errors = this.validateRouteConfiguration();\n if (errors.length > 0) {\n throw new RouteConfigurationError(errors);\n }\n }\n\n /**\n * Register a custom paywall provider for generating HTML\n *\n * @param provider - PaywallProvider instance\n * @returns This service instance for chaining\n */\n registerPaywallProvider(provider: PaywallProvider): this {\n this.paywallProvider = provider;\n return this;\n }\n\n /**\n * Register a hook that runs on every request to a protected route, before payment processing.\n * Hooks are executed in order of registration. The first hook to return a non-void result wins.\n *\n * @param hook - The request hook function\n * @returns The x402HTTPResourceServer instance for chaining\n */\n onProtectedRequest(hook: ProtectedRequestHook): this {\n this.protectedRequestHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to call when the facilitator returns status=\"timeout\".\n * The hook should verify the tx on-chain and return { confirmed: boolean }.\n * If confirmed=true the resource is delivered (200); otherwise 402 is returned.\n *\n * @param hook - On-chain verification callback\n * @returns The x402HTTPResourceServer instance for chaining\n */\n onSettlementTimeout(hook: OnSettlementTimeoutHook): this {\n this.timeoutRecoveryHook = hook;\n return this;\n }\n\n /**\n * Set the poll deadline for settle/status polling on timeout recovery.\n * Default is 5000ms.\n *\n * @param deadlineMs - Maximum time to poll in milliseconds\n * @returns The x402HTTPResourceServer instance for chaining\n */\n setPollDeadline(deadlineMs: number): this {\n this.pollDeadlineMs = deadlineMs;\n return this;\n }\n\n /**\n * Process HTTP request and return response instructions\n * This is the main entry point for framework middleware\n *\n * @param context - HTTP request context\n * @param paywallConfig - Optional paywall configuration\n * @returns Process result indicating next action for middleware\n */\n async processHTTPRequest(\n context: HTTPRequestContext,\n paywallConfig?: PaywallConfig,\n ): Promise<HTTPProcessResult> {\n const { adapter, path, method } = context;\n\n // Find matching route\n const routeMatch = this.getRouteConfig(path, method);\n if (!routeMatch) {\n return { type: \"no-payment-required\" }; // No payment required for this route\n }\n const { config: routeConfig, pattern: routePattern } = routeMatch;\n const enrichedContext: HTTPRequestContext = { ...context, routePattern };\n\n // Execute request hooks before any payment processing\n for (const hook of this.protectedRequestHooks) {\n const result = await hook(enrichedContext, routeConfig);\n if (result && \"grantAccess\" in result) {\n return { type: \"no-payment-required\" };\n }\n if (result && \"abort\" in result) {\n return {\n type: \"payment-error\",\n response: {\n status: 403,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: result.reason },\n },\n };\n }\n }\n\n // Normalize accepts field to array of payment options\n const paymentOptions = this.normalizePaymentOptions(routeConfig);\n\n // Check for payment header (v1 or v2)\n const paymentPayload = this.extractPayment(adapter);\n\n // Create resource info, using config override if provided\n const resourceInfo = {\n url: routeConfig.resource || enrichedContext.adapter.getUrl(),\n description: routeConfig.description || \"\",\n mimeType: routeConfig.mimeType || \"\",\n };\n\n // Build requirements from all payment options\n // (this method handles resolving dynamic functions internally)\n let requirements = await this.ResourceServer.buildPaymentRequirementsFromOptions(\n paymentOptions,\n enrichedContext,\n );\n\n let extensions = routeConfig.extensions;\n if (extensions) {\n extensions = this.ResourceServer.enrichExtensions(extensions, enrichedContext);\n }\n\n // createPaymentRequiredResponse already handles extension enrichment in the core layer\n const transportContext: HTTPTransportContext = { request: enrichedContext };\n const paymentRequired = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n !paymentPayload ? \"Payment required\" : undefined,\n extensions,\n transportContext,\n );\n\n // If no payment provided\n if (!paymentPayload) {\n // Resolve custom unpaid response body if provided\n const unpaidBody = routeConfig.unpaidResponseBody\n ? await routeConfig.unpaidResponseBody(enrichedContext)\n : undefined;\n\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(\n paymentRequired,\n this.isWebBrowser(adapter),\n paywallConfig,\n routeConfig.customPaywallHtml,\n unpaidBody,\n ),\n };\n }\n\n // Verify payment\n try {\n const matchingRequirements = this.ResourceServer.findMatchingRequirements(\n paymentRequired.accepts,\n paymentPayload,\n );\n\n if (!matchingRequirements) {\n const errorResponse = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n \"No matching payment requirements\",\n routeConfig.extensions,\n transportContext,\n );\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(errorResponse, false, paywallConfig),\n };\n }\n\n const verifyResult = await this.ResourceServer.verifyPayment(\n paymentPayload,\n matchingRequirements,\n );\n\n if (!verifyResult.isValid) {\n const errorResponse = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n verifyResult.invalidReason,\n routeConfig.extensions,\n transportContext,\n );\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(errorResponse, false, paywallConfig),\n };\n }\n\n // Payment is valid, return data needed for settlement\n return {\n type: \"payment-verified\",\n paymentPayload,\n paymentRequirements: matchingRequirements,\n declaredExtensions: routeConfig.extensions,\n };\n } catch (error) {\n if (error instanceof FacilitatorResponseError) {\n throw error;\n }\n const errorResponse = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n error instanceof Error ? error.message : \"Payment verification failed\",\n routeConfig.extensions,\n transportContext,\n );\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(errorResponse, false, paywallConfig),\n };\n }\n }\n\n /**\n * Process settlement after successful response\n *\n * @param paymentPayload - The verified payment payload\n * @param requirements - The matching payment requirements\n * @param declaredExtensions - Optional declared extensions (for per-key enrichment)\n * @param transportContext - Optional HTTP transport context\n * @param settlementOverrides - Optional settlement overrides (e.g., partial settlement amount)\n * @returns ProcessSettleResultResponse - SettleResponse with headers if success or errorReason if failure\n */\n async processSettlement(\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n declaredExtensions?: Record<string, unknown>,\n transportContext?: HTTPTransportContext,\n settlementOverrides?: SettlementOverrides,\n ): Promise<ProcessSettleResultResponse> {\n try {\n // Resolve overrides: explicit param takes precedence, fall back to response header\n let resolvedOverrides = settlementOverrides;\n if (!resolvedOverrides && transportContext?.responseHeaders?.[SETTLEMENT_OVERRIDES_HEADER]) {\n try {\n resolvedOverrides = JSON.parse(\n transportContext.responseHeaders[SETTLEMENT_OVERRIDES_HEADER],\n );\n } catch {\n // Ignore malformed header\n }\n }\n\n const settleResponse = await this.ResourceServer.settlePayment(\n paymentPayload,\n requirements,\n declaredExtensions,\n transportContext,\n resolvedOverrides,\n );\n\n // status=\"timeout\" → facilitator gave up waiting for on-chain confirmation.\n // Step 1: Poll /settle/status (interval 1s, deadline from config).\n // Step 2: If polling fails/times out, try developer's timeout hook.\n if (settleResponse.status === \"timeout\") {\n if (settleResponse.transaction) {\n // Step 1: Poll settle/status\n const pollResult = await this.ResourceServer.pollSettleStatus(\n settleResponse.transaction,\n paymentPayload,\n requirements,\n this.pollDeadlineMs,\n );\n\n if (pollResult === \"success\") {\n // Poll confirmed on-chain → deliver resource\n const recovered = { ...settleResponse, status: \"success\" as const };\n return {\n ...recovered,\n success: true as const,\n headers: this.createSettlementHeaders(recovered),\n requirements,\n };\n }\n\n // Step 2: Poll unsuccessful → try developer's timeout hook\n if (this.timeoutRecoveryHook) {\n try {\n const { confirmed } = await this.timeoutRecoveryHook(\n settleResponse.transaction,\n settleResponse.network as string,\n );\n if (confirmed) {\n const recovered = { ...settleResponse, status: \"success\" as const };\n return {\n ...recovered,\n success: true as const,\n headers: this.createSettlementHeaders(recovered),\n requirements,\n };\n }\n } catch (err) {\n console.warn(\"[x402] onSettlementTimeout hook error:\", err);\n }\n }\n }\n\n // No transaction, or poll+hook both failed → 402\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason: \"settlement_timeout\",\n errorMessage: \"Settlement timed out waiting for on-chain confirmation\",\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n\n // status=\"success\" → on-chain confirmed (syncSettle=true), deliver resource\n // status=\"pending\" → async mode, Seller trusts Facilitator, deliver resource\n // no status → standard okx facilitator, check success field\n if (settleResponse.status === \"success\" || settleResponse.status === \"pending\") {\n return {\n ...settleResponse,\n success: true as const,\n headers: this.createSettlementHeaders(settleResponse),\n requirements,\n };\n }\n\n // Fallback: standard okx facilitator (no status field)\n if (!settleResponse.success) {\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason: settleResponse.errorReason || \"Settlement failed\",\n errorMessage:\n settleResponse.errorMessage || settleResponse.errorReason || \"Settlement failed\",\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n\n return {\n ...settleResponse,\n success: true,\n headers: this.createSettlementHeaders(settleResponse),\n requirements,\n };\n } catch (error) {\n if (error instanceof FacilitatorResponseError) {\n throw error;\n }\n if (error instanceof SettleError) {\n const errorReason = error.errorReason || error.message;\n const settleResponse: SettleResponse = {\n success: false,\n errorReason,\n errorMessage: error.errorMessage || errorReason,\n payer: error.payer,\n network: error.network,\n transaction: error.transaction,\n };\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason,\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n const errorReason = error instanceof Error ? error.message : \"Settlement failed\";\n const settleResponse: SettleResponse = {\n success: false,\n errorReason,\n errorMessage: errorReason,\n network: requirements.network as Network,\n transaction: \"\",\n };\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason,\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n }\n\n /**\n * Check if a request requires payment based on route configuration\n *\n * @param context - HTTP request context\n * @returns True if the route requires payment, false otherwise\n */\n requiresPayment(context: HTTPRequestContext): boolean {\n return this.getRouteConfig(context.path, context.method) !== undefined;\n }\n\n /**\n * Build HTTPResponseInstructions for settlement failure.\n * Uses settlementFailedResponseBody hook if configured, otherwise defaults to empty body.\n *\n * @param failure - Settlement failure result with headers\n * @param transportContext - Optional HTTP transport context for the request\n * @returns HTTP response instructions for the 402 settlement failure response\n */\n private async buildSettlementFailureResponse(\n failure: Omit<ProcessSettleFailureResponse, \"response\">,\n transportContext?: HTTPTransportContext,\n ): Promise<HTTPResponseInstructions> {\n const settlementHeaders = failure.headers;\n const routeConfig = transportContext\n ? this.getRouteConfig(transportContext.request.path, transportContext.request.method)\n : undefined;\n\n const customBody = routeConfig?.config.settlementFailedResponseBody\n ? await routeConfig.config.settlementFailedResponseBody(transportContext!.request, failure)\n : undefined;\n\n const contentType = customBody ? customBody.contentType : \"application/json\";\n const body = customBody ? customBody.body : {};\n\n return {\n status: 402,\n headers: {\n \"Content-Type\": contentType,\n ...settlementHeaders,\n },\n body,\n isHtml: contentType.includes(\"text/html\"),\n };\n }\n\n /**\n * Normalizes a RouteConfig's accepts field into an array of PaymentOptions\n * Handles both single PaymentOption and array formats\n *\n * @param routeConfig - Route configuration\n * @returns Array of payment options\n */\n private normalizePaymentOptions(routeConfig: RouteConfig): PaymentOption[] {\n return Array.isArray(routeConfig.accepts) ? routeConfig.accepts : [routeConfig.accepts];\n }\n\n /**\n * Validates that all payment options in routes have corresponding registered schemes\n * and facilitator support.\n *\n * @returns Array of validation errors (empty if all routes are valid)\n */\n private validateRouteConfiguration(): RouteValidationError[] {\n const errors: RouteValidationError[] = [];\n\n // Normalize routes to array of [pattern, config] pairs\n const normalizedRoutes =\n typeof this.routesConfig === \"object\" && !(\"accepts\" in this.routesConfig)\n ? Object.entries(this.routesConfig as Record<string, RouteConfig>)\n : [[\"*\", this.routesConfig as RouteConfig] as [string, RouteConfig]];\n\n for (const [pattern, config] of normalizedRoutes) {\n // Warn if wildcard routes are used with discovery extensions\n const pathPart = pattern.includes(\" \") ? pattern.split(/\\s+/)[1] : pattern;\n if (\n pathPart &&\n pathPart.includes(\"*\") &&\n config.extensions &&\n \"bazaar\" in config.extensions\n ) {\n console.warn(\n `[x402] Route \"${pattern}\": Wildcard (*) patterns with bazaar discovery extensions ` +\n `will auto-generate parameter names (var1, var2, ...). ` +\n `Consider using named parameters instead (e.g. /weather/:city) for better discovery metadata.`,\n );\n }\n\n const paymentOptions = this.normalizePaymentOptions(config);\n\n for (const option of paymentOptions) {\n // Check 1: Is scheme registered?\n if (!this.ResourceServer.hasRegisteredScheme(option.network, option.scheme)) {\n errors.push({\n routePattern: pattern,\n scheme: option.scheme,\n network: option.network,\n reason: \"missing_scheme\",\n message: `Route \"${pattern}\": No scheme implementation registered for \"${option.scheme}\" on network \"${option.network}\"`,\n });\n // Skip facilitator check if scheme isn't registered\n continue;\n }\n\n // Check 2: Does facilitator support this scheme/network combination?\n const supportedKind = this.ResourceServer.getSupportedKind(\n x402Version,\n option.network,\n option.scheme,\n );\n\n if (!supportedKind) {\n errors.push({\n routePattern: pattern,\n scheme: option.scheme,\n network: option.network,\n reason: \"missing_facilitator\",\n message: `Route \"${pattern}\": Facilitator does not support scheme \"${option.scheme}\" on network \"${option.network}\"`,\n });\n }\n }\n }\n\n return errors;\n }\n\n /**\n * Get route configuration for a request\n *\n * @param path - Request path\n * @param method - HTTP method\n * @returns Route configuration and pattern, or undefined if no match\n */\n private getRouteConfig(\n path: string,\n method: string,\n ): { config: RouteConfig; pattern: string } | undefined {\n const normalizedPath = this.normalizePath(path);\n const upperMethod = method.toUpperCase();\n\n const matchingRoute = this.compiledRoutes.find(\n route =>\n route.regex.test(normalizedPath) && (route.verb === \"*\" || route.verb === upperMethod),\n );\n\n if (!matchingRoute) return undefined;\n return { config: matchingRoute.config, pattern: matchingRoute.pattern };\n }\n\n /**\n * Extract payment from HTTP headers (handles v1 and v2)\n *\n * @param adapter - HTTP adapter\n * @returns Decoded payment payload or null\n */\n private extractPayment(adapter: HTTPAdapter): PaymentPayload | null {\n // Check v2 header first (PAYMENT-SIGNATURE)\n const header = adapter.getHeader(\"payment-signature\") || adapter.getHeader(\"PAYMENT-SIGNATURE\");\n\n if (header) {\n try {\n return decodePaymentSignatureHeader(header);\n } catch (error) {\n console.warn(\"Failed to decode PAYMENT-SIGNATURE header:\", error);\n }\n }\n\n return null;\n }\n\n /**\n * Check if request is from a web browser\n *\n * @param adapter - HTTP adapter\n * @returns True if request appears to be from a browser\n */\n private isWebBrowser(adapter: HTTPAdapter): boolean {\n const accept = adapter.getAcceptHeader();\n const userAgent = adapter.getUserAgent();\n return accept.includes(\"text/html\") && userAgent.includes(\"Mozilla\");\n }\n\n /**\n * Create HTTP response instructions from payment required\n *\n * @param paymentRequired - Payment requirements\n * @param isWebBrowser - Whether request is from browser\n * @param paywallConfig - Paywall configuration\n * @param customHtml - Custom HTML template\n * @param unpaidResponse - Optional custom response (content type and body) for unpaid API requests\n * @returns Response instructions\n */\n private createHTTPResponse(\n paymentRequired: PaymentRequired,\n isWebBrowser: boolean,\n paywallConfig?: PaywallConfig,\n customHtml?: string,\n unpaidResponse?: HTTPResponseBody,\n ): HTTPResponseInstructions {\n // Use 412 Precondition Failed for permit2_allowance_required error\n // This signals client needs to approve Permit2 before retrying\n const status = paymentRequired.error === \"permit2_allowance_required\" ? 412 : 402;\n\n if (isWebBrowser) {\n const html = this.generatePaywallHTML(paymentRequired, paywallConfig, customHtml);\n return {\n status,\n headers: { \"Content-Type\": \"text/html\" },\n body: html,\n isHtml: true,\n };\n }\n\n const response = this.createHTTPPaymentRequiredResponse(paymentRequired);\n\n // Use callback result if provided, otherwise default to JSON with empty object\n const contentType = unpaidResponse ? unpaidResponse.contentType : \"application/json\";\n const body = unpaidResponse ? unpaidResponse.body : {};\n\n return {\n status,\n headers: {\n \"Content-Type\": contentType,\n ...response.headers,\n },\n body,\n };\n }\n\n /**\n * Create HTTP payment required response (v1 puts in body, v2 puts in header)\n *\n * @param paymentRequired - Payment required object\n * @returns Headers and body for the HTTP response\n */\n private createHTTPPaymentRequiredResponse(paymentRequired: PaymentRequired): {\n headers: Record<string, string>;\n } {\n return {\n headers: {\n \"PAYMENT-REQUIRED\": encodePaymentRequiredHeader(paymentRequired),\n },\n };\n }\n\n /**\n * Create settlement response headers\n *\n * @param settleResponse - Settlement response\n * @returns Headers to add to response\n */\n private createSettlementHeaders(settleResponse: SettleResponse): Record<string, string> {\n const encoded = encodePaymentResponseHeader(settleResponse);\n return { \"PAYMENT-RESPONSE\": encoded };\n }\n\n /**\n * Parse route pattern into verb and regex\n *\n * @param pattern - Route pattern like \"GET /api/*\", \"/api/[id]\", or \"/api/:id\"\n * @returns Parsed pattern with verb and regex\n */\n private parseRoutePattern(pattern: string): { verb: string; regex: RegExp; path: string } {\n const [verb, path] = pattern.includes(\" \") ? pattern.split(/\\s+/) : [\"*\", pattern];\n\n const regex = new RegExp(\n `^${\n path\n .replace(/[$()+.?^{|}]/g, \"\\\\$&\") // Escape regex special chars\n .replace(/\\*/g, \".*?\") // Wildcards\n .replace(/\\[([^\\]]+)\\]/g, \"[^/]+\") // Parameters (Next.js style [param])\n .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, \"[^/]+\") // Parameters (Express style :param)\n .replace(/\\//g, \"\\\\/\") // Escape slashes\n }$`,\n \"i\",\n );\n\n return { verb: verb.toUpperCase(), regex, path };\n }\n\n /**\n * Normalize path for matching\n *\n * @param path - Raw path from request\n * @returns Normalized path\n */\n private normalizePath(path: string): string {\n const pathWithoutQuery = path.split(/[?#]/)[0];\n\n let decodedOrRawPath: string;\n try {\n decodedOrRawPath = decodeURIComponent(pathWithoutQuery);\n } catch {\n decodedOrRawPath = pathWithoutQuery;\n }\n\n return decodedOrRawPath\n .replace(/\\\\/g, \"/\")\n .replace(/\\/+/g, \"/\")\n .replace(/(.+?)\\/+$/, \"$1\");\n }\n\n /**\n * Generate paywall HTML for browser requests\n *\n * @param paymentRequired - Payment required response\n * @param paywallConfig - Optional paywall configuration\n * @param customHtml - Optional custom HTML template\n * @returns HTML string\n */\n private generatePaywallHTML(\n paymentRequired: PaymentRequired,\n paywallConfig?: PaywallConfig,\n customHtml?: string,\n ): string {\n if (customHtml) {\n return customHtml;\n }\n\n // Use custom paywall provider if set\n if (this.paywallProvider) {\n return this.paywallProvider.generateHtml(paymentRequired, paywallConfig);\n }\n\n // Fallback: Basic HTML paywall\n const resource = paymentRequired.resource;\n const displayAmount = this.getDisplayAmount(paymentRequired);\n\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>Payment Required</title>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body>\n <div style=\"max-width: 600px; margin: 50px auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;\">\n ${paywallConfig?.appLogo ? `<img src=\"${paywallConfig.appLogo}\" alt=\"${paywallConfig.appName || \"App\"}\" style=\"max-width: 200px; margin-bottom: 20px;\">` : \"\"}\n <h1>Payment Required</h1>\n ${resource ? `<p><strong>Resource:</strong> ${resource.description || resource.url}</p>` : \"\"}\n <p><strong>Amount:</strong> $${displayAmount.toFixed(2)} USDC</p>\n <div id=\"payment-widget\" \n data-requirements='${JSON.stringify(paymentRequired)}'\n data-app-name=\"${paywallConfig?.appName || \"\"}\"\n data-testnet=\"${paywallConfig?.testnet || false}\">\n </div>\n </div>\n </body>\n </html>\n `;\n }\n\n /**\n * Extract display amount from payment requirements.\n *\n * @param paymentRequired - The payment required object\n * @returns The display amount in decimal format\n */\n private getDisplayAmount(paymentRequired: PaymentRequired): number {\n const accepts = paymentRequired.accepts;\n if (accepts && accepts.length > 0) {\n const firstReq = accepts[0];\n if (\"amount\" in firstReq) {\n // V2 format\n return parseFloat(firstReq.amount) / 1000000; // Assuming USDC with 6 decimals\n }\n }\n return 0;\n }\n}\n","import {\n decodePaymentRequiredHeader,\n decodePaymentResponseHeader,\n encodePaymentSignatureHeader,\n} from \".\";\nimport { SettleResponse } from \"../types\";\nimport { PaymentPayload, PaymentRequired } from \"../types/payments\";\nimport { x402Client } from \"../client/x402Client\";\n\n/**\n * Context provided to onPaymentRequired hooks.\n */\nexport interface PaymentRequiredContext {\n paymentRequired: PaymentRequired;\n}\n\n/**\n * Hook called when a 402 response is received, before payment processing.\n * Return headers to try before payment, or void to proceed directly to payment.\n */\nexport type PaymentRequiredHook = (\n context: PaymentRequiredContext,\n) => Promise<{ headers: Record<string, string> } | void>;\n\n/**\n * HTTP-specific client for handling x402 payment protocol over HTTP.\n *\n * Wraps a x402Client to provide HTTP-specific encoding/decoding functionality\n * for payment headers and responses while maintaining the builder pattern.\n */\nexport class x402HTTPClient {\n private paymentRequiredHooks: PaymentRequiredHook[] = [];\n\n /**\n * Creates a new x402HTTPClient instance.\n *\n * @param client - The underlying x402Client for payment logic\n */\n constructor(private readonly client: x402Client) {}\n\n /**\n * Register a hook to handle 402 responses before payment.\n * Hooks run in order; first to return headers wins.\n *\n * @param hook - The hook function to register\n * @returns This instance for chaining\n */\n onPaymentRequired(hook: PaymentRequiredHook): this {\n this.paymentRequiredHooks.push(hook);\n return this;\n }\n\n /**\n * Run hooks and return headers if any hook provides them.\n *\n * @param paymentRequired - The payment required response from the server\n * @returns Headers to use for retry, or null to proceed to payment\n */\n async handlePaymentRequired(\n paymentRequired: PaymentRequired,\n ): Promise<Record<string, string> | null> {\n for (const hook of this.paymentRequiredHooks) {\n const result = await hook({ paymentRequired });\n if (result?.headers) {\n return result.headers;\n }\n }\n return null;\n }\n\n /**\n * Encodes a payment payload into appropriate HTTP headers based on version.\n *\n * @param paymentPayload - The payment payload to encode\n * @returns HTTP headers containing the encoded payment signature\n */\n encodePaymentSignatureHeader(paymentPayload: PaymentPayload): Record<string, string> {\n return {\n \"PAYMENT-SIGNATURE\": encodePaymentSignatureHeader(paymentPayload),\n };\n }\n\n /**\n * Extracts payment required information from HTTP response.\n *\n * @param getHeader - Function to retrieve header value by name (case-insensitive)\n * @returns The payment required object\n */\n getPaymentRequiredResponse(\n getHeader: (name: string) => string | null | undefined,\n ): PaymentRequired {\n const paymentRequired = getHeader(\"PAYMENT-REQUIRED\");\n if (paymentRequired) {\n return decodePaymentRequiredHeader(paymentRequired);\n }\n\n throw new Error(\"Invalid payment required response\");\n }\n\n /**\n * Extracts payment settlement response from HTTP headers.\n *\n * @param getHeader - Function to retrieve header value by name (case-insensitive)\n * @returns The settlement response object\n */\n getPaymentSettleResponse(getHeader: (name: string) => string | null | undefined): SettleResponse {\n const paymentResponse = getHeader(\"PAYMENT-RESPONSE\");\n if (paymentResponse) {\n return decodePaymentResponseHeader(paymentResponse);\n }\n\n throw new Error(\"Payment response header not found\");\n }\n\n /**\n * Creates a payment payload for the given payment requirements.\n * Delegates to the underlying x402Client.\n *\n * @param paymentRequired - The payment required response from the server\n * @returns Promise resolving to the payment payload\n */\n async createPaymentPayload(paymentRequired: PaymentRequired): Promise<PaymentPayload> {\n return this.client.createPaymentPayload(paymentRequired);\n }\n}\n"],"mappings":"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","names":["import_zod","errorReason","settleResponse","failure","response"]}
1
+ {"version":3,"sources":["../../../src/subscription/codec/typed-data.ts","../../../src/subscription/codec/base64.ts","../../../src/subscription/codec/payload.ts","../../../src/subscription/types.ts","../../../src/subscription/errors.ts","../../../src/subscription/store.ts","../../../src/subscription/client.ts","../../../src/subscription/codec/verify-terms.ts","../../../src/subscription/codec/period-math.ts","../../../src/subscription/codec/access-proof.ts","../../../src/subscription/codec/index.ts","../../../src/subscription/facilitator-client.ts","../../../src/subscription/index.ts","../../../src/http/index.ts","../../../src/utils/index.ts","../../../src/types/facilitator.ts","../../../src/http/httpFacilitatorClient.ts","../../../src/schemas/index.ts","../../../src/facilitator/OKXFacilitatorClient.ts","../../../src/index.ts","../../../src/server/x402ResourceServer.ts","../../../src/http/x402HTTPResourceServer.ts","../../../src/http/x402HTTPClient.ts"],"sourcesContent":["import { encodeAbiParameters, keccak256, type Hex, type TypedDataDomain } from \"viem\";\n\nimport type { PaymentRequirements } from \"../../types/payments\";\nimport type { CancelInitiator, PlanInitialCharge } from \"../types\";\nimport type { PermitSingleData, SubscriptionTerms } from \"./payload\";\n\n/** 32-byte zero hash, used as the sentinel for empty bytes32 fields. */\nexport const ZERO_BYTES32: Hex = `0x${\"0\".repeat(64)}`;\n\n/**\n * Permit2 PermitSingle (AllowanceTransfer) EIP-712 schema. Used for the\n * continuous-pull authorization signed by the buyer. The Permit2 domain has\n * NO `version` field — only `name=\"Permit2\"`, `chainId`, `verifyingContract`.\n */\nexport const PERMIT2_TYPES = {\n PermitSingle: [\n { name: \"details\", type: \"PermitDetails\" },\n { name: \"spender\", type: \"address\" },\n { name: \"sigDeadline\", type: \"uint256\" },\n ],\n PermitDetails: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint160\" },\n { name: \"expiration\", type: \"uint48\" },\n { name: \"nonce\", type: \"uint48\" },\n ],\n} as const;\n\n/**\n * SubscriptionTerms EIP-712 schema. 17 fields; field ORDER + integer widths\n * must mirror the contract. TypeHash:\n * 0xa5223de56e7694cf776c7d4f74c0323f42bf9e65655fe49affefbdfd40ec97ae\n * (verify against contract `SUBSCRIPTION_TERMS_TYPEHASH()`)\n */\nexport const SUBSCRIPTION_TERMS_TYPES = {\n SubscriptionTerms: [\n { name: \"payer\", type: \"address\" },\n { name: \"merchant\", type: \"address\" },\n { name: \"facilitator\", type: \"address\" },\n { name: \"token\", type: \"address\" },\n { name: \"amountPerPeriod\", type: \"uint160\" },\n { name: \"periodSec\", type: \"uint64\" },\n { name: \"maxPeriods\", type: \"uint32\" },\n { name: \"startAt\", type: \"uint64\" },\n { name: \"initialChargePeriods\", type: \"uint32\" },\n { name: \"initialChargeAmount\", type: \"uint160\" },\n { name: \"termsDeadline\", type: \"uint64\" },\n { name: \"permitHash\", type: \"bytes32\" },\n { name: \"salt\", type: \"bytes32\" },\n { name: \"planTier\", type: \"uint8\" },\n { name: \"changeFromSubId\", type: \"bytes32\" },\n { name: \"changeEffectiveAt\", type: \"uint8\" },\n { name: \"periodMode\", type: \"uint8\" },\n ],\n} as const;\n\n/**\n * CancelAuth EIP-712 schema (subscription contract domain):\n * `CancelAuth(uint8 action, bytes32 subId, uint8 initiator, bytes32 nonce, uint64 deadline)`\n */\nexport const CANCEL_AUTH_TYPES = {\n CancelAuth: [\n { name: \"action\", type: \"uint8\" },\n { name: \"subId\", type: \"bytes32\" },\n { name: \"initiator\", type: \"uint8\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"deadline\", type: \"uint64\" },\n ],\n} as const;\n\n/**\n * PendingChangeCancelAuth EIP-712 schema (subscription contract domain):\n * `PendingChangeCancelAuth(bytes32 subId, bytes32 newSubId, bytes32 nonce, uint64 deadline)`\n */\nexport const PENDING_CHANGE_CANCEL_AUTH_TYPES = {\n PendingChangeCancelAuth: [\n { name: \"subId\", type: \"bytes32\" },\n { name: \"newSubId\", type: \"bytes32\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"deadline\", type: \"uint64\" },\n ],\n} as const;\n\nexport interface SubscriptionPlanExtra {\n id: string;\n tier: number;\n name?: string;\n}\n\n/**\n * Buyer's intent to switch from `fromSubId` to a new plan. Present on\n * PaymentRequirements.extra ONLY when the requirements are a change offer\n * for an upgrade/downgrade.\n */\nexport interface ChangeFromExtra {\n fromSubId: Hex;\n fromPlanId: Hex;\n fromPlanTier: number;\n direction: \"upgrade\" | \"downgrade\";\n effectiveAt: \"immediate\" | \"period_end\";\n}\n\nexport interface SubscriptionContractAddresses {\n subscription: string;\n permit2: string;\n}\n\n/**\n * Typed view of the `extra` field on subscription PaymentRequirements. The\n * evm scheme is responsible for producing PaymentRequirements whose `extra`\n * matches this shape; codec helpers consume it via this type rather than\n * Record<string, unknown> to keep field access type-safe.\n *\n * Index signature lets this be assigned directly to\n * `PaymentRequirements.extra: Record<string, unknown>` without a cast.\n */\nexport interface SubscriptionRequirementsExtra {\n contracts: SubscriptionContractAddresses;\n facilitator: string;\n amountPerPeriod: string;\n periodSec: number;\n /** uint8 — 0 fixed_seconds (default) / 1 calendar_month. */\n periodMode?: number;\n maxPeriods: number;\n startAt?: number;\n initialCharge?: PlanInitialCharge | null;\n plan: SubscriptionPlanExtra;\n changeFrom?: ChangeFromExtra;\n domain: TypedDataDomain;\n [key: string]: unknown;\n}\n\nexport interface TypedDataEnvelope<TPrimary extends string, TMessage> {\n domain: TypedDataDomain;\n types: Record<string, ReadonlyArray<{ name: string; type: string }>>;\n primaryType: TPrimary;\n message: TMessage;\n}\n\nexport interface BuildPermit2TypedDataInput {\n /** PaymentRequirements with subscription `extra`. */\n selected: PaymentRequirements;\n /** uint48 — current nonce from allowance-status (NOT +1). */\n nonce: number;\n /** uint48 unix seconds — Permit2 allowance expiration. */\n expiration: number;\n /** uint256 decimal — outer signature expiry. */\n sigDeadline: string;\n /** Override amount; default = initialChargeAmount + (maxPeriods - initialChargePeriods) * amountPerPeriod. */\n amount?: string;\n}\n\nexport interface BuildSubscriptionTermsTypedDataInput {\n selected: PaymentRequirements;\n payer: string;\n startAt: number;\n /** uint64 unix seconds — terms signature validity. */\n termsDeadline: number;\n /** bytes32 — random anti-replay; reuse the same hex string ≤ once. */\n salt: Hex;\n /** bytes32 — keccak256 of the PermitSingle struct hash; bind permit. */\n permitHash: Hex;\n changeFrom?: ChangeFromExtra;\n /** Override domain for special cases; defaults to `selected.extra.domain`. */\n domain?: TypedDataDomain;\n}\n\nexport interface BuildCancelAuthTypedDataInput {\n subId: Hex;\n initiator: CancelInitiator;\n /** uint64 unix seconds. */\n deadline: number;\n /** bytes32. */\n nonce: Hex;\n domain: TypedDataDomain;\n}\n\nexport interface BuildPendingChangeCancelAuthTypedDataInput {\n subId: Hex;\n /** The pending change's target newSubId — must match `pendingPlanChange.newSubId`. */\n newSubId: Hex;\n deadline: number;\n nonce: Hex;\n domain: TypedDataDomain;\n}\n\nconst CANCEL_INITIATOR_TO_ENUM: Record<CancelInitiator, 0 | 1> = {\n payer: 0,\n merchant: 1,\n};\n\nfunction getSubscriptionExtra(req: PaymentRequirements): SubscriptionRequirementsExtra {\n const extra = req.extra as Partial<SubscriptionRequirementsExtra> | undefined;\n if (!extra || !extra.contracts || !extra.plan || !extra.domain) {\n throw new Error(\n \"subscription codec: PaymentRequirements.extra is missing contracts/plan/domain\",\n );\n }\n return extra as SubscriptionRequirementsExtra;\n}\n\n/**\n * Default permit.amount:\n * amount ≥ reservedAmount + newCommit\n * newCommit = initialChargeAmount + (maxPeriods - initialChargePeriods) * amountPerPeriod\n *\n * `reservedAmount` (existing on-chain commitments) is NOT included here —\n * Buyer SDK should add it on top from `allowance-status.reservedAmount` if a\n * concurrent sub already holds budget against the same (payer, token).\n */\nfunction defaultPermitAmount(extra: SubscriptionRequirementsExtra): string {\n const initialChargePeriods = BigInt(extra.initialCharge?.periodCount ?? 0);\n const initialChargeAmount = BigInt(extra.initialCharge?.totalAmount ?? \"0\");\n const remainingPeriods = BigInt(extra.maxPeriods) - initialChargePeriods;\n const remainingAmount =\n remainingPeriods > 0n ? remainingPeriods * BigInt(extra.amountPerPeriod) : 0n;\n return (initialChargeAmount + remainingAmount).toString();\n}\n\n/**\n * Build the Permit2 PermitSingle (AllowanceTransfer) typed data the wallet\n * signs. `spender = subscription contract`; `amount` covers the entire\n * remaining commitment (default), so the subscription contract can pull from\n * the same Permit2 allowance on every charge without re-signing.\n *\n * Permit2's EIP-712 domain has NO `version` field.\n */\nexport function buildPermit2TypedData(\n input: BuildPermit2TypedDataInput,\n): TypedDataEnvelope<\"PermitSingle\", Record<string, unknown>> {\n const extra = getSubscriptionExtra(input.selected);\n const amount = input.amount ?? defaultPermitAmount(extra);\n const chainId = parseChainIdFromNetwork(input.selected.network);\n\n return {\n domain: {\n name: \"Permit2\",\n chainId,\n verifyingContract: extra.contracts.permit2 as Hex,\n },\n types: PERMIT2_TYPES as unknown as TypedDataEnvelope<\n \"PermitSingle\",\n Record<string, unknown>\n >[\"types\"],\n primaryType: \"PermitSingle\",\n message: {\n details: {\n token: input.selected.asset,\n amount,\n expiration: input.expiration,\n nonce: input.nonce,\n },\n spender: extra.contracts.subscription,\n sigDeadline: input.sigDeadline,\n },\n };\n}\n\n/**\n * Compute the EIP-712 struct hash of a PermitSingle message — what\n * `terms.permitHash` must equal byte-for-byte. The facilitator verifies this\n * via `permit_hash_mismatch`.\n *\n * permitDetailsHash = keccak256(\n * PERMIT_DETAILS_TYPEHASH ‖ token ‖ amount ‖ expiration ‖ nonce\n * )\n * permitSingleHash = keccak256(\n * PERMIT_SINGLE_TYPEHASH ‖ permitDetailsHash ‖ spender ‖ sigDeadline\n * )\n */\nexport function computePermitSingleStructHash(permit: PermitSingleData): Hex {\n // PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\n const PERMIT_DETAILS_TYPEHASH = keccak256(\n new TextEncoder().encode(\n \"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\",\n ),\n );\n const detailsHash = keccak256(\n encodeAbiParameters(\n [\n { type: \"bytes32\" },\n { type: \"address\" },\n { type: \"uint160\" },\n { type: \"uint48\" },\n { type: \"uint48\" },\n ],\n [\n PERMIT_DETAILS_TYPEHASH,\n permit.details.token as Hex,\n BigInt(permit.details.amount),\n Number(permit.details.expiration),\n Number(permit.details.nonce),\n ],\n ),\n );\n\n // PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(...)\n const PERMIT_SINGLE_TYPEHASH = keccak256(\n new TextEncoder().encode(\n \"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)\" +\n \"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)\",\n ),\n );\n return keccak256(\n encodeAbiParameters(\n [{ type: \"bytes32\" }, { type: \"bytes32\" }, { type: \"address\" }, { type: \"uint256\" }],\n [PERMIT_SINGLE_TYPEHASH, detailsHash, permit.spender as Hex, BigInt(permit.sigDeadline)],\n ),\n );\n}\n\n/**\n * Build the EIP-712 typed-data object the wallet signs to commit to the\n * subscription terms (17 fields). `permitHash` MUST be the struct hash of\n * the PermitSingle the buyer signed for permit2 (compute it via\n * `computePermitSingleStructHash`) — the contract verifies this binding to\n * defeat detached-signature swap attacks.\n */\nexport function buildSubscriptionTermsTypedData(\n input: BuildSubscriptionTermsTypedDataInput,\n): TypedDataEnvelope<\"SubscriptionTerms\", SubscriptionTerms> {\n const extra = getSubscriptionExtra(input.selected);\n const domain = input.domain ?? extra.domain;\n\n // changeEffectiveAt: 0=none(create), 1=immediate(upgrade), 2=period_end(downgrade)\n let changeEffectiveAt = 0;\n if (input.changeFrom?.effectiveAt === \"immediate\") changeEffectiveAt = 1;\n else if (input.changeFrom?.effectiveAt === \"period_end\") changeEffectiveAt = 2;\n\n const message: SubscriptionTerms = {\n payer: input.payer,\n merchant: input.selected.payTo,\n facilitator: extra.facilitator,\n token: input.selected.asset,\n amountPerPeriod: extra.amountPerPeriod,\n periodSec: extra.periodSec,\n maxPeriods: extra.maxPeriods,\n startAt: input.startAt,\n initialChargePeriods: extra.initialCharge?.periodCount ?? 0,\n initialChargeAmount: extra.initialCharge?.totalAmount ?? \"0\",\n termsDeadline: input.termsDeadline,\n permitHash: input.permitHash,\n salt: input.salt,\n planTier: extra.plan.tier,\n changeFromSubId: input.changeFrom?.fromSubId ?? ZERO_BYTES32,\n changeEffectiveAt,\n periodMode: extra.periodMode ?? 0,\n };\n\n return {\n domain,\n types: SUBSCRIPTION_TERMS_TYPES as unknown as TypedDataEnvelope<\n \"SubscriptionTerms\",\n SubscriptionTerms\n >[\"types\"],\n primaryType: \"SubscriptionTerms\",\n message,\n };\n}\n\nexport function buildCancelAuthTypedData(\n input: BuildCancelAuthTypedDataInput,\n): TypedDataEnvelope<\"CancelAuth\", Record<string, unknown>> {\n return {\n domain: input.domain,\n types: CANCEL_AUTH_TYPES as unknown as TypedDataEnvelope<\n \"CancelAuth\",\n Record<string, unknown>\n >[\"types\"],\n primaryType: \"CancelAuth\",\n message: {\n action: 0,\n subId: input.subId,\n initiator: CANCEL_INITIATOR_TO_ENUM[input.initiator],\n nonce: input.nonce,\n deadline: input.deadline,\n },\n };\n}\n\nexport function buildPendingChangeCancelAuthTypedData(\n input: BuildPendingChangeCancelAuthTypedDataInput,\n): TypedDataEnvelope<\"PendingChangeCancelAuth\", Record<string, unknown>> {\n return {\n domain: input.domain,\n types: PENDING_CHANGE_CANCEL_AUTH_TYPES as unknown as TypedDataEnvelope<\n \"PendingChangeCancelAuth\",\n Record<string, unknown>\n >[\"types\"],\n primaryType: \"PendingChangeCancelAuth\",\n message: {\n subId: input.subId,\n newSubId: input.newSubId,\n nonce: input.nonce,\n deadline: input.deadline,\n },\n };\n}\n\n/**\n * Parse the chainId from a CAIP-2 network identifier (`eip155:<chainId>`).\n * Throws if not an EVM CAIP — the subscription scheme is EVM-only.\n */\nexport function parseChainIdFromNetwork(network: string): number {\n const parts = network.split(\":\");\n if (parts.length !== 2 || parts[0] !== \"eip155\") {\n throw new Error(`parseChainIdFromNetwork: expected \"eip155:<chainId>\", got \"${network}\"`);\n }\n const id = Number(parts[1]);\n if (!Number.isInteger(id) || id <= 0) {\n throw new Error(`parseChainIdFromNetwork: invalid chainId \"${parts[1]}\"`);\n }\n return id;\n}\n","/**\n * Isomorphic UTF-8 ↔ base64 helpers.\n *\n * Buyers may run this code in a browser; Buffer is preferred on Node so the\n * built CJS bundle stays free of `globalThis.atob` polyfills, but we fall back\n * to atob/btoa when Buffer is unavailable.\n */\n\nconst hasBuffer = typeof Buffer !== \"undefined\";\n\nexport function base64EncodeUtf8(value: string): string {\n if (hasBuffer) return Buffer.from(value, \"utf8\").toString(\"base64\");\n const binary = unescape(encodeURIComponent(value));\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (globalThis as any).btoa(binary);\n}\n\nexport function base64DecodeUtf8(value: string): string {\n if (hasBuffer) return Buffer.from(value, \"base64\").toString(\"utf8\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const binary: string = (globalThis as any).atob(value);\n return decodeURIComponent(escape(binary));\n}\n","import type { Hex } from \"viem\";\n\nimport type { PaymentPayload, PaymentRequired, PaymentRequirements } from \"../../types/payments\";\nimport { base64DecodeUtf8, base64EncodeUtf8 } from \"./base64\";\n\n/**\n * Permit2 PermitSingle (AllowanceTransfer) — what the buyer signs to authorize\n * the subscription contract to pull tokens on every charge.\n *\n * PermitSingle(PermitDetails details, address spender, uint256 sigDeadline)\n * PermitDetails(address token, uint160 amount, uint48 expiration, uint48 nonce)\n */\nexport interface PermitSingleData {\n details: {\n token: string;\n /** uint160 as decimal string — covers entire remaining commitment. */\n amount: string;\n /** uint48 unix seconds — Permit2 allowance expiration. */\n expiration: number;\n /** uint48 — Permit2 nonce (current value from allowance-status, NOT +1). */\n nonce: number;\n };\n /** Subscription contract address. */\n spender: string;\n /** uint256 as decimal string — outer signature expiry. */\n sigDeadline: string;\n}\n\n/**\n * SubscriptionTerms — what the buyer's EIP-712 signature commits to. 17\n * fields. Field ORDER MATTERS because it determines the EIP-712 TypeHash:\n * 0xa5223de56e7694cf776c7d4f74c0323f42bf9e65655fe49affefbdfd40ec97ae\n */\nexport interface SubscriptionTerms {\n payer: string;\n merchant: string;\n facilitator: string;\n token: string;\n /** uint160 (atomic units). */\n amountPerPeriod: string;\n /** uint64 seconds; MUST be 0 when periodMode=1 (calendar_month). */\n periodSec: number;\n /** uint32. */\n maxPeriods: number;\n /** uint64 unix seconds; 0 means \"use block.timestamp on-chain\". */\n startAt: number;\n /** uint32; 0 = no separate initial charge. */\n initialChargePeriods: number;\n /** uint160; atomic units. */\n initialChargeAmount: string;\n /** uint64 unix seconds — terms signature validity window. */\n termsDeadline: number;\n /** bytes32 — keccak256 of the PermitSingle EIP-712 struct hash, binds terms to permit. */\n permitHash: Hex;\n /** bytes32 — buyer-generated random anti-replay value. */\n salt: Hex;\n /** uint8 (>0) — plan tier for upgrade/downgrade comparison. */\n planTier: number;\n /** bytes32 — old subId on change, zero on create. */\n changeFromSubId: Hex;\n /** uint8 — 0 none(create) / 1 immediate(upgrade) / 2 period_end(downgrade). */\n changeEffectiveAt: number;\n /** uint8 — 0 fixed_seconds / 1 calendar_month. */\n periodMode: number;\n /**\n * bytes32 — keccak256(utf8(plan.id)). Buyer SDKs sign it as a terms field\n * and the facilitator persists it as the on-chain `planId`. Seller verify\n * MUST cross-check this hash equals `keccak256(utf8(accepted.extra.plan.id))`\n * to defeat plan-spoof attacks.\n */\n planId?: Hex;\n}\n\n/**\n * Concrete payload nested inside `PaymentPayload.payload` for the `period`\n * scheme.\n */\nexport interface SubscriptionPaymentInner {\n permitSingle: PermitSingleData;\n permitSingleSignature: Hex;\n terms: SubscriptionTerms;\n termsSignature: Hex;\n}\n\nexport interface EncodePaymentPayloadInput {\n selected: PaymentRequirements;\n permitSingle: PermitSingleData;\n permitSingleSignature: Hex;\n terms: SubscriptionTerms;\n termsSignature: Hex;\n}\n\n/**\n * Decode the `APP-PAYMENT-REQUIRED` header into the underlying\n * `PaymentRequired.accepts` array. Throws on invalid base64 / JSON.\n */\nexport function parsePaymentRequired(headerValue: string): PaymentRequirements[] {\n const json = base64DecodeUtf8(headerValue);\n const parsed = JSON.parse(json) as PaymentRequired;\n if (!parsed || !Array.isArray(parsed.accepts)) {\n throw new Error(\"parsePaymentRequired: missing or invalid `accepts` array\");\n }\n return parsed.accepts;\n}\n\n/**\n * Build the `PAYMENT-SIGNATURE` header value (base64-encoded JSON). Buyer side.\n */\nexport function encodePaymentPayload(input: EncodePaymentPayloadInput): string {\n const payload: PaymentPayload = {\n x402Version: 2,\n accepted: input.selected,\n payload: {\n permitSingle: input.permitSingle,\n permitSingleSignature: input.permitSingleSignature,\n terms: input.terms,\n termsSignature: input.termsSignature,\n },\n };\n return base64EncodeUtf8(JSON.stringify(payload));\n}\n\n/**\n * Decode the `PAYMENT-SIGNATURE` header value back into a typed PaymentPayload.\n * Throws on invalid base64 / JSON; does not validate field shapes (that is the\n * responsibility of the scheme verify step).\n */\nexport function decodePaymentPayload(headerValue: string): PaymentPayload {\n const json = base64DecodeUtf8(headerValue);\n return JSON.parse(json) as PaymentPayload;\n}\n\n/**\n * Narrow a generic PaymentPayload's `.payload` to the subscription inner.\n * Throws if required fields are missing — single chokepoint between base64\n * decode and verify.\n */\nexport function asSubscriptionPaymentInner(payload: PaymentPayload): SubscriptionPaymentInner {\n const inner = payload.payload as Partial<SubscriptionPaymentInner>;\n if (\n !inner ||\n !inner.permitSingle ||\n !inner.terms ||\n !inner.permitSingleSignature ||\n !inner.termsSignature\n ) {\n throw new Error(\n \"asSubscriptionPaymentInner: payload.payload is missing required permitSingle/terms fields\",\n );\n }\n return inner as SubscriptionPaymentInner;\n}\n","import type { PaymentPayload, PaymentRequirements } from \"../types/payments\";\n\n/**\n * Subscription state: `active`, `canceled`, `completed`, `changed`.\n */\n/**\n * Local mirror of facilitator's SubscriptionState enum. Numeric mapping:\n * 0 pending / 1 active / 2 completed / 3 canceled / 4 changed / 99 failed\n */\nexport type SubscriptionState =\n | \"pending\"\n | \"active\"\n | \"completed\"\n | \"canceled\"\n | \"changed\"\n | \"failed\";\n\n/**\n * Set on an ACTIVE sub when a downgrade has been scheduled but not yet\n * activated. `state` lets the seller observe the terminal disposition\n * (PENDING / ACTIVATED / CANCELED / EXPIRED) via GET /pending.\n */\nexport interface PendingPlanChange {\n subId: string;\n newSubId: string;\n effectiveFromPeriod: number;\n /** 0 pending / 1 activated / 2 canceled / 3 expired. */\n state: number;\n}\n\n/**\n * Seller-side projection of a subscription. All fields come from the\n * facilitator GET /subscriptions/detail endpoint; the store never holds\n * data the facilitator can't refresh.\n *\n * Snapshot fields (`isActive` / `serviceEnded` / `currentPeriod` /\n * `elapsedPeriods` / `nextChargeableAt`) are valid as of the last sync\n * only; they drift with wall-clock time.\n */\nexport interface Subscription {\n subId: string;\n payer: string;\n merchant: string;\n token: string;\n amountPerPeriod: string;\n /** 0 fixed_seconds / 1 calendar_month. */\n periodMode: number;\n periodSec: number;\n /** Calendar-month billing anchor (Unix s). Undefined or 0 in fixed_seconds mode. */\n billingAnchorAt?: number;\n maxPeriods: number;\n startAt: number;\n state: SubscriptionState;\n lastChargedPeriod: number;\n totalPulled: string;\n planId: string;\n planTier: number;\n changedToSubId?: string;\n pendingPlanChange?: PendingPlanChange;\n /** Derived snapshot — true iff state==ACTIVE && now < endAt. */\n isActive?: boolean;\n /** Derived snapshot — true iff state==ACTIVE && !isActive (expired, not yet finalized). */\n serviceEnded?: boolean;\n /** Derived snapshot — current period number, clamped to maxPeriods. */\n currentPeriod?: number;\n /** Derived snapshot — real elapsed period count, NOT clamped (use this for expiry checks). */\n elapsedPeriods?: number;\n /** Derived snapshot — next chargeable boundary (Unix s); null when all periods are charged. */\n nextChargeableAt?: number;\n}\n\nexport interface AccessProof {\n kind: \"subscription-id\";\n subId: string;\n payer: string;\n timestamp: number;\n signature: string;\n}\n\n/**\n * `CancelAuth.initiator` enum — only payer / merchant.\n */\nexport type CancelInitiator = \"payer\" | \"merchant\";\n\n/**\n * EIP-712 `CancelAuth` payload (subscription contract domain):\n * `CancelAuth(uint8 action, bytes32 subId, uint8 initiator, bytes32 nonce, uint64 deadline)`\n *\n * `action` is locked to `0 = cancel_subscription`. `cancel_pending_change`\n * uses the standalone `cancel-pending-change` endpoint with its own\n * `PendingChangeCancelAuth` signature.\n */\nexport interface CancelAuth {\n action: 0;\n subId: string;\n initiator: 0 | 1;\n nonce: string;\n deadline: number;\n signature: string;\n}\n\n/**\n * EIP-712 `PendingChangeCancelAuth` payload (subscription contract domain).\n * Payer-only.\n *\n * TypeHash:\n * keccak256(\"PendingChangeCancelAuth(bytes32 subId,bytes32 newSubId,bytes32 nonce,uint64 deadline)\")\n *\n * `newSubId` MUST equal the currently-PENDING `pendingPlanChange.newSubId`\n * (the to-be-cancelled downgrade target); facilitator rejects with\n * `pending_cancel_target_mismatch` otherwise.\n */\nexport interface PendingChangeCancelAuth {\n subId: string;\n newSubId: string;\n nonce: string;\n deadline: number;\n signature: string;\n}\n\nexport interface PlanInitialCharge {\n periodCount: number;\n totalAmount: string;\n}\n\nexport interface PlanCatalogEntry {\n id: string;\n tier: number;\n amountPerPeriod: string;\n /** 0 fixed_seconds (default) / 1 calendar_month. */\n periodMode?: 0 | 1;\n periodSec: number;\n maxPeriods: number;\n /**\n * ERC-20 token address. Optional — if omitted, the EVM scheme fills from\n * `getDefaultAsset(network)` (same per-network map exact / upto /\n * aggr_deferred consume).\n */\n asset?: string;\n payTo: string;\n initialCharge?: PlanInitialCharge;\n name?: string;\n}\n\nexport type PlanCatalog = Record<string, PlanCatalogEntry>;\n\nexport interface AccessRouteRequirements {\n /**\n * PlanIds that satisfy this route. Derived from the route's `accepts`\n * payment options (`accepts[].extra.plan.id`). A subscription is allowed\n * access iff its `planId` appears in this list.\n *\n * `undefined` means \"no plan restriction\" — any active subscription on\n * the route passes (use sparingly).\n */\n acceptedPlanIds?: string[];\n\n /**\n * Full `PaymentRequirements` for every plan the route accepts — the same\n * list the seller declared as `RouteConfig.accepts`, resolved to wire\n * format. Each entry carries the plan metadata in `extra.plan`\n * (`{ id, tier, name }`) plus `extra.amountPerPeriod`, `extra.periodSec`,\n * `extra.periodMode`, `extra.maxPeriods`, etc. — everything an\n * `onBeforeAccess` hook needs to decide policy against catalog details\n * (upgrade offers, tier ceilings, per-plan feature flags) without joining\n * an external catalog table.\n */\n accepts?: PaymentRequirements[];\n}\n\n/**\n * Context passed to `OnBeforeAccessHook`. Carries the full stored\n * `Subscription` (so the seller can inspect any field — payer, planId,\n * lastChargedPeriod, changedToSubId, etc. — for arbitrary policy) plus\n * the incoming HTTP request shape and route metadata.\n */\nexport interface OnBeforeAccessContext {\n subscription: Subscription;\n request: {\n path: string;\n method: string;\n headers: Record<string, string>;\n };\n route: AccessRouteRequirements;\n}\n\n/**\n * Result of an `OnBeforeAccessHook`:\n * - `{ ok: true }` → allow the request through\n * - `{ ok: false }` → deny; `error` shows up in the 402 body, `retryAfter`\n * (seconds) becomes a `Retry-After` header hint, `upgradeOffers` lets\n * the seller point the buyer at an alternate plan\n *\n * Denial use cases: rate-limiting, quota exhaustion, bans / blacklists,\n * per-plan feature gating beyond the simple `acceptedPlanIds` allowlist.\n */\nexport type OnBeforeAccessResult =\n | { ok: true }\n | {\n ok: false;\n error?: string;\n retryAfter?: number;\n upgradeOffers?: PaymentRequirements[];\n };\n\n/**\n * Route-level hook fired AFTER `verifyAccess` succeeded (signature +\n * payer + plan-allowlist + period math) but BEFORE the handler runs.\n * The seller uses it to implement custom access policy — e.g. a ban list\n * keyed by subId or payer, per-plan feature flags, or dynamic quota.\n */\nexport type OnBeforeAccessHook = (ctx: OnBeforeAccessContext) => Promise<OnBeforeAccessResult>;\n\nexport type VerifyResultOk = { ok: true };\nexport type VerifyResultFail = { ok: false; error: string };\nexport type VerifyResult = VerifyResultOk | VerifyResultFail;\n\nexport interface VerifyChangeOk {\n ok: true;\n oldSubId: string;\n direction: \"upgrade\" | \"downgrade\";\n}\nexport type VerifyChangeResult = VerifyChangeOk | VerifyResultFail;\n\nexport interface VerifyAccessOk {\n ok: true;\n subscription: Subscription;\n}\nexport type VerifyAccessResult = VerifyAccessOk | VerifyResultFail;\n\n/**\n * Result of `verifyOwnership` — used by the change-route sniff path to\n * confirm the AccessProof signer owns the named subscription, without\n * imposing the plan-allowlist / period-math gating that `verifyAccess`\n * applies for resource consumption.\n */\nexport interface VerifyOwnershipOk {\n ok: true;\n subId: string;\n payer: string;\n subscription: Subscription;\n}\nexport type VerifyOwnershipResult = VerifyOwnershipOk | VerifyResultFail;\n\nexport type SettleResultFail = {\n success: false;\n error: string;\n /**\n * Set when the chain operation may still complete asynchronously: the\n * facilitator accepted the write call but returned `state=pending`, and the\n * SDK's client-side polling (5×1s) timed out before settlement. Seller\n * should remember `subId` and call `syncFromChain(subId)` later.\n */\n subId?: string;\n pending?: boolean;\n};\n\nexport interface SettleSubscribeOk {\n success: true;\n subId: string;\n subscription: Subscription;\n headers: Record<string, string>;\n}\nexport type SettleSubscribeResult = SettleSubscribeOk | SettleResultFail;\n\nexport interface SettleChangeOk {\n success: true;\n oldSubId: string;\n newSubId: string;\n operationType: \"upgrade\" | \"downgrade\";\n scheduledFromPeriod?: number;\n headers: Record<string, string>;\n}\nexport type SettleChangeResult = SettleChangeOk | SettleResultFail;\n\nexport interface SettleCancelOk {\n success: true;\n subId: string;\n headers: Record<string, string>;\n}\nexport type SettleCancelResult = SettleCancelOk | SettleResultFail;\n\n/**\n * Result of `settleCancelPendingChange` — cancels a scheduled downgrade\n * (removes `pendingPlanChange` on the old sub while the sub itself stays\n * ACTIVE). No refund, no state transition on the sub itself.\n */\nexport interface SettleCancelPendingChangeOk {\n success: true;\n subId: string;\n headers: Record<string, string>;\n}\nexport type SettleCancelPendingChangeResult = SettleCancelPendingChangeOk | SettleResultFail;\n\nexport interface ChargeResult {\n success: true;\n period: number;\n amount: string;\n txHash?: string;\n planChangeTriggered?: boolean;\n newSubId?: string;\n}\n\nexport interface SubscriptionCapability {\n readonly settlementMode: \"pre\";\n\n verifySubscribe(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResult>;\n\n settleSubscribe(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleSubscribeResult>;\n\n /**\n * Inject `extra.changeFrom = { fromSubId, fromPlanId, fromPlanTier,\n * direction, effectiveAt }` into each accept of a change route's 402\n * accepts. Direction / effectiveAt are derived per-accept by comparing\n * `accept.extra.plan.tier` against the stored `oldSub.planTier`. Same-tier\n * accepts are dropped (a change to the same tier is illegal —\n * `tier_same`).\n *\n * Returns `null` when the seller's local store has no record of\n * `currentSubId` — middleware then 404s the GET so buyers see the misuse.\n */\n enrichAcceptsForChange(\n accepts: PaymentRequirements[],\n currentSubId: string,\n ): Promise<PaymentRequirements[] | null>;\n\n verifyChange(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyChangeResult>;\n\n settleChange(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleChangeResult>;\n\n verifyCancel(auth: CancelAuth, subId: string): Promise<VerifyResult>;\n\n settleCancel(auth: CancelAuth, subId: string): Promise<SettleCancelResult>;\n\n /**\n * Verify a `PendingChangeCancelAuth` before facilitator submission.\n * Requires `auth.subId == body.subId` and `auth.newSubId` equal to the\n * currently PENDING `pendingPlanChange.newSubId` — the SDK checks the\n * former; facilitator enforces the latter as\n * `pending_cancel_target_mismatch`.\n */\n verifyCancelPendingChange(auth: PendingChangeCancelAuth, subId: string): Promise<VerifyResult>;\n\n /**\n * Cancel a scheduled downgrade (`pendingPlanChange`) — the current sub\n * stays ACTIVE, only the pending row is retired. Facilitator returns the\n * new state; SDK re-pulls GET /detail to refresh the store entry.\n */\n settleCancelPendingChange(\n auth: PendingChangeCancelAuth,\n subId: string,\n ): Promise<SettleCancelPendingChangeResult>;\n\n verifyAccess(proof: AccessProof, route: AccessRouteRequirements): Promise<VerifyAccessResult>;\n\n /**\n * Lightweight ownership check for the change-route sniff path. Verifies\n * the AccessProof signature, looks up the sub in the store, and confirms\n * `sub.payer == proof.payer`. Deliberately does NOT enforce plan\n * allowlist or period math — the caller is identifying themselves to\n * receive change offers, not consuming a protected resource.\n */\n verifyOwnership(proof: AccessProof): Promise<VerifyOwnershipResult>;\n\n charge(subId: string): Promise<ChargeResult>;\n\n getSubscription(subId: string): Promise<Subscription | null>;\n}\n\nexport function hasSubscriptionCapability(scheme: unknown): scheme is SubscriptionCapability {\n return (\n typeof scheme === \"object\" &&\n scheme !== null &&\n \"verifyAccess\" in scheme &&\n \"settlementMode\" in scheme &&\n (scheme as { settlementMode: unknown }).settlementMode === \"pre\"\n );\n}\n","/**\n * Canonical facilitator error reasons. The SDK uses these literal strings\n * verbatim in verify / settle / charge return values so seller code can\n * switch on a single set of codes regardless of whether the rejection\n * originated in the SDK pre-check or in the facilitator response.\n */\nexport const ErrorCode = {\n // subscribe / change\n TermsBindingInvalid: \"terms_binding_invalid\",\n AllowanceInsufficient: \"allowance_insufficient\",\n AllowanceExpired: \"allowance_expired\",\n // charge\n PeriodNotDue: \"period_not_due\",\n InsufficientBalance: \"insufficient_balance\",\n // charge / cancel / access\n SubscriptionNotActive: \"subscription_not_active\",\n /**\n * SDK-local code. Surfaced by `verifyAccess` when local period math\n * yields `currentCalculatePeriod === 0` — subscription exists but\n * `nowSec < startAt`, i.e. has not yet entered its first chargeable\n * period.\n */\n SubscriptionNotYetActive: \"subscription_not_yet_active\",\n UnauthorizedCaller: \"unauthorized_caller\",\n // cancel\n CancelSignatureInvalid: \"cancel_signature_invalid\",\n CancelNonceUsed: \"cancel_nonce_used\",\n // change\n TierSame: \"tier_same\",\n ChangeEffectiveAtMismatch: \"change_effective_at_mismatch\",\n MerchantMismatch: \"merchant_mismatch\",\n PayerMismatch: \"payer_mismatch\",\n PendingChangeExists: \"pending_change_exists\",\n SubNotActiveForChange: \"sub_not_active_for_change\",\n // cancel-pending-change\n NoPendingChange: \"no_pending_change\",\n // all writes\n ConfirmationTimeout: \"confirmation_timeout\",\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n/**\n * Charge-flow subset of ErrorCode. Seller scheduler switches on these 6\n * codes.\n */\nexport const ChargeErrorCode = {\n PeriodNotDue: ErrorCode.PeriodNotDue,\n SubscriptionNotActive: ErrorCode.SubscriptionNotActive,\n InsufficientBalance: ErrorCode.InsufficientBalance,\n AllowanceExpired: ErrorCode.AllowanceExpired,\n UnauthorizedCaller: ErrorCode.UnauthorizedCaller,\n ConfirmationTimeout: ErrorCode.ConfirmationTimeout,\n} as const;\n\nexport type ChargeErrorCode = (typeof ChargeErrorCode)[keyof typeof ChargeErrorCode];\n\nexport class ChargeError extends Error {\n public readonly code: ChargeErrorCode;\n public readonly subId: string;\n public readonly txHash?: string;\n\n constructor(code: ChargeErrorCode, subId: string, txHash?: string) {\n super(`charge failed: ${code} (sub=${subId})`);\n this.name = \"ChargeError\";\n this.code = code;\n this.subId = subId;\n this.txHash = txHash;\n }\n}\n","import type { Subscription } from \"./types\";\n\n/**\n * Persistence abstraction for subscription state.\n *\n * Intentionally minimal — every state transition is performed by `put`-ing\n * the full Subscription object, and every lookup is by `subId`. Address /\n * payer-indexed queries are deliberately NOT part of this contract: the\n * seller's own data model should own that (e.g. by mapping wallet →\n * subId(s) in its user table), keeping the SDK store free of any secondary\n * index requirement.\n */\nexport interface SubscriptionStore {\n get(subId: string): Promise<Subscription | null>;\n put(sub: Subscription): Promise<void>;\n delete(subId: string): Promise<void>;\n}\n\n/**\n * In-memory reference implementation. Suitable for development / unit tests /\n * single-process demos only — multi-process deployments must replace this\n * with a shared persistent backend.\n */\nexport class InMemoryStore implements SubscriptionStore {\n private readonly data = new Map<string, Subscription>();\n\n async get(subId: string): Promise<Subscription | null> {\n const sub = this.data.get(subId);\n return sub ? { ...sub } : null;\n }\n\n async put(sub: Subscription): Promise<void> {\n this.data.set(sub.subId, { ...sub });\n }\n\n async delete(subId: string): Promise<void> {\n this.data.delete(subId);\n }\n\n /**\n * Return all subscriptions, ordered by `startAt` ascending. Not part of\n * the SubscriptionStore interface — admin/debug helper, not used by the\n * scheme. Production backends should expose paginated equivalents.\n */\n async list(): Promise<Subscription[]> {\n return Array.from(this.data.values())\n .map(s => ({ ...s }))\n .sort((a, b) => a.startAt - b.startAt);\n }\n}\n","import type { CancelAuth, ChargeResult, Subscription, SubscriptionCapability } from \"./types\";\nimport type { SubscriptionStore } from \"./store\";\n\nexport interface SubscriptionClientConfig {\n /**\n * The scheme instance to delegate facilitator-touching operations to.\n * Typically the same `PermitSubscriptionScheme` instance that is registered\n * to `x402ResourceServer`, so HTTP main-line state and out-of-band charge\n * state share one source of truth.\n */\n scheme: SubscriptionCapability;\n /**\n * The store the scheme writes to. Required here because `getSubscription`\n * reads from the store (fast path) while `syncFromChain` writes to it after\n * re-fetching from chain.\n */\n store: SubscriptionStore;\n}\n\n/**\n * Out-of-band primitives for Seller scheduler / business code. SDK ships the\n * per-call atoms (charge / cancelBySeller / syncFromChain / etc.) but NOT a\n * scheduler — cron, due index, retry policy, distributed locks are all\n * Seller infrastructure.\n *\n * All methods are thin wrappers:\n * - `charge` delegates to scheme.charge (throws ChargeError on fail)\n * - `cancelBySeller` delegates to scheme.settleCancel with a Seller-built\n * CancelAuth\n * - `syncFromChain` re-pulls Subscription via scheme.getSubscription and\n * repairs the store; connects with the `state===\"changed\"`\n * chain to also sync the downstream new sub\n * - `getSubscription` direct store read (does NOT touch the chain)\n */\nexport class SubscriptionClient {\n protected readonly scheme: SubscriptionCapability;\n protected readonly store: SubscriptionStore;\n\n constructor(config: SubscriptionClientConfig) {\n this.scheme = config.scheme;\n this.store = config.store;\n }\n\n /**\n * Run one charge period for a subscription. Throws `ChargeError` (one of 6\n * codes) on facilitator-side failure. Internally `scheme.charge` already\n * updates the store on success (and on `planChangeTriggered`); the client is\n * a pass-through.\n */\n async charge(subId: string): Promise<ChargeResult> {\n return this.scheme.charge(subId);\n }\n\n /**\n * Seller-initiated cancel (e.g. ToS violation, fraud, business reason).\n *\n * The SDK does NOT hold the Seller's merchant private key; the Seller must\n * construct + sign a `CancelAuth` with `by=1 (MERCHANT)` outside and pass\n * it in. SDK runs verifyCancel (sanity check on the auth) then settleCancel\n * (facilitator + store mark canceled).\n *\n * Throws on either verify or settle failure.\n */\n async cancelBySeller(subId: string, auth: CancelAuth, _reason?: string): Promise<void> {\n const v = await this.scheme.verifyCancel(auth, subId);\n if (!v.ok) {\n throw new Error(`cancelBySeller.verify failed: ${v.error}`);\n }\n const r = await this.scheme.settleCancel(auth, subId);\n if (!r.success) {\n throw new Error(`cancelBySeller.settle failed: ${r.error}`);\n }\n }\n\n /**\n * Re-sync a subscription from chain and repair the store. Use when:\n * - `charge` threw `SubscriptionNotActive` (buyer may have cancelled\n * directly via the facilitator or contract)\n * - `charge` threw `ConfirmationTimeout` (network-level failure; chain\n * may or may not have written)\n * - periodic reconciliation\n *\n * If the synced sub is in `\"changed\"` state, the downstream `changedToSubId`\n * is also fetched and persisted, so the Seller's `dueIndex` can switch over\n * to the new sub without manual intervention.\n */\n async syncFromChain(subId: string): Promise<Subscription | null> {\n const latest = await this.scheme.getSubscription(subId);\n if (!latest) return null;\n await this.store.put(latest);\n\n if (latest.state === \"changed\" && latest.changedToSubId) {\n const newSub = await this.scheme.getSubscription(latest.changedToSubId);\n if (newSub) await this.store.put(newSub);\n }\n return latest;\n }\n\n /**\n * Direct store read. Cheap; does NOT touch the chain. Use this for hot-path\n * lookups (e.g. resolving subId to plan/tier for business logic). For chain\n * state of record, use `syncFromChain`.\n */\n async getSubscription(subId: string): Promise<Subscription | null> {\n return this.store.get(subId);\n }\n}\n","import type { Hex } from \"viem\";\n\nimport type { PaymentRequirements } from \"../../types/payments\";\nimport { ErrorCode } from \"../errors\";\nimport type { SubscriptionTerms } from \"./payload\";\nimport { ZERO_BYTES32, type SubscriptionRequirementsExtra } from \"./typed-data\";\n\nfunction addrEq(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\nfunction hexEq(a: Hex | undefined, b: Hex): boolean {\n return !!a && a.toLowerCase() === b.toLowerCase();\n}\n\n/**\n * Verify that buyer-signed `terms` bind to the server-advertised\n * PaymentRequirements. Without this field-by-field check a buyer could sign\n * a basic-tier accepted but submit terms claiming enterprise-tier access at\n * basic price. The contract verifies the signature but cannot see what the\n * seller offered in 402 — only the SDK can enforce this binding.\n *\n * All mismatches collapse to `terms_binding_invalid` so the caller's switch\n * statement stays compact.\n *\n * Returns `null` on match, an `ErrorCode` on first mismatch.\n */\nexport function verifyTermsBindRequirements(\n terms: SubscriptionTerms,\n requirements: PaymentRequirements,\n): ErrorCode | null {\n const extra = (requirements.extra ?? {}) as Partial<SubscriptionRequirementsExtra>;\n if (!extra.plan || extra.amountPerPeriod === undefined || extra.facilitator === undefined) {\n return ErrorCode.TermsBindingInvalid;\n }\n\n if (!addrEq(terms.merchant, requirements.payTo)) return ErrorCode.MerchantMismatch;\n if (!addrEq(terms.token, requirements.asset)) return ErrorCode.TermsBindingInvalid;\n if (!addrEq(terms.facilitator, extra.facilitator)) return ErrorCode.TermsBindingInvalid;\n\n if (terms.amountPerPeriod !== extra.amountPerPeriod) return ErrorCode.TermsBindingInvalid;\n if (terms.periodSec !== extra.periodSec) return ErrorCode.TermsBindingInvalid;\n if (terms.maxPeriods !== extra.maxPeriods) return ErrorCode.TermsBindingInvalid;\n if (terms.periodMode !== (extra.periodMode ?? 0)) return ErrorCode.TermsBindingInvalid;\n if (terms.planTier !== extra.plan.tier) return ErrorCode.TermsBindingInvalid;\n\n // Server-pinned startAt must be honored; if server left it unset (==undefined),\n // accept whatever the buyer signed (contract resolves 0 → block.timestamp).\n if (extra.startAt !== undefined && terms.startAt !== extra.startAt) {\n return ErrorCode.TermsBindingInvalid;\n }\n\n const expectedInitPeriods = extra.initialCharge?.periodCount ?? 0;\n const expectedInitAmount = extra.initialCharge?.totalAmount ?? \"0\";\n if (terms.initialChargePeriods !== expectedInitPeriods) return ErrorCode.TermsBindingInvalid;\n if (terms.initialChargeAmount !== expectedInitAmount) return ErrorCode.TermsBindingInvalid;\n\n // planId itself isn't compared here — the other field-level checks\n // (planTier / amountPerPeriod / merchant / …) already pin down the\n // economic effect of the subscription.\n\n // changeFrom binding — direction encoded in changeEffectiveAt:\n // undefined → create (changeFromSubId==0 / changeEffectiveAt==0)\n // immediate → upgrade (changeEffectiveAt==1)\n // period_end → downgrade (changeEffectiveAt==2)\n if (extra.changeFrom) {\n if (!hexEq(terms.changeFromSubId, extra.changeFrom.fromSubId)) {\n return ErrorCode.TermsBindingInvalid;\n }\n const expectedEff =\n extra.changeFrom.effectiveAt === \"immediate\"\n ? 1\n : extra.changeFrom.effectiveAt === \"period_end\"\n ? 2\n : 0;\n if (terms.changeEffectiveAt !== expectedEff) return ErrorCode.TermsBindingInvalid;\n } else {\n if (terms.changeFromSubId !== ZERO_BYTES32) return ErrorCode.TermsBindingInvalid;\n if (terms.changeEffectiveAt !== 0) return ErrorCode.TermsBindingInvalid;\n }\n\n return null;\n}\n","/**\n * Local mirror of the facilitator's elapsed-period math. Used by\n * `verifyAccess` to decide whether `lastChargedPeriod` is current without\n * hitting the facilitator on every request — only when the local\n * computation says we're behind does the SDK fall through to a GET /detail\n * refresh.\n *\n * MUST stay bit-for-bit equivalent to the backend implementation. Returns\n * `0` when the subscription has not yet started — caller treats this as a\n * special \"pre-start\" state.\n */\n\nconst PERIOD_MODE_CALENDAR_MONTH = 1;\n\n/**\n * Compute the real elapsed period count at `nowSec`, NOT clamped to\n * `maxPeriods`. Period 1 is the first chargeable period; `0` means\n * pre-start (subscription not yet effective).\n */\nexport function computeElapsedPeriods(\n periodMode: number,\n startAt: number,\n billingAnchorAt: number,\n periodSec: number,\n nowSec: number,\n): number {\n if (nowSec < startAt) return 0;\n if (periodMode === PERIOD_MODE_CALENDAR_MONTH) {\n const anchor = billingAnchorAt > 0 ? billingAnchorAt : startAt;\n const startOffset = elapsedCalendarMonths(anchor, startAt);\n return elapsedCalendarMonths(anchor, nowSec) - startOffset + 1;\n }\n if (periodSec <= 0) return 0;\n return Math.floor((nowSec - startAt) / periodSec) + 1;\n}\n\n/**\n * Number of calendar-month boundaries crossed between `anchorSec` (exclusive)\n * and `tsSec` (inclusive). Each boundary is `addCalendarMonths(anchor, n)`\n * for n=1,2,…, with month-end truncation (1/31 + 1m → 2/28/29).\n */\nexport function elapsedCalendarMonths(anchorSec: number, tsSec: number): number {\n if (tsSec <= anchorSec) return 0;\n const anchor = new Date(anchorSec * 1000);\n const ts = new Date(tsSec * 1000);\n let diff =\n (ts.getUTCFullYear() - anchor.getUTCFullYear()) * 12 +\n (ts.getUTCMonth() - anchor.getUTCMonth());\n if (diff < 0) return 0;\n if (addCalendarMonths(anchorSec, diff) > tsSec) diff--;\n return Math.max(diff, 0);\n}\n\n/**\n * Add `n` calendar months to `anchorSec`, keeping the anchor's day-of-month\n * but truncating to month-end when overflowing (1/31 + 1m → 2/28 or 2/29).\n * Returned timestamp preserves the anchor's hour / minute / second / ms in UTC.\n */\nexport function addCalendarMonths(anchorSec: number, n: number): number {\n const anchor = new Date(anchorSec * 1000);\n const targetYear = anchor.getUTCFullYear() + Math.floor((anchor.getUTCMonth() + n) / 12);\n const targetMonth = (((anchor.getUTCMonth() + n) % 12) + 12) % 12;\n // Days in target month (UTC) — day 0 of month+1 is the last day of month.\n const daysInTargetMonth = new Date(Date.UTC(targetYear, targetMonth + 1, 0)).getUTCDate();\n const day = Math.min(anchor.getUTCDate(), daysInTargetMonth);\n const ts = Date.UTC(\n targetYear,\n targetMonth,\n day,\n anchor.getUTCHours(),\n anchor.getUTCMinutes(),\n anchor.getUTCSeconds(),\n anchor.getUTCMilliseconds(),\n );\n return Math.floor(ts / 1000);\n}\n","import { encodePacked, keccak256, type Hex } from \"viem\";\n\nimport type { AccessProof } from \"../types\";\nimport { base64DecodeUtf8, base64EncodeUtf8 } from \"./base64\";\n\nexport interface AccessProofMessageInput {\n subId: Hex; // bytes32\n payer: Hex; // address\n timestamp: number; // uint64, unix seconds\n}\n\n/**\n * Returns the inner 32-byte hash that wallets sign via EIP-191 personal_sign.\n *\n * Layout:\n * inner = keccak256(abi.encodePacked(bytes32 subId, address payer, uint256 timestamp))\n *\n * `timestamp` is encoded as `uint256` (32 bytes). Switching to anything\n * narrower yields a different digest and silently produces\n * `signature_invalid` on every access call.\n *\n * IMPORTANT: callers must NOT prepend the EIP-191 envelope themselves —\n * `wallet.signMessage(buildAccessProofMessage(...))` will add the\n * `\\x19Ethereum Signed Message:\\n32` prefix automatically. The recover step on\n * the server must mirror this (verify EIP-191 signature, not raw keccak).\n */\nexport function buildAccessProofMessage(input: AccessProofMessageInput): Hex {\n return keccak256(\n encodePacked(\n [\"bytes32\", \"address\", \"uint256\"],\n [input.subId, input.payer, BigInt(input.timestamp)],\n ),\n );\n}\n\nexport function encodeAccessProof(proof: AccessProof): string {\n return base64EncodeUtf8(JSON.stringify(proof));\n}\n\nexport function decodeAccessProof(headerValue: string): AccessProof {\n const json = base64DecodeUtf8(headerValue);\n const parsed = JSON.parse(json) as AccessProof;\n if (!parsed || parsed.kind !== \"subscription-id\") {\n throw new Error(`decodeAccessProof: expected kind=\"subscription-id\", got \"${parsed?.kind}\"`);\n }\n return parsed;\n}\n","export { verifyTermsBindRequirements } from \"./verify-terms\";\nexport { addCalendarMonths, computeElapsedPeriods, elapsedCalendarMonths } from \"./period-math\";\nexport { base64DecodeUtf8, base64EncodeUtf8 } from \"./base64\";\n\nexport type {\n EncodePaymentPayloadInput,\n PermitSingleData,\n SubscriptionPaymentInner,\n SubscriptionTerms,\n} from \"./payload\";\nexport {\n asSubscriptionPaymentInner,\n decodePaymentPayload,\n encodePaymentPayload,\n parsePaymentRequired,\n} from \"./payload\";\n\nexport type { AccessProofMessageInput } from \"./access-proof\";\nexport { buildAccessProofMessage, decodeAccessProof, encodeAccessProof } from \"./access-proof\";\n\nexport type {\n BuildCancelAuthTypedDataInput,\n BuildPendingChangeCancelAuthTypedDataInput,\n BuildPermit2TypedDataInput,\n BuildSubscriptionTermsTypedDataInput,\n ChangeFromExtra,\n SubscriptionContractAddresses,\n SubscriptionPlanExtra,\n SubscriptionRequirementsExtra,\n TypedDataEnvelope,\n} from \"./typed-data\";\nexport {\n buildCancelAuthTypedData,\n buildPendingChangeCancelAuthTypedData,\n buildPermit2TypedData,\n buildSubscriptionTermsTypedData,\n CANCEL_AUTH_TYPES,\n computePermitSingleStructHash,\n PENDING_CHANGE_CANCEL_AUTH_TYPES,\n PERMIT2_TYPES,\n parseChainIdFromNetwork,\n SUBSCRIPTION_TERMS_TYPES,\n ZERO_BYTES32,\n} from \"./typed-data\";\n","import type { FacilitatorClient } from \"../http/httpFacilitatorClient\";\nimport type { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport type { CancelAuth, PendingChangeCancelAuth, Subscription } from \"./types\";\n\n/**\n * Standard OKX facilitator response envelope. `code === 0` means success\n * (NUMBER, not string).\n */\nexport interface FacilitatorEnvelope<T> {\n code: number;\n msg?: string | null;\n data?: T;\n}\n\n/** POST /api/v6/pay/x402/subscriptions response data. */\nexport interface FacilitatorSubscribeData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/change response data. */\nexport interface FacilitatorChangeData {\n newSubId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/cancel response data. */\nexport interface FacilitatorCancelData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/cancel-pending-change response data. */\nexport interface FacilitatorCancelPendingData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/charge response data. */\nexport interface FacilitatorChargeData {\n subId: string;\n period: number;\n txHash?: string;\n /** SubscriptionChargeState — 0 pending / 1 success / 2 failed. */\n state: number;\n planChangeTriggered?: boolean;\n newSubId?: string | null;\n}\n\n/** POST /api/v6/pay/x402/subscriptions/{id}/finalize-expired response data. */\nexport interface FacilitatorFinalizeExpiredData {\n subId: string;\n txHash?: string;\n state: number;\n}\n\n/** One row of the charges feed (GET /api/v6/pay/x402/subscriptions/charges). */\nexport interface FacilitatorChargeRow {\n subId: string;\n period: number;\n /** 1 initial / 2 periodic / 3 downgrade_first_period / 4 finalize_expired_marker. */\n chargeType: number;\n amount: string;\n /** 0 pending / 1 success / 2 failed. */\n state: number;\n txHash?: string;\n planChangeTriggered?: boolean;\n newSubId?: string | null;\n}\n\n/** GET /api/v6/pay/x402/subscriptions/charges response data. */\nexport interface FacilitatorGetChargesData {\n charges: FacilitatorChargeRow[];\n}\n\n/** GET /api/v6/pay/x402/subscriptions/pending response data (most recent row). */\nexport interface FacilitatorPendingChangeRow {\n subId: string;\n newSubId: string;\n effectiveFromPeriod: number;\n /** 0 pending / 1 activated / 2 canceled / 3 expired. */\n state: number;\n}\n\n/** GET /api/v6/pay/x402/subscriptions/{id} response data. */\nexport interface FacilitatorGetSubscriptionData {\n subId: string;\n state: number;\n payer: string;\n merchant: string;\n token: string;\n amountPerPeriod: string;\n periodSec: number;\n /** 0 fixed_seconds / 1 calendar_month. */\n periodMode: number;\n maxPeriods: number;\n startAt: number;\n /** Calendar-month billing anchor (Unix s); 0/undefined in fixed_seconds mode. */\n billingAnchorAt?: number;\n /** Seller-side business identifier (NOT on-chain); facilitator echoes from its DB. */\n planId?: string;\n /** Plan tier from on-chain terms.planTier. */\n planTier?: number;\n lastChargedPeriod: number;\n totalPulled: string;\n changedToSubId?: string | null;\n isActive?: boolean;\n serviceEnded?: boolean;\n /** Mode-aware current period, clamped to maxPeriods (boundary = next period). */\n currentPeriod?: number;\n /**\n * Real elapsed period number, NOT clamped — `elapsedPeriods > maxPeriods`\n * means the service window already ended. SDK polls until\n * `lastChargedPeriod >= elapsedPeriods` to confirm a write settled.\n */\n elapsedPeriods?: number;\n nextChargeableAt?: number;\n pendingPlanChange?: {\n subId: string;\n newSubId: string;\n effectiveFromPeriod: number;\n state: number;\n } | null;\n}\n\n/**\n * Subscription write-flow request body shared by subscribe / change. The\n * facilitator parses these field-by-field — DO NOT wrap in an x402 envelope\n * (no `paymentPayload` / `paymentRequirements` wrapping).\n */\nexport interface SubscriptionWriteRequest {\n chainIndex: number;\n terms: PaymentPayload[\"payload\"] extends { terms: infer T } ? T : unknown;\n permit: PaymentPayload[\"payload\"] extends { permit: infer P } ? P : unknown;\n termsSig: string;\n permitSig: string;\n syncSettle?: boolean;\n}\n\n/** Subscription-aware facilitator client. Extends the base FacilitatorClient. */\nexport interface SubscriptionFacilitatorClient extends FacilitatorClient {\n /** POST /api/v6/pay/x402/subscriptions */\n subscribe(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorSubscribeData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/change */\n changeSubscription(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n oldSubId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChangeData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/{subId}/cancel */\n cancelSubscription(\n subId: string,\n cancelAuth: CancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/{subId}/cancel-pending-change */\n cancelPendingChange(\n subId: string,\n cancelAuth: PendingChangeCancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelPendingData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/{subId}/charge */\n chargeSubscription(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChargeData>>;\n\n /** POST /api/v6/pay/x402/subscriptions/finalize-expired — cleans up an ACTIVE sub whose service window has ended. */\n finalizeExpired(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorFinalizeExpiredData>>;\n\n /** GET /api/v6/pay/x402/subscriptions/charges — paginated charge feed. */\n getCharges(\n subId: string,\n limit?: number,\n offset?: number,\n ): Promise<FacilitatorEnvelope<FacilitatorGetChargesData>>;\n\n /** GET /api/v6/pay/x402/subscriptions/pending — most recent pendingPlanChange row (any state). */\n getPendingChange(subId: string): Promise<FacilitatorEnvelope<FacilitatorPendingChangeRow | null>>;\n\n /** GET /api/v6/pay/x402/subscriptions/{subId} */\n getSubscription(subId: string): Promise<FacilitatorEnvelope<FacilitatorGetSubscriptionData>>;\n}\n\n/**\n * Type guard: does this FacilitatorClient implement the subscription\n * endpoints?\n */\nexport function supportsSubscription(\n client: FacilitatorClient,\n): client is SubscriptionFacilitatorClient {\n const c = client as Partial<SubscriptionFacilitatorClient>;\n return (\n typeof c.subscribe === \"function\" &&\n typeof c.changeSubscription === \"function\" &&\n typeof c.cancelSubscription === \"function\" &&\n typeof c.cancelPendingChange === \"function\" &&\n typeof c.chargeSubscription === \"function\" &&\n typeof c.finalizeExpired === \"function\" &&\n typeof c.getCharges === \"function\" &&\n typeof c.getPendingChange === \"function\" &&\n typeof c.getSubscription === \"function\"\n );\n}\n\n/** Re-export `Subscription` so consumers don't have to import from `./types`. */\nexport type { Subscription };\n","export type {\n AccessProof,\n AccessRouteRequirements,\n CancelAuth,\n PendingChangeCancelAuth,\n CancelInitiator,\n ChargeResult,\n PendingPlanChange,\n PlanCatalog,\n PlanCatalogEntry,\n PlanInitialCharge,\n OnBeforeAccessContext,\n OnBeforeAccessHook,\n OnBeforeAccessResult,\n SettleCancelOk,\n SettleCancelPendingChangeOk,\n SettleCancelPendingChangeResult,\n SettleCancelResult,\n SettleChangeOk,\n SettleChangeResult,\n SettleResultFail,\n SettleSubscribeOk,\n SettleSubscribeResult,\n Subscription,\n SubscriptionCapability,\n SubscriptionState,\n VerifyAccessOk,\n VerifyAccessResult,\n VerifyOwnershipOk,\n VerifyOwnershipResult,\n VerifyChangeOk,\n VerifyChangeResult,\n VerifyResult,\n VerifyResultFail,\n VerifyResultOk,\n} from \"./types\";\nexport { hasSubscriptionCapability } from \"./types\";\n\nexport { ChargeError, ChargeErrorCode, ErrorCode } from \"./errors\";\n\nexport type { SubscriptionStore } from \"./store\";\nexport { InMemoryStore } from \"./store\";\n\nexport type { SubscriptionClientConfig } from \"./client\";\nexport { SubscriptionClient } from \"./client\";\n\nexport type {\n AccessProofMessageInput,\n BuildCancelAuthTypedDataInput,\n BuildPermit2TypedDataInput,\n BuildSubscriptionTermsTypedDataInput,\n ChangeFromExtra,\n EncodePaymentPayloadInput,\n PermitSingleData,\n SubscriptionContractAddresses,\n SubscriptionPaymentInner,\n SubscriptionPlanExtra,\n SubscriptionRequirementsExtra,\n SubscriptionTerms,\n TypedDataEnvelope,\n} from \"./codec\";\nexport {\n asSubscriptionPaymentInner,\n addCalendarMonths,\n base64DecodeUtf8,\n base64EncodeUtf8,\n buildAccessProofMessage,\n buildCancelAuthTypedData,\n buildPendingChangeCancelAuthTypedData,\n buildPermit2TypedData,\n buildSubscriptionTermsTypedData,\n CANCEL_AUTH_TYPES,\n computeElapsedPeriods,\n computePermitSingleStructHash,\n decodeAccessProof,\n decodePaymentPayload,\n elapsedCalendarMonths,\n encodeAccessProof,\n encodePaymentPayload,\n parseChainIdFromNetwork,\n parsePaymentRequired,\n PENDING_CHANGE_CANCEL_AUTH_TYPES,\n PERMIT2_TYPES,\n SUBSCRIPTION_TERMS_TYPES,\n verifyTermsBindRequirements,\n ZERO_BYTES32,\n} from \"./codec\";\n\nexport type {\n FacilitatorCancelData,\n FacilitatorCancelPendingData,\n FacilitatorChangeData,\n FacilitatorChargeData,\n FacilitatorChargeRow,\n FacilitatorEnvelope,\n FacilitatorFinalizeExpiredData,\n FacilitatorGetChargesData,\n FacilitatorGetSubscriptionData,\n FacilitatorPendingChangeRow,\n FacilitatorSubscribeData,\n SubscriptionFacilitatorClient,\n} from \"./facilitator-client\";\nexport { supportsSubscription } from \"./facilitator-client\";\n","import { SettleResponse } from \"../types\";\nimport { PaymentPayload, PaymentRequired } from \"../types/payments\";\nimport { Base64EncodedRegex, safeBase64Decode, safeBase64Encode } from \"../utils\";\n\n// HTTP Methods that typically use query parameters\nexport type QueryParamMethods = \"GET\" | \"HEAD\" | \"DELETE\";\n\n// HTTP Methods that typically use request body\nexport type BodyMethods = \"POST\" | \"PUT\" | \"PATCH\";\n\n/**\n * Encodes a payment payload as a base64 header value.\n *\n * @param paymentPayload - The payment payload to encode\n * @returns Base64 encoded string representation of the payment payload\n */\nexport function encodePaymentSignatureHeader(paymentPayload: PaymentPayload): string {\n return safeBase64Encode(JSON.stringify(paymentPayload));\n}\n\n/**\n * Decodes a base64 payment signature header into a payment payload.\n *\n * @param paymentSignatureHeader - The base64 encoded payment signature header\n * @returns The decoded payment payload\n */\nexport function decodePaymentSignatureHeader(paymentSignatureHeader: string): PaymentPayload {\n if (!Base64EncodedRegex.test(paymentSignatureHeader)) {\n throw new Error(\"Invalid payment signature header\");\n }\n return JSON.parse(safeBase64Decode(paymentSignatureHeader)) as PaymentPayload;\n}\n\n/**\n * Encodes a payment required object as a base64 header value.\n *\n * @param paymentRequired - The payment required object to encode\n * @returns Base64 encoded string representation of the payment required object\n */\nexport function encodePaymentRequiredHeader(paymentRequired: PaymentRequired): string {\n return safeBase64Encode(JSON.stringify(paymentRequired));\n}\n\n/**\n * Decodes a base64 payment required header into a payment required object.\n *\n * @param paymentRequiredHeader - The base64 encoded payment required header\n * @returns The decoded payment required object\n */\nexport function decodePaymentRequiredHeader(paymentRequiredHeader: string): PaymentRequired {\n if (!Base64EncodedRegex.test(paymentRequiredHeader)) {\n throw new Error(\"Invalid payment required header\");\n }\n return JSON.parse(safeBase64Decode(paymentRequiredHeader)) as PaymentRequired;\n}\n\n/**\n * Encodes a payment response as a base64 header value.\n *\n * @param paymentResponse - The payment response to encode\n * @returns Base64 encoded string representation of the payment response\n */\nexport function encodePaymentResponseHeader(paymentResponse: SettleResponse): string {\n return safeBase64Encode(JSON.stringify(paymentResponse));\n}\n\n/**\n * Decodes a base64 payment response header into a settle response.\n *\n * @param paymentResponseHeader - The base64 encoded payment response header\n * @returns The decoded settle response\n */\nexport function decodePaymentResponseHeader(paymentResponseHeader: string): SettleResponse {\n if (!Base64EncodedRegex.test(paymentResponseHeader)) {\n throw new Error(\"Invalid payment response header\");\n }\n return JSON.parse(safeBase64Decode(paymentResponseHeader)) as SettleResponse;\n}\n\n// Export HTTP service and types\nexport {\n x402HTTPResourceServer,\n HTTPAdapter,\n HTTPRequestContext,\n HTTPTransportContext,\n HTTPResponseInstructions,\n HTTPProcessResult,\n PaywallConfig,\n PaywallProvider,\n PaymentOption,\n RouteConfig,\n RoutesConfig,\n CompiledRoute,\n DynamicPayTo,\n DynamicPrice,\n UnpaidResponseBody,\n HTTPResponseBody,\n SettlementFailedResponseBody,\n ProcessSettleResultResponse,\n ProcessSettleSuccessResponse,\n ProcessSettleFailureResponse,\n RouteValidationError,\n RouteConfigurationError,\n ProtectedRequestHook,\n OnSettlementTimeoutHook,\n} from \"./x402HTTPResourceServer\";\nexport {\n HTTPFacilitatorClient,\n FacilitatorClient,\n FacilitatorConfig,\n} from \"./httpFacilitatorClient\";\nexport { FacilitatorResponseError, getFacilitatorResponseError } from \"../types\";\nexport { x402HTTPClient, PaymentRequiredContext, PaymentRequiredHook } from \"./x402HTTPClient\";\n","import { Network } from \"../types\";\n\n/**\n * Scheme data structure for facilitator storage\n */\nexport interface SchemeData<T> {\n facilitator: T;\n networks: Set<Network>;\n pattern: Network;\n}\n\nexport const findSchemesByNetwork = <T>(\n map: Map<string, Map<string, T>>,\n network: Network,\n): Map<string, T> | undefined => {\n // Direct match first\n let implementationsByScheme = map.get(network);\n\n if (!implementationsByScheme) {\n // Try pattern matching for registered network patterns\n for (const [registeredNetworkPattern, implementations] of map.entries()) {\n // Convert the registered network pattern to a regex\n // e.g., \"eip155:*\" becomes /^eip155:.*$/\n const pattern = registeredNetworkPattern\n .replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\") // Escape special regex chars except *\n .replace(/\\\\\\*/g, \".*\"); // Replace escaped * with .*\n\n const regex = new RegExp(`^${pattern}$`);\n\n if (regex.test(network)) {\n implementationsByScheme = implementations;\n break;\n }\n }\n }\n\n return implementationsByScheme;\n};\n\nexport const findByNetworkAndScheme = <T>(\n map: Map<string, Map<string, T>>,\n scheme: string,\n network: Network,\n): T | undefined => {\n return findSchemesByNetwork(map, network)?.get(scheme);\n};\n\n/**\n * Finds a facilitator by scheme and network using pattern matching.\n * Works with new SchemeData storage structure.\n *\n * @param schemeMap - Map of scheme names to SchemeData\n * @param scheme - The scheme to find\n * @param network - The network to match against\n * @returns The facilitator if found, undefined otherwise\n */\nexport const findFacilitatorBySchemeAndNetwork = <T>(\n schemeMap: Map<string, SchemeData<T>>,\n scheme: string,\n network: Network,\n): T | undefined => {\n const schemeData = schemeMap.get(scheme);\n if (!schemeData) return undefined;\n\n // Check if network is in the stored networks set\n if (schemeData.networks.has(network)) {\n return schemeData.facilitator;\n }\n\n // Try pattern matching\n const patternRegex = new RegExp(\"^\" + schemeData.pattern.replace(\"*\", \".*\") + \"$\");\n if (patternRegex.test(network)) {\n return schemeData.facilitator;\n }\n\n return undefined;\n};\n\nexport const Base64EncodedRegex = /^[A-Za-z0-9+/]*={0,2}$/;\n\n/**\n * Encodes a string to base64 format\n *\n * @param data - The string to be encoded to base64\n * @returns The base64 encoded string\n */\nexport function safeBase64Encode(data: string): string {\n if (typeof globalThis !== \"undefined\" && typeof globalThis.btoa === \"function\") {\n const bytes = new TextEncoder().encode(data);\n const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join(\"\");\n return globalThis.btoa(binaryString);\n }\n return Buffer.from(data, \"utf8\").toString(\"base64\");\n}\n\n/**\n * Decodes a base64 string back to its original format\n *\n * @param data - The base64 encoded string to be decoded\n * @returns The decoded string in UTF-8 format\n */\nexport function safeBase64Decode(data: string): string {\n if (typeof globalThis !== \"undefined\" && typeof globalThis.atob === \"function\") {\n const binaryString = globalThis.atob(data);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n const decoder = new TextDecoder(\"utf-8\");\n return decoder.decode(bytes);\n }\n return Buffer.from(data, \"base64\").toString(\"utf-8\");\n}\n\n/**\n * Deep equality comparison for payment requirements\n * Uses a normalized JSON.stringify for consistent comparison\n *\n * @param obj1 - First object to compare\n * @param obj2 - Second object to compare\n * @returns True if objects are deeply equal\n */\nexport function deepEqual(obj1: unknown, obj2: unknown): boolean {\n // Normalize and stringify both objects for comparison\n // This handles nested objects, arrays, and different property orders\n const normalize = (obj: unknown): string => {\n // Handle primitives and null/undefined\n if (obj === null || obj === undefined) return JSON.stringify(obj);\n if (typeof obj !== \"object\") return JSON.stringify(obj);\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return JSON.stringify(\n obj.map(item =>\n typeof item === \"object\" && item !== null ? JSON.parse(normalize(item)) : item,\n ),\n );\n }\n\n // Handle objects - sort keys and recursively normalize values\n const sorted: Record<string, unknown> = {};\n Object.keys(obj as Record<string, unknown>)\n .sort()\n .forEach(key => {\n const value = (obj as Record<string, unknown>)[key];\n sorted[key] =\n typeof value === \"object\" && value !== null ? JSON.parse(normalize(value)) : value;\n });\n return JSON.stringify(sorted);\n };\n\n try {\n return normalize(obj1) === normalize(obj2);\n } catch {\n // Fallback to simple comparison if normalization fails\n return JSON.stringify(obj1) === JSON.stringify(obj2);\n }\n}\n","import { PaymentPayload, PaymentRequirements } from \"./payments\";\nimport { Network } from \"./\";\n\nexport type VerifyRequest = {\n x402Version: number;\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n};\n\nexport type VerifyResponse = {\n isValid: boolean;\n invalidReason?: string;\n invalidMessage?: string;\n payer?: string;\n extensions?: Record<string, unknown>;\n};\n\nexport type SettleRequest = {\n x402Version: number;\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n};\n\nexport type SettleResponse = {\n success: boolean;\n /** OKX extension: pending (async, Seller trusts Facilitator), success (immediate), timeout (on-chain timed out) */\n status?: \"pending\" | \"success\" | \"timeout\";\n errorReason?: string;\n errorMessage?: string;\n payer?: string;\n transaction: string;\n network: Network;\n /** Actual amount settled in atomic token units. Present for schemes like `upto` where settlement amount may differ from the authorized maximum. */\n amount?: string;\n extensions?: Record<string, unknown>;\n};\n\nexport type SupportedKind = {\n x402Version: number;\n scheme: string;\n network: Network;\n extra?: Record<string, unknown>;\n};\n\nexport type SupportedResponse = {\n kinds: SupportedKind[];\n extensions: string[];\n signers: Record<string, string[]>; // CAIP family pattern → Signer addresses\n};\n\n/**\n * Response from `GET /settle/status?txHash=...`.\n * OKX extension: query on-chain settlement status by transaction hash.\n */\nexport type SettleStatusResponse = {\n success: boolean;\n status?: \"pending\" | \"success\" | \"failed\";\n errorReason?: string;\n errorMessage?: string;\n payer?: string;\n transaction?: string;\n network?: Network;\n};\n\n/**\n * Error thrown when payment verification fails.\n */\nexport class VerifyError extends Error {\n readonly invalidReason?: string;\n readonly invalidMessage?: string;\n readonly payer?: string;\n readonly statusCode: number;\n\n /**\n * Creates a VerifyError from a failed verification response.\n *\n * @param statusCode - HTTP status code from the facilitator\n * @param response - The verify response containing error details\n */\n constructor(statusCode: number, response: VerifyResponse) {\n const reason = response.invalidReason || \"unknown reason\";\n const message = response.invalidMessage;\n super(message ? `${reason}: ${message}` : reason);\n this.name = \"VerifyError\";\n this.statusCode = statusCode;\n this.invalidReason = response.invalidReason;\n this.invalidMessage = response.invalidMessage;\n this.payer = response.payer;\n }\n}\n\n/**\n * Error thrown when payment settlement fails.\n */\nexport class SettleError extends Error {\n readonly errorReason?: string;\n readonly errorMessage?: string;\n readonly payer?: string;\n readonly transaction: string;\n readonly network: Network;\n readonly statusCode: number;\n\n /**\n * Creates a SettleError from a failed settlement response.\n *\n * @param statusCode - HTTP status code from the facilitator\n * @param response - The settle response containing error details\n */\n constructor(statusCode: number, response: SettleResponse) {\n const reason = response.errorReason || \"unknown reason\";\n const message = response.errorMessage;\n super(message ? `${reason}: ${message}` : reason);\n this.name = \"SettleError\";\n this.statusCode = statusCode;\n this.errorReason = response.errorReason;\n this.errorMessage = response.errorMessage;\n this.payer = response.payer;\n this.transaction = response.transaction;\n this.network = response.network;\n }\n}\n\n/**\n * Error thrown when a facilitator returns malformed success payload data.\n */\nexport class FacilitatorResponseError extends Error {\n /**\n * Creates a FacilitatorResponseError for malformed facilitator responses.\n *\n * @param message - The boundary error message\n */\n constructor(message: string) {\n super(message);\n this.name = \"FacilitatorResponseError\";\n }\n}\n\n/**\n * Walks an error cause chain to find the first facilitator response error.\n *\n * @param error - The thrown value to inspect\n * @returns The nested facilitator response error, if present\n */\nexport function getFacilitatorResponseError(error: unknown): FacilitatorResponseError | null {\n let current = error;\n\n while (current instanceof Error) {\n if (current instanceof FacilitatorResponseError) {\n return current;\n }\n current = current.cause;\n }\n\n return null;\n}\n","import { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport {\n VerifyResponse,\n SettleResponse,\n SettleStatusResponse,\n SupportedResponse,\n VerifyError,\n SettleError,\n FacilitatorResponseError,\n} from \"../types/facilitator\";\nimport type {\n FacilitatorCancelData,\n FacilitatorCancelPendingData,\n FacilitatorChangeData,\n FacilitatorChargeData,\n FacilitatorEnvelope,\n FacilitatorFinalizeExpiredData,\n FacilitatorGetChargesData,\n FacilitatorGetSubscriptionData,\n FacilitatorPendingChangeRow,\n FacilitatorSubscribeData,\n} from \"../subscription/facilitator-client\";\nimport { parseChainIdFromNetwork } from \"../subscription/codec/typed-data\";\nimport { asSubscriptionPaymentInner } from \"../subscription/codec/payload\";\nimport type { CancelAuth, PendingChangeCancelAuth } from \"../subscription/types\";\nimport { z } from \"../schemas\";\n\nconst DEFAULT_FACILITATOR_URL = \"https://web3.okx.com/facilitator\";\n\nexport interface FacilitatorConfig {\n url?: string;\n createAuthHeaders?: () => Promise<{\n verify: Record<string, string>;\n settle: Record<string, string>;\n supported: Record<string, string>;\n }>;\n /**\n * Optional per-operation auth header generator for subscription endpoints.\n * Called with `subscribe` | `change` | `cancel` | `charge` | `getSubscription`.\n * If omitted, subscription requests go out without auth headers (suitable\n * for self-hosted facilitators or tests; for OKX use `OKXFacilitatorClient`).\n */\n createSubscriptionAuthHeaders?: (op: string) => Promise<Record<string, string>>;\n /**\n * Inject a fetch implementation (test mock / custom transport). Defaults\n * to the global `fetch`.\n */\n fetchFn?: typeof fetch;\n}\n\n/**\n * Interface for facilitator clients\n * Can be implemented for HTTP-based or local facilitators\n */\nexport interface FacilitatorClient {\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentPayload - The payment to verify\n * @param paymentRequirements - The requirements to verify against\n * @returns Verification response\n */\n verify(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<VerifyResponse>;\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentPayload - The payment to settle\n * @param paymentRequirements - The requirements for settlement\n * @returns Settlement response\n */\n settle(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<SettleResponse>;\n\n /**\n * Get supported payment kinds and extensions from the facilitator\n *\n * @returns Supported payment kinds and extensions\n */\n getSupported(): Promise<SupportedResponse>;\n\n /**\n * Query on-chain settlement status by transaction hash.\n * OKX extension: used for timeout recovery polling.\n *\n * @param txHash - The transaction hash to query\n * @returns Settlement status response\n */\n getSettleStatus?(txHash: string): Promise<SettleStatusResponse>;\n}\n\n/** Number of retries for getSupported() on 429 rate limit errors */\nconst GET_SUPPORTED_RETRIES = 3;\n/** Base delay in ms for exponential backoff on retries */\nconst GET_SUPPORTED_RETRY_DELAY_MS = 1000;\n\nconst verifyResponseSchema: z.ZodType<VerifyResponse, z.ZodTypeDef, unknown> = z.object({\n isValid: z.boolean(),\n invalidReason: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n invalidMessage: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n payer: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n extensions: z\n .record(z.string(), z.unknown())\n .nullish()\n .transform(v => v ?? undefined),\n});\n\nconst settleResponseSchema: z.ZodType<SettleResponse, z.ZodTypeDef, unknown> = z.object({\n success: z.boolean(),\n // OKX extension: pending (async), success (immediate), timeout (on-chain timed out)\n status: z\n .enum([\"pending\", \"success\", \"timeout\"])\n .nullish()\n .transform(v => v ?? undefined)\n .optional(),\n errorReason: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n errorMessage: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n payer: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n transaction: z.string(),\n network: z.custom<SettleResponse[\"network\"]>(value => typeof value === \"string\"),\n amount: z\n .string()\n .nullish()\n .transform(v => v ?? undefined),\n extensions: z\n .record(z.string(), z.unknown())\n .nullish()\n .transform(v => v ?? undefined),\n});\n\nconst supportedKindSchema: z.ZodType<SupportedResponse[\"kinds\"][number], z.ZodTypeDef, unknown> =\n z.object({\n x402Version: z.number(),\n scheme: z.string(),\n network: z.custom<SupportedResponse[\"kinds\"][number][\"network\"]>(\n value => typeof value === \"string\",\n ),\n extra: z\n .record(z.string(), z.unknown())\n .nullish()\n .transform(v => v ?? undefined),\n });\n\nconst supportedResponseSchema: z.ZodType<SupportedResponse, z.ZodTypeDef, unknown> = z.object({\n kinds: z.array(supportedKindSchema),\n extensions: z.array(z.string()).default([]),\n signers: z.record(z.string(), z.array(z.string())).default({}),\n});\n\n/**\n * Produces a compact excerpt of a facilitator response body for error messages.\n *\n * @param text - The raw response body text\n * @param limit - The maximum number of characters to include\n * @returns A normalized excerpt suitable for logs and thrown errors\n */\nfunction responseExcerpt(text: string, limit: number = 200): string {\n const compact = text.trim().replace(/\\s+/g, \" \");\n if (!compact) {\n return \"<empty response>\";\n }\n\n if (compact.length <= limit) {\n return compact;\n }\n\n return `${compact.slice(0, limit - 3)}...`;\n}\n\n/**\n * Parses and validates a successful facilitator response body.\n *\n * @param response - The HTTP response returned by the facilitator\n * @param schema - The schema used to validate the response payload\n * @param operation - The facilitator operation name for error reporting\n * @returns The validated facilitator payload\n */\nasync function parseSuccessResponse<T>(\n response: Response,\n schema: z.ZodType<T, z.ZodTypeDef, unknown>,\n operation: string,\n): Promise<T> {\n const text = await response.text();\n\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new FacilitatorResponseError(\n `Facilitator ${operation} returned invalid JSON: ${responseExcerpt(text)}`,\n );\n }\n\n const parsed = schema.safeParse(data);\n if (!parsed.success) {\n throw new FacilitatorResponseError(\n `Facilitator ${operation} returned invalid data: ${responseExcerpt(text)}`,\n );\n }\n\n return parsed.data;\n}\n\n/**\n * HTTP-based client for interacting with x402 facilitator services\n * Handles HTTP communication with facilitator endpoints\n */\nexport class HTTPFacilitatorClient implements FacilitatorClient {\n readonly url: string;\n private readonly _createAuthHeaders?: FacilitatorConfig[\"createAuthHeaders\"];\n private readonly _createSubscriptionAuthHeaders?: FacilitatorConfig[\"createSubscriptionAuthHeaders\"];\n private readonly _fetchFn: typeof fetch;\n\n /**\n * Creates a new HTTPFacilitatorClient instance.\n *\n * @param config - Configuration options for the facilitator client\n */\n constructor(config?: FacilitatorConfig) {\n this.url = config?.url || DEFAULT_FACILITATOR_URL;\n this._createAuthHeaders = config?.createAuthHeaders;\n this._createSubscriptionAuthHeaders = config?.createSubscriptionAuthHeaders;\n this._fetchFn = config?.fetchFn ?? fetch;\n }\n\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentPayload - The payment to verify\n * @param paymentRequirements - The requirements to verify against\n * @returns Verification response\n */\n async verify(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"verify\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n const response = await this._fetchFn(`${this.url}/verify`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n x402Version: paymentPayload.x402Version,\n paymentPayload: this.toJsonSafe(paymentPayload),\n paymentRequirements: this.toJsonSafe(paymentRequirements),\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(`Facilitator verify failed (${response.status}): ${responseExcerpt(text)}`);\n }\n\n if (typeof data === \"object\" && data !== null && \"isValid\" in data) {\n throw new VerifyError(response.status, data as VerifyResponse);\n }\n\n throw new Error(\n `Facilitator verify failed (${response.status}): ${responseExcerpt(JSON.stringify(data))}`,\n );\n }\n\n return parseSuccessResponse(response, verifyResponseSchema, \"verify\");\n }\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentPayload - The payment to settle\n * @param paymentRequirements - The requirements for settlement\n * @returns Settlement response\n */\n async settle(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"settle\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n const response = await this._fetchFn(`${this.url}/settle`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n x402Version: paymentPayload.x402Version,\n paymentPayload: this.toJsonSafe(paymentPayload),\n paymentRequirements: this.toJsonSafe(paymentRequirements),\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n let data: unknown;\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(`Facilitator settle failed (${response.status}): ${responseExcerpt(text)}`);\n }\n\n if (typeof data === \"object\" && data !== null && \"success\" in data) {\n throw new SettleError(response.status, data as SettleResponse);\n }\n\n throw new Error(\n `Facilitator settle failed (${response.status}): ${responseExcerpt(JSON.stringify(data))}`,\n );\n }\n\n return parseSuccessResponse(response, settleResponseSchema, \"settle\");\n }\n\n /**\n * Get supported payment kinds and extensions from the facilitator.\n * Retries with exponential backoff on 429 rate limit errors.\n *\n * @returns Supported payment kinds and extensions\n */\n async getSupported(): Promise<SupportedResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"supported\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n let lastError: Error | null = null;\n for (let attempt = 0; attempt < GET_SUPPORTED_RETRIES; attempt++) {\n const response = await this._fetchFn(`${this.url}/supported`, {\n method: \"GET\",\n headers,\n });\n\n if (response.ok) {\n return parseSuccessResponse(response, supportedResponseSchema, \"supported\");\n }\n\n const errorText = await response.text().catch(() => response.statusText);\n lastError = new Error(\n `Facilitator getSupported failed (${response.status}): ${responseExcerpt(errorText)}`,\n );\n\n // Retry on 429 rate limit errors with exponential backoff\n if (response.status === 429 && attempt < GET_SUPPORTED_RETRIES - 1) {\n const delay = GET_SUPPORTED_RETRY_DELAY_MS * Math.pow(2, attempt);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n throw lastError;\n }\n\n throw lastError ?? new Error(\"Facilitator getSupported failed after retries\");\n }\n\n /**\n * Query on-chain settlement status by transaction hash.\n *\n * @param txHash - The transaction hash to query\n * @returns Settlement status response\n */\n async getSettleStatus(txHash: string): Promise<SettleStatusResponse> {\n let headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (this._createAuthHeaders) {\n const authHeaders = await this.createAuthHeaders(\"settle/status\");\n headers = { ...headers, ...authHeaders.headers };\n }\n\n const response = await this._fetchFn(\n `${this.url}/settle/status?txHash=${encodeURIComponent(txHash)}`,\n {\n method: \"GET\",\n headers,\n },\n );\n\n if (!response.ok) {\n const text = await response.text().catch(() => response.statusText);\n throw new Error(\n `Facilitator getSettleStatus failed (${response.status}): ${responseExcerpt(text)}`,\n );\n }\n\n const json = (await response.json()) as SettleStatusResponse;\n return json;\n }\n\n /**\n * Creates authentication headers for a specific path.\n *\n * @param path - The path to create authentication headers for (e.g., \"verify\", \"settle\", \"supported\")\n * @returns An object containing the authentication headers for the specified path\n */\n async createAuthHeaders(path: string): Promise<{\n headers: Record<string, string>;\n }> {\n if (this._createAuthHeaders) {\n const authHeaders = (await this._createAuthHeaders()) as Record<\n string,\n Record<string, string>\n >;\n return {\n headers: authHeaders[path] ?? {},\n };\n }\n return {\n headers: {},\n };\n }\n\n /**\n * Helper to convert objects to JSON-safe format.\n * Handles BigInt and other non-JSON types.\n *\n * @param obj - The object to convert\n * @returns The JSON-safe representation of the object\n */\n private toJsonSafe(obj: unknown): unknown {\n return JSON.parse(\n JSON.stringify(obj, (_, value) => (typeof value === \"bigint\" ? value.toString() : value)),\n );\n }\n\n // ── SubscriptionFacilitatorClient (period) ─────────────\n //\n // Generic JSON POST / GET helpers parameterized by `op` so the same code\n // path covers all five subscription endpoints. The standard OKX envelope\n // `{ code, msg?, data? }` is returned to the caller unparsed (the\n // subscription scheme reads `code === \"0\"` and `data` directly).\n\n private async subscriptionAuthHeaders(op: string): Promise<Record<string, string>> {\n if (!this._createSubscriptionAuthHeaders) return {};\n return this._createSubscriptionAuthHeaders(op);\n }\n\n private async subscriptionPost<T>(\n op: string,\n path: string,\n body: unknown,\n ): Promise<FacilitatorEnvelope<T>> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(await this.subscriptionAuthHeaders(op)),\n };\n const resp = await this._fetchFn(`${this.url}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(this.toJsonSafe(body)),\n });\n if (!resp.ok) {\n throw new Error(`facilitator ${op} returned HTTP ${resp.status}: ${await resp.text()}`);\n }\n return (await resp.json()) as FacilitatorEnvelope<T>;\n }\n\n private async subscriptionGet<T>(op: string, path: string): Promise<FacilitatorEnvelope<T>> {\n const headers = await this.subscriptionAuthHeaders(op);\n const resp = await this._fetchFn(`${this.url}${path}`, { method: \"GET\", headers });\n if (!resp.ok) {\n throw new Error(`facilitator ${op} returned HTTP ${resp.status}: ${await resp.text()}`);\n }\n return (await resp.json()) as FacilitatorEnvelope<T>;\n }\n\n /**\n * Build the {chainIndex, terms, permit, termsSig, permitSig, syncSettle}\n * request body shared by subscribe / change endpoints.\n */\n private buildWriteBody(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n syncSettle?: boolean,\n ): Record<string, unknown> {\n const inner = asSubscriptionPaymentInner(payload);\n return {\n chainIndex: parseChainIdFromNetwork(requirements.network),\n terms: inner.terms,\n permit: inner.permitSingle,\n termsSig: inner.termsSignature,\n permitSig: inner.permitSingleSignature,\n syncSettle: syncSettle ?? true,\n };\n }\n\n async subscribe(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorSubscribeData>> {\n return this.subscriptionPost<FacilitatorSubscribeData>(\n \"subscribe\",\n \"/api/v6/pay/x402/subscriptions\",\n this.buildWriteBody(paymentPayload, paymentRequirements, syncSettle),\n );\n }\n\n async changeSubscription(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n oldSubId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChangeData>> {\n return this.subscriptionPost<FacilitatorChangeData>(\n \"change\",\n \"/api/v6/pay/x402/subscriptions/change\",\n {\n ...this.buildWriteBody(paymentPayload, paymentRequirements, syncSettle),\n // `oldSubId` is informational — server reads\n // newTerms.changeFromSubId for the authoritative value.\n oldSubId,\n // change body uses `newTerms` not `terms`.\n newTerms: asSubscriptionPaymentInner(paymentPayload).terms,\n terms: undefined,\n },\n );\n }\n\n async cancelSubscription(\n subId: string,\n cancelAuth: CancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelData>> {\n return this.subscriptionPost<FacilitatorCancelData>(\n \"cancel\",\n \"/api/v6/pay/x402/subscriptions/cancel\",\n { subId, cancelAuth, syncSettle: syncSettle ?? true },\n );\n }\n\n async cancelPendingChange(\n subId: string,\n cancelAuth: PendingChangeCancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelPendingData>> {\n return this.subscriptionPost<FacilitatorCancelPendingData>(\n \"cancel-pending-change\",\n \"/api/v6/pay/x402/subscriptions/cancel-pending-change\",\n { subId, cancelAuth, syncSettle: syncSettle ?? true },\n );\n }\n\n async chargeSubscription(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChargeData>> {\n return this.subscriptionPost<FacilitatorChargeData>(\n \"charge\",\n \"/api/v6/pay/x402/subscriptions/charge\",\n { subId, syncSettle: syncSettle ?? true },\n );\n }\n\n async finalizeExpired(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorFinalizeExpiredData>> {\n return this.subscriptionPost<FacilitatorFinalizeExpiredData>(\n \"finalize-expired\",\n \"/api/v6/pay/x402/subscriptions/finalize-expired\",\n { subId, syncSettle: syncSettle ?? true },\n );\n }\n\n async getCharges(\n subId: string,\n limit = 50,\n offset = 0,\n ): Promise<FacilitatorEnvelope<FacilitatorGetChargesData>> {\n const q = new URLSearchParams({ subId, limit: String(limit), offset: String(offset) });\n return this.subscriptionGet<FacilitatorGetChargesData>(\n \"getCharges\",\n `/api/v6/pay/x402/subscriptions/charges?${q.toString()}`,\n );\n }\n\n async getPendingChange(\n subId: string,\n ): Promise<FacilitatorEnvelope<FacilitatorPendingChangeRow | null>> {\n return this.subscriptionGet<FacilitatorPendingChangeRow | null>(\n \"getPendingChange\",\n `/api/v6/pay/x402/subscriptions/pending?subId=${encodeURIComponent(subId)}`,\n );\n }\n\n async getSubscription(\n subId: string,\n ): Promise<FacilitatorEnvelope<FacilitatorGetSubscriptionData>> {\n return this.subscriptionGet<FacilitatorGetSubscriptionData>(\n \"getSubscription\",\n `/api/v6/pay/x402/subscriptions/detail?subId=${encodeURIComponent(subId)}`,\n );\n }\n}\n","import { z } from \"zod\";\n\n// ============================================================================\n// Reusable Primitive Schemas\n// ============================================================================\n\n/**\n * Non-empty string schema - a string with at least one character.\n * Used for required string fields that cannot be empty.\n */\nexport const NonEmptyString = z.string().min(1);\nexport type NonEmptyString = z.infer<typeof NonEmptyString>;\n\n/**\n * Any record schema - an object with unknown keys and values.\n * Used for scheme-specific payloads and other extensible objects.\n */\nexport const Any = z.record(z.unknown());\nexport type Any = z.infer<typeof Any>;\n\n/**\n * Optional any record schema - an optional object with unknown keys and values.\n * Used for optional extension fields like `extra` and `extensions`.\n */\nexport const OptionalAny = z.record(z.unknown()).optional().nullable();\nexport type OptionalAny = z.infer<typeof OptionalAny>;\n\n// ============================================================================\n// Network Schemas\n// ============================================================================\n\n/**\n * Network identifier schema - CAIP-2 format validation.\n * Requires minimum length of 3 and a colon separator (e.g., \"eip155:196\", \"eip155:196\").\n */\nexport const NetworkSchema = z\n .string()\n .min(3)\n .refine(val => val.includes(\":\"), {\n message: \"Network must be in CAIP-2 format (e.g., 'eip155:196')\",\n });\nexport type Network = z.infer<typeof NetworkSchema>;\n\n// ============================================================================\n// Shared Schemas\n// ============================================================================\n\n/**\n * ResourceInfo schema for V2 - describes the protected resource.\n */\nexport const ResourceInfoSchema = z.object({\n url: NonEmptyString,\n description: z.string().optional(),\n mimeType: z.string().optional(),\n});\nexport type ResourceInfo = z.infer<typeof ResourceInfoSchema>;\n\n// ============================================================================\n// Payment Schemas\n// ============================================================================\n\n/**\n * PaymentRequirements schema.\n */\nexport const PaymentRequirementsSchema = z.object({\n scheme: NonEmptyString,\n network: NetworkSchema,\n amount: NonEmptyString,\n asset: NonEmptyString,\n payTo: NonEmptyString,\n maxTimeoutSeconds: z.number().positive(),\n extra: OptionalAny,\n});\nexport type PaymentRequirements = z.infer<typeof PaymentRequirementsSchema>;\n\n/**\n * PaymentRequired (402 response) schema.\n * Contains payment requirements when a resource requires payment.\n */\nexport const PaymentRequiredSchema = z.object({\n x402Version: z.literal(2),\n error: z.string().optional(),\n resource: ResourceInfoSchema,\n accepts: z.array(PaymentRequirementsSchema).min(1),\n extensions: OptionalAny,\n});\nexport type PaymentRequired = z.infer<typeof PaymentRequiredSchema>;\n\n/**\n * PaymentPayload schema.\n * Contains the payment data sent by the client.\n */\nexport const PaymentPayloadSchema = z.object({\n x402Version: z.literal(2),\n resource: ResourceInfoSchema.optional(),\n accepted: PaymentRequirementsSchema,\n payload: Any,\n extensions: OptionalAny,\n});\nexport type PaymentPayload = z.infer<typeof PaymentPayloadSchema>;\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validates a PaymentRequired object (V1 or V2).\n *\n * @param value - The value to validate\n * @returns A result object with success status and data or error\n */\nexport function parsePaymentRequired(\n value: unknown,\n): z.SafeParseReturnType<unknown, PaymentRequired> {\n return PaymentRequiredSchema.safeParse(value);\n}\n\n/**\n * Validates a PaymentRequired object and throws on error.\n *\n * @param value - The value to validate\n * @returns The validated PaymentRequired\n * @throws ZodError if validation fails\n */\nexport function validatePaymentRequired(value: unknown): PaymentRequired {\n return PaymentRequiredSchema.parse(value);\n}\n\n/**\n * Type guard for PaymentRequired (V1 or V2).\n *\n * @param value - The value to check\n * @returns True if the value is a valid PaymentRequired\n */\nexport function isPaymentRequired(value: unknown): value is PaymentRequired {\n return PaymentRequiredSchema.safeParse(value).success;\n}\n\n/**\n * Validates a PaymentRequirements object (V1 or V2).\n *\n * @param value - The value to validate\n * @returns A result object with success status and data or error\n */\nexport function parsePaymentRequirements(\n value: unknown,\n): z.SafeParseReturnType<unknown, PaymentRequirements> {\n return PaymentRequirementsSchema.safeParse(value);\n}\n\n/**\n * Validates a PaymentRequirements object and throws on error.\n *\n * @param value - The value to validate\n * @returns The validated PaymentRequirements\n * @throws ZodError if validation fails\n */\nexport function validatePaymentRequirements(value: unknown): PaymentRequirements {\n return PaymentRequirementsSchema.parse(value);\n}\n\n/**\n * Type guard for PaymentRequirements (V1 or V2).\n *\n * @param value - The value to check\n * @returns True if the value is a valid PaymentRequirements\n */\nexport function isPaymentRequirements(value: unknown): value is PaymentRequirements {\n return PaymentRequirementsSchema.safeParse(value).success;\n}\n\n/**\n * Validates a PaymentPayload object (V1 or V2).\n *\n * @param value - The value to validate\n * @returns A result object with success status and data or error\n */\nexport function parsePaymentPayload(\n value: unknown,\n): z.SafeParseReturnType<unknown, PaymentPayload> {\n return PaymentPayloadSchema.safeParse(value);\n}\n\n/**\n * Validates a PaymentPayload object and throws on error.\n *\n * @param value - The value to validate\n * @returns The validated PaymentPayload\n * @throws ZodError if validation fails\n */\nexport function validatePaymentPayload(value: unknown): PaymentPayload {\n return PaymentPayloadSchema.parse(value);\n}\n\n/**\n * Type guard for PaymentPayload (V1 or V2).\n *\n * @param value - The value to check\n * @returns True if the value is a valid PaymentPayload\n */\nexport function isPaymentPayload(value: unknown): value is PaymentPayload {\n return PaymentPayloadSchema.safeParse(value).success;\n}\n\n// ============================================================================\n// Re-export zod for convenience\n// ============================================================================\n\nexport { z } from \"zod\";\n","import crypto from \"node:crypto\";\nimport type { FacilitatorClient } from \"../http/httpFacilitatorClient.js\";\nimport type {\n FacilitatorCancelData,\n FacilitatorCancelPendingData,\n FacilitatorChangeData,\n FacilitatorChargeData,\n FacilitatorEnvelope,\n FacilitatorFinalizeExpiredData,\n FacilitatorGetChargesData,\n FacilitatorGetSubscriptionData,\n FacilitatorPendingChangeRow,\n FacilitatorSubscribeData,\n} from \"../subscription/facilitator-client.js\";\nimport { parseChainIdFromNetwork } from \"../subscription/codec/typed-data.js\";\nimport { asSubscriptionPaymentInner } from \"../subscription/codec/payload.js\";\nimport type { CancelAuth, PendingChangeCancelAuth } from \"../subscription/types.js\";\nimport type {\n VerifyResponse,\n SettleResponse,\n SettleStatusResponse,\n SupportedResponse,\n} from \"../types/facilitator.js\";\nimport type { PaymentPayload, PaymentRequirements } from \"../types/payments.js\";\n\nexport interface OKXConfig {\n apiKey: string;\n secretKey: string;\n passphrase: string;\n baseUrl?: string;\n /**\n * OKX exact-scheme extension: when true, the settle call tells the facilitator to\n * wait for on-chain confirmation before responding (syncSettle=true in request body).\n * The facilitator then returns status=\"success\" directly (no polling needed).\n * When false (default), the facilitator responds with status=\"pending\" immediately.\n */\n syncSettle?: boolean;\n}\n\n/**\n * OKX facilitator client implementing the FacilitatorClient interface.\n * Uses HMAC-SHA256 signing per OKX REST API authentication spec.\n */\nexport class OKXFacilitatorClient implements FacilitatorClient {\n private config: Required<Omit<OKXConfig, \"syncSettle\">> & Pick<OKXConfig, \"syncSettle\">;\n\n constructor(config: OKXConfig) {\n this.config = {\n baseUrl: \"https://web3.okx.com\",\n ...config,\n };\n }\n\n /**\n *\n * @param method\n * @param path\n * @param body\n */\n private createHeaders(method: string, path: string, body?: string): Record<string, string> {\n const timestamp = new Date().toISOString();\n const prehash = timestamp + method + path + (body ?? \"\");\n const sign = crypto\n .createHmac(\"sha256\", this.config.secretKey)\n .update(prehash)\n .digest(\"base64\");\n\n return {\n \"OK-ACCESS-KEY\": this.config.apiKey,\n \"OK-ACCESS-SIGN\": sign,\n \"OK-ACCESS-TIMESTAMP\": timestamp,\n \"OK-ACCESS-PASSPHRASE\": this.config.passphrase,\n \"Content-Type\": \"application/json\",\n };\n }\n\n /**\n *\n */\n async getSupported(): Promise<SupportedResponse> {\n const path = \"/api/v6/pay/x402/supported\";\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) throw new Error(`OKX getSupported failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n // OKX API wraps responses in { code, data, msg } envelope\n const data = (json.data ?? json) as SupportedResponse;\n return data;\n }\n\n /**\n *\n * @param payload\n * @param requirements\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const path = \"/api/v6/pay/x402/verify\";\n const body = JSON.stringify({\n x402Version: 2,\n paymentPayload: payload,\n paymentRequirements: requirements,\n });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX verify failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n const data = (json.data ?? json) as VerifyResponse;\n return data;\n }\n\n /**\n *\n * @param payload\n * @param requirements\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const path = \"/api/v6/pay/x402/settle\";\n // Include OKX-extension syncSettle field when configured:\n // syncSettle=true → facilitator waits for on-chain confirmation, returns status=\"success\"\n // syncSettle=false → facilitator returns immediately with status=\"pending\" (default)\n const bodyObj: Record<string, unknown> = {\n x402Version: 2,\n paymentPayload: payload,\n paymentRequirements: requirements,\n };\n if (this.config.syncSettle !== undefined) {\n bodyObj.syncSettle = this.config.syncSettle;\n }\n const body = JSON.stringify(bodyObj);\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX settle failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n const data = (json.data ?? json) as SettleResponse;\n return data;\n }\n\n /**\n * Query on-chain settlement status by transaction hash.\n *\n * @param txHash - The transaction hash to query\n * @returns Settlement status response\n */\n async getSettleStatus(txHash: string): Promise<SettleStatusResponse> {\n const path = `/api/v6/pay/x402/settle/status?txHash=${encodeURIComponent(txHash)}`;\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) throw new Error(`OKX getSettleStatus failed: ${res.status}`);\n const json = (await res.json()) as Record<string, unknown>;\n const data = (json.data ?? json) as SettleStatusResponse;\n return data;\n }\n\n // ── SubscriptionFacilitatorClient (period) ─────────────\n //\n // Subscription endpoints share OKX's HMAC-SHA256 auth (createHeaders) so\n // production sellers route ALL facilitator HTTP through this single\n // client — exact/upto/aggr_deferred go via verify/settle, period\n // goes via these five methods.\n\n /**\n * Build `{chainIndex, terms, permit, termsSig, permitSig, syncSettle}` —\n * request body shared by subscribe / change endpoints.\n */\n private buildWriteBody(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n syncSettle?: boolean,\n ): Record<string, unknown> {\n const inner = asSubscriptionPaymentInner(payload);\n return {\n chainIndex: parseChainIdFromNetwork(requirements.network),\n terms: inner.terms,\n permit: inner.permitSingle,\n termsSig: inner.termsSignature,\n permitSig: inner.permitSingleSignature,\n syncSettle: syncSettle ?? true,\n };\n }\n\n async subscribe(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorSubscribeData>> {\n const path = \"/api/v6/pay/x402/subscriptions\";\n const body = JSON.stringify(\n this.buildWriteBody(paymentPayload, paymentRequirements, syncSettle),\n );\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX subscribe failed: ${res.status}`);\n return (await res.json()) as FacilitatorEnvelope<FacilitatorSubscribeData>;\n }\n\n async changeSubscription(\n paymentPayload: PaymentPayload,\n paymentRequirements: PaymentRequirements,\n oldSubId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChangeData>> {\n const path = \"/api/v6/pay/x402/subscriptions/change\";\n const inner = asSubscriptionPaymentInner(paymentPayload);\n const body = JSON.stringify({\n chainIndex: parseChainIdFromNetwork(paymentRequirements.network),\n oldSubId,\n newTerms: inner.terms,\n permit: inner.permitSingle,\n termsSig: inner.termsSignature,\n permitSig: inner.permitSingleSignature,\n syncSettle: syncSettle ?? true,\n });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX changeSubscription failed: ${res.status}`);\n return (await res.json()) as FacilitatorEnvelope<FacilitatorChangeData>;\n }\n\n async cancelSubscription(\n subId: string,\n cancelAuth: CancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelData>> {\n const path = \"/api/v6/pay/x402/subscriptions/cancel\";\n const body = JSON.stringify({ subId, cancelAuth, syncSettle: syncSettle ?? true });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX cancelSubscription failed: ${res.status}`);\n return (await res.json()) as FacilitatorEnvelope<FacilitatorCancelData>;\n }\n\n async cancelPendingChange(\n subId: string,\n cancelAuth: PendingChangeCancelAuth,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorCancelPendingData>> {\n const path = \"/api/v6/pay/x402/subscriptions/cancel-pending-change\";\n const body = JSON.stringify({ subId, cancelAuth, syncSettle: syncSettle ?? true });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) throw new Error(`OKX cancelPendingChange failed: ${res.status}`);\n return (await res.json()) as FacilitatorEnvelope<FacilitatorCancelPendingData>;\n }\n\n async chargeSubscription(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorChargeData>> {\n const path = \"/api/v6/pay/x402/subscriptions/charge\";\n const body = JSON.stringify({ subId, syncSettle: syncSettle ?? true });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\");\n throw new Error(`OKX chargeSubscription failed: ${res.status} ${errBody}`);\n }\n return (await res.json()) as FacilitatorEnvelope<FacilitatorChargeData>;\n }\n\n async finalizeExpired(\n subId: string,\n syncSettle?: boolean,\n ): Promise<FacilitatorEnvelope<FacilitatorFinalizeExpiredData>> {\n const path = \"/api/v6/pay/x402/subscriptions/finalize-expired\";\n const body = JSON.stringify({ subId, syncSettle: syncSettle ?? true });\n const res = await fetch(this.config.baseUrl + path, {\n method: \"POST\",\n headers: this.createHeaders(\"POST\", path, body),\n body,\n });\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\");\n throw new Error(`OKX finalizeExpired failed: ${res.status} ${errBody}`);\n }\n return (await res.json()) as FacilitatorEnvelope<FacilitatorFinalizeExpiredData>;\n }\n\n async getCharges(\n subId: string,\n limit = 50,\n offset = 0,\n ): Promise<FacilitatorEnvelope<FacilitatorGetChargesData>> {\n const q = new URLSearchParams({ subId, limit: String(limit), offset: String(offset) });\n const path = `/api/v6/pay/x402/subscriptions/charges?${q.toString()}`;\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\");\n throw new Error(`OKX getCharges failed: ${res.status} ${errBody}`);\n }\n return (await res.json()) as FacilitatorEnvelope<FacilitatorGetChargesData>;\n }\n\n async getPendingChange(\n subId: string,\n ): Promise<FacilitatorEnvelope<FacilitatorPendingChangeRow | null>> {\n const path = `/api/v6/pay/x402/subscriptions/pending?subId=${encodeURIComponent(subId)}`;\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) {\n const errBody = await res.text().catch(() => \"\");\n throw new Error(`OKX getPendingChange failed: ${res.status} ${errBody}`);\n }\n return (await res.json()) as FacilitatorEnvelope<FacilitatorPendingChangeRow | null>;\n }\n\n async getSubscription(\n subId: string,\n ): Promise<FacilitatorEnvelope<FacilitatorGetSubscriptionData>> {\n const path = `/api/v6/pay/x402/subscriptions/detail?subId=${encodeURIComponent(subId)}`;\n const res = await fetch(this.config.baseUrl + path, {\n headers: this.createHeaders(\"GET\", path),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`OKX getSubscription failed: ${res.status} ${body}`);\n }\n return (await res.json()) as FacilitatorEnvelope<FacilitatorGetSubscriptionData>;\n }\n}\n","export const x402Version = 2;\nexport { OKXFacilitatorClient } from \"./facilitator/OKXFacilitatorClient\";\nexport type { OKXConfig } from \"./facilitator/OKXFacilitatorClient\";","import {\n SettleError,\n SettleResponse,\n SettleStatusResponse,\n VerifyResponse,\n SupportedResponse,\n SupportedKind,\n} from \"../types/facilitator\";\nimport {\n PaymentPayload,\n PaymentRequirements,\n PaymentRequired,\n ResourceInfo,\n} from \"../types/payments\";\nimport { SchemeNetworkServer } from \"../types/mechanisms\";\nimport { Price, Network, ResourceServerExtension, VerifyError } from \"../types\";\nimport { deepEqual, findByNetworkAndScheme } from \"../utils\";\nimport { FacilitatorClient, HTTPFacilitatorClient } from \"../http/httpFacilitatorClient\";\nimport { x402Version } from \"..\";\n\n/** Default poll interval for settle/status queries (1 second). */\nexport const DEFAULT_POLL_INTERVAL_MS = 1_000;\n\n/** Default poll deadline for settle/status queries (5 seconds). */\nexport const DEFAULT_POLL_DEADLINE_MS = 5_000;\n\n/** Result of polling `GET /settle/status`. */\nexport type PollResult = \"success\" | \"failed\" | \"timeout\";\n\n/**\n * Configuration for a protected resource\n * Only contains payment-specific configuration, not resource metadata\n */\nexport interface ResourceConfig {\n scheme: string;\n payTo: string; // Payment recipient address\n price: Price;\n network: Network;\n maxTimeoutSeconds?: number;\n extra?: Record<string, unknown>; // Scheme-specific additional data\n}\n\n/**\n * Lifecycle Hook Context Interfaces\n */\n\nexport interface PaymentRequiredContext {\n requirements: PaymentRequirements[];\n resourceInfo: ResourceInfo;\n error?: string;\n paymentRequiredResponse: PaymentRequired;\n transportContext?: unknown;\n}\n\nexport interface VerifyContext {\n paymentPayload: PaymentPayload;\n requirements: PaymentRequirements;\n}\n\nexport interface VerifyResultContext extends VerifyContext {\n result: VerifyResponse;\n}\n\nexport interface VerifyFailureContext extends VerifyContext {\n error: Error;\n}\n\nexport interface SettleContext {\n paymentPayload: PaymentPayload;\n requirements: PaymentRequirements;\n}\n\nexport interface SettleResultContext extends SettleContext {\n result: SettleResponse;\n transportContext?: unknown;\n}\n\nexport interface SettleFailureContext extends SettleContext {\n error: Error;\n}\n\n/**\n * Lifecycle Hook Type Definitions\n */\n\nexport type BeforeVerifyHook = (\n context: VerifyContext,\n) => Promise<void | { abort: true; reason: string; message?: string }>;\n\nexport type AfterVerifyHook = (context: VerifyResultContext) => Promise<void>;\n\nexport type OnVerifyFailureHook = (\n context: VerifyFailureContext,\n) => Promise<void | { recovered: true; result: VerifyResponse }>;\n\nexport type BeforeSettleHook = (\n context: SettleContext,\n) => Promise<void | { abort: true; reason: string; message?: string }>;\n\nexport type AfterSettleHook = (context: SettleResultContext) => Promise<void>;\n\nexport type OnSettleFailureHook = (\n context: SettleFailureContext,\n) => Promise<void | { recovered: true; result: SettleResponse }>;\n\n/**\n * Optional overrides for settlement parameters.\n * Used to support partial settlement (e.g., upto scheme billing by actual usage).\n *\n * Note: Overriding the amount to a value different from the agreed-upon\n * `PaymentRequirements.amount` is only valid in schemes that explicitly support\n * partial settlement, such as the `upto` scheme. Using this with standard\n * x402 schemes (e.g., `exact`) will likely cause settlement verification to fail.\n */\nexport interface SettlementOverrides {\n /**\n * Amount to settle. Supports three formats:\n *\n * - **Raw atomic units** — e.g., `\"1000\"` settles exactly 1000 atomic units.\n * - **Percent** — e.g., `\"50%\"` settles 50% of `PaymentRequirements.amount`.\n * Supports up to two decimal places (e.g., `\"33.33%\"`). The result is floored\n * to the nearest atomic unit.\n * - **Dollar price** — e.g., `\"$0.05\"` converts a USD-denominated price to\n * atomic units. Uses `PaymentRequirements.extra.decimals` if set; otherwise\n * defaults to 6 (standard for USDC stablecoins). The result is rounded to\n * the nearest atomic unit.\n *\n * The resolved amount must be <= the authorized maximum in `PaymentRequirements`.\n *\n * Note: Setting this to an amount other than `PaymentRequirements.amount` is\n * only valid in schemes that support partial settlement, such as `upto`.\n */\n amount?: string;\n}\n\n/**\n * Resolves a settlement override amount string to a final atomic-unit string.\n *\n * Supports three input formats (see {@link SettlementOverrides.amount}):\n * - Raw atomic units: `\"1000\"`\n * - Percent of `PaymentRequirements.amount`: `\"50%\"`\n * - Dollar price: `\"$0.05\"` (uses `requirements.extra.decimals` or defaults to 6)\n *\n * @param rawAmount - The override amount string (e.g., `\"1000\"`, `\"50%\"`, `\"$0.05\"`)\n * @param requirements - The payment requirements containing the base amount and token decimals\n * @returns The resolved amount as an atomic-unit string\n */\nexport function resolveSettlementOverrideAmount(\n rawAmount: string,\n requirements: PaymentRequirements,\n): string {\n // Percent format: \"50%\" or \"33.33%\"\n const percentMatch = rawAmount.match(/^(\\d+(?:\\.\\d{0,2})?)%$/);\n if (percentMatch) {\n const [intPart, decPart = \"\"] = percentMatch[1].split(\".\");\n const scaledPercent = BigInt(intPart) * 100n + BigInt(decPart.padEnd(2, \"0\").slice(0, 2));\n const base = BigInt(requirements.amount);\n return ((base * scaledPercent) / 10000n).toString();\n }\n\n // Dollar price format: \"$0.05\"\n const dollarMatch = rawAmount.match(/^\\$(\\d+(?:\\.\\d+)?)$/);\n if (dollarMatch) {\n const decimals =\n typeof requirements.extra?.decimals === \"number\" ? requirements.extra.decimals : 6;\n const dollars = parseFloat(dollarMatch[1]);\n return Math.round(dollars * 10 ** decimals).toString();\n }\n\n // Raw atomic units (existing behavior)\n return rawAmount;\n}\n\n/**\n * Core x402 protocol server for resource protection\n * Transport-agnostic implementation of the x402 payment protocol\n */\nexport class x402ResourceServer {\n private facilitatorClients: FacilitatorClient[];\n private registeredServerSchemes: Map<string, Map<string, SchemeNetworkServer>> = new Map();\n private supportedResponsesMap: Map<number, Map<string, Map<string, SupportedResponse>>> =\n new Map();\n private facilitatorClientsMap: Map<number, Map<string, Map<string, FacilitatorClient>>> =\n new Map();\n private registeredExtensions: Map<string, ResourceServerExtension> = new Map();\n\n private beforeVerifyHooks: BeforeVerifyHook[] = [];\n private afterVerifyHooks: AfterVerifyHook[] = [];\n private onVerifyFailureHooks: OnVerifyFailureHook[] = [];\n private beforeSettleHooks: BeforeSettleHook[] = [];\n private afterSettleHooks: AfterSettleHook[] = [];\n private onSettleFailureHooks: OnSettleFailureHook[] = [];\n\n /**\n * Creates a new x402ResourceServer instance.\n *\n * @param facilitatorClients - Optional facilitator client(s) for payment processing\n */\n constructor(facilitatorClients?: FacilitatorClient | FacilitatorClient[]) {\n // Normalize facilitator clients to array\n if (!facilitatorClients) {\n // No clients provided, create a default HTTP client\n this.facilitatorClients = [new HTTPFacilitatorClient()];\n } else if (Array.isArray(facilitatorClients)) {\n // Array of clients provided\n this.facilitatorClients =\n facilitatorClients.length > 0 ? facilitatorClients : [new HTTPFacilitatorClient()];\n } else {\n // Single client provided\n this.facilitatorClients = [facilitatorClients];\n }\n }\n\n /**\n * Register a scheme/network server implementation.\n *\n * @param network - The network identifier\n * @param server - The scheme/network server implementation\n * @returns The x402ResourceServer instance for chaining\n */\n register(network: Network, server: SchemeNetworkServer): x402ResourceServer {\n if (!this.registeredServerSchemes.has(network)) {\n this.registeredServerSchemes.set(network, new Map());\n }\n\n const serverByScheme = this.registeredServerSchemes.get(network)!;\n if (!serverByScheme.has(server.scheme)) {\n serverByScheme.set(server.scheme, server);\n }\n\n return this;\n }\n\n /**\n * Check if a scheme is registered for a given network.\n *\n * @param network - The network identifier\n * @param scheme - The payment scheme name\n * @returns True if the scheme is registered for the network, false otherwise\n */\n hasRegisteredScheme(network: Network, scheme: string): boolean {\n return !!findByNetworkAndScheme(this.registeredServerSchemes, scheme, network);\n }\n\n /**\n * Look up the registered SchemeNetworkServer for a given network + scheme.\n * Exposed so the HTTP dispatch layer can perform capability detection\n * (e.g. `hasSubscriptionCapability(scheme)`) on the actual instance.\n *\n * Pattern matching follows the same CAIP-style rules as `verifyPayment`:\n * registered keys may use wildcards like `eip155:*`.\n *\n * @param network - The network identifier\n * @param scheme - The payment scheme name\n * @returns The registered scheme server, or undefined if none matches.\n */\n findScheme(network: Network, scheme: string): SchemeNetworkServer | undefined {\n return findByNetworkAndScheme(this.registeredServerSchemes, scheme, network);\n }\n\n /**\n * Registers a resource service extension that can enrich extension declarations.\n *\n * @param extension - The extension to register\n * @returns The x402ResourceServer instance for chaining\n */\n registerExtension(extension: ResourceServerExtension): this {\n this.registeredExtensions.set(extension.key, extension);\n return this;\n }\n\n /**\n * Check if an extension is registered.\n *\n * @param key - The extension key\n * @returns True if the extension is registered\n */\n hasExtension(key: string): boolean {\n return this.registeredExtensions.has(key);\n }\n\n /**\n * Get all registered extensions.\n *\n * @returns Array of registered extensions\n */\n getExtensions(): ResourceServerExtension[] {\n return Array.from(this.registeredExtensions.values());\n }\n\n /**\n * Enriches declared extensions using registered extension hooks.\n *\n * @param declaredExtensions - Extensions declared on the route\n * @param transportContext - Transport-specific context (HTTP, A2A, MCP, etc.)\n * @returns Enriched extensions map\n */\n enrichExtensions(\n declaredExtensions: Record<string, unknown>,\n transportContext: unknown,\n ): Record<string, unknown> {\n const enriched: Record<string, unknown> = {};\n\n for (const [key, declaration] of Object.entries(declaredExtensions)) {\n const extension = this.registeredExtensions.get(key);\n\n if (extension?.enrichDeclaration) {\n enriched[key] = extension.enrichDeclaration(declaration, transportContext);\n } else {\n enriched[key] = declaration;\n }\n }\n\n return enriched;\n }\n\n /**\n * Register a hook to execute before payment verification.\n * Can abort verification by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onBeforeVerify(hook: BeforeVerifyHook): x402ResourceServer {\n this.beforeVerifyHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment verification.\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onAfterVerify(hook: AfterVerifyHook): x402ResourceServer {\n this.afterVerifyHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment verification fails.\n * Can recover from failure by returning { recovered: true, result: VerifyResponse }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onVerifyFailure(hook: OnVerifyFailureHook): x402ResourceServer {\n this.onVerifyFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute before payment settlement.\n * Can abort settlement by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onBeforeSettle(hook: BeforeSettleHook): x402ResourceServer {\n this.beforeSettleHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment settlement.\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onAfterSettle(hook: AfterSettleHook): x402ResourceServer {\n this.afterSettleHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment settlement fails.\n * Can recover from failure by returning { recovered: true, result: SettleResponse }\n *\n * @param hook - The hook function to register\n * @returns The x402ResourceServer instance for chaining\n */\n onSettleFailure(hook: OnSettleFailureHook): x402ResourceServer {\n this.onSettleFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Initialize by fetching supported kinds from all facilitators\n * Creates mappings for supported responses and facilitator clients\n * Earlier facilitators in the array get precedence\n */\n async initialize(): Promise<void> {\n // Clear existing mappings\n this.supportedResponsesMap.clear();\n this.facilitatorClientsMap.clear();\n let lastError: Error | undefined;\n\n // Fetch supported kinds from all facilitator clients\n // Process in order to give precedence to earlier facilitators\n for (const facilitatorClient of this.facilitatorClients) {\n try {\n const supported = await facilitatorClient.getSupported();\n\n // Process each supported kind (now flat array with version in each element)\n for (const kind of supported.kinds) {\n const x402Version = kind.x402Version;\n\n // Get or create version map for supported responses\n if (!this.supportedResponsesMap.has(x402Version)) {\n this.supportedResponsesMap.set(x402Version, new Map());\n }\n const responseVersionMap = this.supportedResponsesMap.get(x402Version)!;\n\n // Get or create version map for facilitator clients\n if (!this.facilitatorClientsMap.has(x402Version)) {\n this.facilitatorClientsMap.set(x402Version, new Map());\n }\n const clientVersionMap = this.facilitatorClientsMap.get(x402Version)!;\n\n // Get or create network map for responses\n if (!responseVersionMap.has(kind.network)) {\n responseVersionMap.set(kind.network, new Map());\n }\n const responseNetworkMap = responseVersionMap.get(kind.network)!;\n\n // Get or create network map for clients\n if (!clientVersionMap.has(kind.network)) {\n clientVersionMap.set(kind.network, new Map());\n }\n const clientNetworkMap = clientVersionMap.get(kind.network)!;\n\n // Only store if not already present (gives precedence to earlier facilitators)\n if (!responseNetworkMap.has(kind.scheme)) {\n responseNetworkMap.set(kind.scheme, supported);\n clientNetworkMap.set(kind.scheme, facilitatorClient);\n }\n }\n } catch (error) {\n lastError = error as Error;\n // Log error but continue with other facilitators\n console.warn(`Failed to fetch supported kinds from facilitator: ${error}`);\n }\n }\n\n if (this.supportedResponsesMap.size === 0) {\n throw lastError\n ? new Error(\n \"Failed to initialize: no supported payment kinds loaded from any facilitator.\",\n {\n cause: lastError,\n },\n )\n : new Error(\n \"Failed to initialize: no supported payment kinds loaded from any facilitator.\",\n );\n }\n }\n\n /**\n * Get supported kind for a specific version, network, and scheme\n *\n * @param x402Version - The x402 version\n * @param network - The network identifier\n * @param scheme - The payment scheme\n * @returns The supported kind or undefined if not found\n */\n getSupportedKind(\n x402Version: number,\n network: Network,\n scheme: string,\n ): SupportedKind | undefined {\n const versionMap = this.supportedResponsesMap.get(x402Version);\n if (!versionMap) return undefined;\n\n const supportedResponse = findByNetworkAndScheme(versionMap, scheme, network);\n if (!supportedResponse) return undefined;\n\n // Find the specific kind from the response (kinds are flat array with version in each element)\n return supportedResponse.kinds.find(\n kind =>\n kind.x402Version === x402Version && kind.network === network && kind.scheme === scheme,\n );\n }\n\n /**\n * Get facilitator extensions for a specific version, network, and scheme\n *\n * @param x402Version - The x402 version\n * @param network - The network identifier\n * @param scheme - The payment scheme\n * @returns The facilitator extensions or empty array if not found\n */\n getFacilitatorExtensions(x402Version: number, network: Network, scheme: string): string[] {\n const versionMap = this.supportedResponsesMap.get(x402Version);\n if (!versionMap) return [];\n\n const supportedResponse = findByNetworkAndScheme(versionMap, scheme, network);\n return supportedResponse?.extensions || [];\n }\n\n /**\n * Build payment requirements for a protected resource\n *\n * @param resourceConfig - Configuration for the protected resource\n * @returns Array of payment requirements\n */\n async buildPaymentRequirements(resourceConfig: ResourceConfig): Promise<PaymentRequirements[]> {\n const requirements: PaymentRequirements[] = [];\n\n // Find the matching server implementation\n const scheme = resourceConfig.scheme;\n const SchemeNetworkServer = findByNetworkAndScheme(\n this.registeredServerSchemes,\n scheme,\n resourceConfig.network,\n );\n\n if (!SchemeNetworkServer) {\n // Fallback to placeholder implementation if no server registered\n // TODO: Remove this fallback once implementations are registered\n console.warn(\n `No server implementation registered for scheme: ${scheme}, network: ${resourceConfig.network}`,\n );\n return requirements;\n }\n\n // Find the matching supported kind from facilitator\n const supportedKind = this.getSupportedKind(\n x402Version,\n resourceConfig.network,\n SchemeNetworkServer.scheme,\n );\n\n if (!supportedKind) {\n throw new Error(\n `Facilitator does not support ${SchemeNetworkServer.scheme} on ${resourceConfig.network}. ` +\n `Make sure to call initialize() to fetch supported kinds from facilitators.`,\n );\n }\n\n // Get facilitator extensions for this combination\n const facilitatorExtensions = this.getFacilitatorExtensions(\n x402Version,\n resourceConfig.network,\n SchemeNetworkServer.scheme,\n );\n\n // Parse the price using the scheme's price parser\n const parsedPrice = await SchemeNetworkServer.parsePrice(\n resourceConfig.price,\n resourceConfig.network,\n );\n\n // Build base payment requirements from resource config\n const baseRequirements: PaymentRequirements = {\n scheme: SchemeNetworkServer.scheme,\n network: resourceConfig.network,\n amount: parsedPrice.amount,\n asset: parsedPrice.asset,\n payTo: resourceConfig.payTo,\n maxTimeoutSeconds: resourceConfig.maxTimeoutSeconds || 300, // Default 5 minutes\n extra: {\n ...parsedPrice.extra,\n ...resourceConfig.extra, // Merge user-provided extra\n },\n };\n\n // Delegate to the implementation for scheme-specific enhancements\n // Note: enhancePaymentRequirements expects x402Version in the kind, so we add it back\n const requirement = await SchemeNetworkServer.enhancePaymentRequirements(\n baseRequirements,\n {\n ...supportedKind,\n x402Version,\n },\n facilitatorExtensions,\n );\n\n requirements.push(requirement);\n return requirements;\n }\n\n /**\n * Build payment requirements from multiple payment options\n * This method handles resolving dynamic payTo/price functions and builds requirements for each option\n *\n * @param paymentOptions - Array of payment options to convert\n * @param context - HTTP request context for resolving dynamic functions\n * @returns Array of payment requirements (one per option)\n */\n async buildPaymentRequirementsFromOptions<TContext = unknown>(\n paymentOptions: Array<{\n scheme: string;\n payTo: string | ((context: TContext) => string | Promise<string>);\n price: Price | ((context: TContext) => Price | Promise<Price>);\n network: Network;\n maxTimeoutSeconds?: number;\n extra?: Record<string, unknown>;\n }>,\n context: TContext,\n ): Promise<PaymentRequirements[]> {\n const allRequirements: PaymentRequirements[] = [];\n\n for (const option of paymentOptions) {\n // Resolve dynamic payTo and price if they are functions\n const resolvedPayTo =\n typeof option.payTo === \"function\" ? await option.payTo(context) : option.payTo;\n const resolvedPrice =\n typeof option.price === \"function\" ? await option.price(context) : option.price;\n\n const resourceConfig: ResourceConfig = {\n scheme: option.scheme,\n payTo: resolvedPayTo,\n price: resolvedPrice,\n network: option.network,\n maxTimeoutSeconds: option.maxTimeoutSeconds,\n extra: option.extra,\n };\n\n // Use existing buildPaymentRequirements for each option\n const requirements = await this.buildPaymentRequirements(resourceConfig);\n allRequirements.push(...requirements);\n }\n\n return allRequirements;\n }\n\n /**\n * Create a payment required response\n *\n * @param requirements - Payment requirements\n * @param resourceInfo - Resource information\n * @param error - Error message\n * @param extensions - Optional declared extensions (for per-key enrichment)\n * @param transportContext - Optional transport-specific context (e.g., HTTP request, MCP tool context)\n * @returns Payment required response object\n */\n async createPaymentRequiredResponse(\n requirements: PaymentRequirements[],\n resourceInfo: ResourceInfo,\n error?: string,\n extensions?: Record<string, unknown>,\n transportContext?: unknown,\n ): Promise<PaymentRequired> {\n // V2 response with resource at top level\n let response: PaymentRequired = {\n x402Version: 2,\n error,\n resource: resourceInfo,\n accepts: requirements as PaymentRequirements[],\n };\n\n // Add extensions if provided\n if (extensions && Object.keys(extensions).length > 0) {\n response.extensions = extensions;\n }\n\n // Let declared extensions add data to PaymentRequired response\n if (extensions) {\n for (const [key, declaration] of Object.entries(extensions)) {\n const extension = this.registeredExtensions.get(key);\n if (extension?.enrichPaymentRequiredResponse) {\n try {\n const context: PaymentRequiredContext = {\n requirements,\n resourceInfo,\n error,\n paymentRequiredResponse: response,\n transportContext,\n };\n const extensionData = await extension.enrichPaymentRequiredResponse(\n declaration,\n context,\n );\n if (extensionData !== undefined) {\n if (!response.extensions) {\n response.extensions = {};\n }\n response.extensions[key] = extensionData;\n }\n } catch (error) {\n console.error(\n `Error in enrichPaymentRequiredResponse hook for extension ${key}:`,\n error,\n );\n }\n }\n }\n }\n\n return response;\n }\n\n /**\n * Verify a payment against requirements\n *\n * @param paymentPayload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Verification response\n */\n async verifyPayment(\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const context: VerifyContext = {\n paymentPayload,\n requirements,\n };\n\n // Execute beforeVerify hooks\n for (const hook of this.beforeVerifyHooks) {\n try {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n return {\n isValid: false,\n invalidReason: result.reason,\n invalidMessage: result.message,\n };\n }\n } catch (error) {\n throw new VerifyError(400, {\n isValid: false,\n invalidReason: \"before_verify_hook_error\",\n invalidMessage: error instanceof Error ? error.message : \"\",\n });\n }\n }\n\n try {\n // Find the facilitator that supports this payment type\n const facilitatorClient = this.getFacilitatorClient(\n paymentPayload.x402Version,\n requirements.network,\n requirements.scheme,\n );\n\n let verifyResult: VerifyResponse;\n\n if (!facilitatorClient) {\n // Fallback: try all facilitators if no specific support found\n let lastError: Error | undefined;\n\n for (const client of this.facilitatorClients) {\n try {\n verifyResult = await client.verify(paymentPayload, requirements);\n break;\n } catch (error) {\n lastError = error as Error;\n }\n }\n\n if (!verifyResult!) {\n throw (\n lastError ||\n new Error(\n `No facilitator supports ${requirements.scheme} on ${requirements.network} for v${paymentPayload.x402Version}`,\n )\n );\n }\n } else {\n // Use the specific facilitator that supports this payment\n verifyResult = await facilitatorClient.verify(paymentPayload, requirements);\n }\n\n // Execute afterVerify hooks\n const resultContext: VerifyResultContext = {\n ...context,\n result: verifyResult,\n };\n\n for (const hook of this.afterVerifyHooks) {\n await hook(resultContext);\n }\n\n return verifyResult;\n } catch (error) {\n const failureContext: VerifyFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onVerifyFailure hooks\n for (const hook of this.onVerifyFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.result;\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Settle a verified payment\n *\n * @param paymentPayload - The payment payload to settle\n * @param requirements - The payment requirements\n * @param declaredExtensions - Optional declared extensions (for per-key enrichment)\n * @param transportContext - Optional transport-specific context (e.g., HTTP request/response, MCP tool context)\n * @param settlementOverrides - Optional overrides for settlement parameters (e.g., partial settlement amount)\n * @returns Settlement response\n */\n async settlePayment(\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n declaredExtensions?: Record<string, unknown>,\n transportContext?: unknown,\n settlementOverrides?: SettlementOverrides,\n ): Promise<SettleResponse> {\n // Apply settlement overrides (e.g., partial settlement for upto scheme)\n let effectiveRequirements = requirements;\n if (settlementOverrides?.amount !== undefined) {\n effectiveRequirements = {\n ...requirements,\n amount: resolveSettlementOverrideAmount(settlementOverrides.amount, requirements),\n };\n }\n\n const context: SettleContext = {\n paymentPayload,\n requirements: effectiveRequirements,\n };\n\n // Execute beforeSettle hooks\n for (const hook of this.beforeSettleHooks) {\n try {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n throw new SettleError(400, {\n success: false,\n errorReason: result.reason,\n errorMessage: result.message,\n transaction: \"\",\n network: requirements.network,\n });\n }\n } catch (error) {\n if (error instanceof SettleError) {\n throw error;\n }\n throw new SettleError(400, {\n success: false,\n errorReason: \"before_settle_hook_error\",\n errorMessage: error instanceof Error ? error.message : \"\",\n transaction: \"\",\n network: requirements.network,\n });\n }\n }\n\n try {\n // Find the facilitator that supports this payment type\n const facilitatorClient = this.getFacilitatorClient(\n paymentPayload.x402Version,\n effectiveRequirements.network,\n effectiveRequirements.scheme,\n );\n\n let settleResult: SettleResponse;\n\n if (!facilitatorClient) {\n // Fallback: try all facilitators if no specific support found\n let lastError: Error | undefined;\n\n for (const client of this.facilitatorClients) {\n try {\n settleResult = await client.settle(paymentPayload, effectiveRequirements);\n break;\n } catch (error) {\n lastError = error as Error;\n }\n }\n\n if (!settleResult!) {\n throw (\n lastError ||\n new Error(\n `No facilitator supports ${effectiveRequirements.scheme} on ${effectiveRequirements.network} for v${paymentPayload.x402Version}`,\n )\n );\n }\n } else {\n // Use the specific facilitator that supports this payment\n settleResult = await facilitatorClient.settle(paymentPayload, effectiveRequirements);\n }\n\n // Execute afterSettle hooks\n const resultContext: SettleResultContext = {\n ...context,\n result: settleResult,\n transportContext,\n };\n\n for (const hook of this.afterSettleHooks) {\n await hook(resultContext);\n }\n\n // Let declared extensions add data to settlement response\n if (declaredExtensions) {\n for (const [key, declaration] of Object.entries(declaredExtensions)) {\n const extension = this.registeredExtensions.get(key);\n if (extension?.enrichSettlementResponse) {\n try {\n const extensionData = await extension.enrichSettlementResponse(\n declaration,\n resultContext,\n );\n if (extensionData !== undefined) {\n if (!settleResult.extensions) {\n settleResult.extensions = {};\n }\n settleResult.extensions[key] = extensionData;\n }\n } catch (error) {\n console.error(`Error in enrichSettlementResponse hook for extension ${key}:`, error);\n }\n }\n }\n }\n\n return settleResult;\n } catch (error) {\n const failureContext: SettleFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onSettleFailure hooks\n for (const hook of this.onSettleFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.result;\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Find matching payment requirements for a payment\n *\n * @param availableRequirements - Array of available payment requirements\n * @param paymentPayload - The payment payload\n * @returns Matching payment requirements or undefined\n */\n findMatchingRequirements(\n availableRequirements: PaymentRequirements[],\n paymentPayload: PaymentPayload,\n ): PaymentRequirements | undefined {\n // Match by accepted requirements.\n // Per OKX spec, buyers may inject scheme-specific fields into accepted.extra\n // (e.g., sessionCert for aggr_deferred) that are not present in the server's\n // original PaymentRequirements. We use a superset check: all server-declared\n // fields must match, but accepted.extra may contain additional buyer fields.\n return availableRequirements.find(serverReq => {\n const { extra: serverExtra, ...serverBase } = serverReq;\n const { extra: buyerExtra, ...buyerBase } = paymentPayload.accepted ?? {};\n if (!deepEqual(serverBase, buyerBase)) return false;\n // Both have no extra — match\n if (!serverExtra && !buyerExtra) return true;\n // Server has no extra requirements — buyer may add whatever it wants\n if (!serverExtra) return true;\n // Server requires extra but buyer provided none — no match\n if (!buyerExtra) return false;\n // All server-required extra fields must match in buyer's accepted.extra\n for (const [key, value] of Object.entries(serverExtra)) {\n if (!deepEqual((buyerExtra as Record<string, unknown>)[key], value)) return false;\n }\n return true;\n });\n }\n\n /**\n * Process a payment request\n *\n * @param paymentPayload - Optional payment payload if provided\n * @param resourceConfig - Configuration for the protected resource\n * @param resourceInfo - Information about the resource being accessed\n * @param extensions - Optional extensions to include in the response\n * @returns Processing result\n */\n async processPaymentRequest(\n paymentPayload: PaymentPayload | null,\n resourceConfig: ResourceConfig,\n resourceInfo: ResourceInfo,\n extensions?: Record<string, unknown>,\n ): Promise<{\n success: boolean;\n requiresPayment?: PaymentRequired;\n verificationResult?: VerifyResponse;\n settlementResult?: SettleResponse;\n error?: string;\n }> {\n const requirements = await this.buildPaymentRequirements(resourceConfig);\n\n if (!paymentPayload) {\n return {\n success: false,\n requiresPayment: await this.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n \"Payment required\",\n extensions,\n ),\n };\n }\n\n // Find matching requirements\n const matchingRequirements = this.findMatchingRequirements(requirements, paymentPayload);\n if (!matchingRequirements) {\n return {\n success: false,\n requiresPayment: await this.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n \"No matching payment requirements found\",\n extensions,\n ),\n };\n }\n\n // Verify payment\n const verificationResult = await this.verifyPayment(paymentPayload, matchingRequirements);\n if (!verificationResult.isValid) {\n return {\n success: false,\n error: verificationResult.invalidReason,\n verificationResult,\n };\n }\n\n // Payment verified, ready for settlement\n return {\n success: true,\n verificationResult,\n };\n }\n\n /**\n * Poll `GET /settle/status` until a terminal state is reached or deadline expires.\n *\n * Used when settle returns `status=\"timeout\"` (exact + syncSettle=true).\n * Mirrors Rust: `X402ResourceServer::poll_settle_status`.\n *\n * @param txHash - Transaction hash to query\n * @param paymentPayload - The payment payload (used to find the correct facilitator client)\n * @param requirements - The payment requirements (used to find the correct facilitator client)\n * @param pollDeadlineMs - Max time to poll in ms (default 5000)\n * @returns Poll result: \"success\", \"failed\", or \"timeout\"\n */\n async pollSettleStatus(\n txHash: string,\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n pollDeadlineMs: number = DEFAULT_POLL_DEADLINE_MS,\n ): Promise<PollResult> {\n const facilitatorClient =\n this.getFacilitatorClient(\n paymentPayload.x402Version,\n requirements.network,\n requirements.scheme,\n ) ?? this.facilitatorClients[0];\n\n if (!facilitatorClient?.getSettleStatus) {\n return \"timeout\";\n }\n\n const deadline = Date.now() + pollDeadlineMs;\n\n while (Date.now() < deadline) {\n try {\n const resp: SettleStatusResponse = await facilitatorClient.getSettleStatus(txHash);\n if (!resp.success) {\n return \"failed\";\n }\n if (resp.status === \"success\") {\n return \"success\";\n }\n // status=\"pending\" or unknown → continue polling\n } catch {\n // API error → continue polling if still within deadline\n }\n\n // Wait before next poll, but don't exceed deadline\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await new Promise(resolve =>\n setTimeout(resolve, Math.min(DEFAULT_POLL_INTERVAL_MS, remaining)),\n );\n }\n return \"timeout\";\n }\n\n /**\n * Get facilitator client for a specific version, network, and scheme\n *\n * @param x402Version - The x402 version\n * @param network - The network identifier\n * @param scheme - The payment scheme\n * @returns The facilitator client or undefined if not found\n */\n private getFacilitatorClient(\n x402Version: number,\n network: Network,\n scheme: string,\n ): FacilitatorClient | undefined {\n const versionMap = this.facilitatorClientsMap.get(x402Version);\n if (!versionMap) return undefined;\n\n // Use findByNetworkAndScheme for pattern matching\n return findByNetworkAndScheme(versionMap, scheme, network);\n }\n}\n\nexport default x402ResourceServer;\n","import { x402ResourceServer, SettlementOverrides, DEFAULT_POLL_DEADLINE_MS } from \"../server\";\nimport {\n decodePaymentSignatureHeader,\n encodePaymentRequiredHeader,\n encodePaymentResponseHeader,\n} from \".\";\nimport {\n PaymentPayload,\n PaymentRequired,\n SettleResponse,\n SettleError,\n FacilitatorResponseError,\n Price,\n Network,\n PaymentRequirements,\n} from \"../types\";\nimport { x402Version } from \"..\";\nimport type { SubscriptionCapability } from \"../subscription\";\n\nexport const SETTLEMENT_OVERRIDES_HEADER = \"settlement-overrides\";\n\n/**\n * Framework-agnostic HTTP adapter interface\n * Implementations provide framework-specific HTTP operations\n */\nexport interface HTTPAdapter {\n getHeader(name: string): string | undefined;\n getMethod(): string;\n getPath(): string;\n getUrl(): string;\n getAcceptHeader(): string;\n getUserAgent(): string;\n\n /**\n * Return the full request headers as a plain lowercase-keyed record.\n * Optional; adapters that don't implement it cause hooks like\n * `onBeforeAccess` to receive an empty headers map.\n */\n getHeaders?(): Record<string, string>;\n\n /**\n * Get query parameters from the request URL\n *\n * @returns Record of query parameter key-value pairs\n */\n getQueryParams?(): Record<string, string | string[]>;\n\n /**\n * Get a specific query parameter by name\n *\n * @param name - The query parameter name\n * @returns The query parameter value(s) or undefined\n */\n getQueryParam?(name: string): string | string[] | undefined;\n\n /**\n * Get the parsed request body\n * Framework adapters should parse JSON/form data appropriately\n *\n * @returns The parsed request body\n */\n getBody?(): unknown;\n}\n\n/**\n * Paywall configuration for HTML responses\n */\nexport interface PaywallConfig {\n appName?: string;\n appLogo?: string;\n sessionTokenEndpoint?: string;\n currentUrl?: string;\n testnet?: boolean;\n}\n\n/**\n * Paywall provider interface for generating HTML\n */\nexport interface PaywallProvider {\n generateHtml(paymentRequired: PaymentRequired, config?: PaywallConfig): string;\n}\n\n/**\n * Dynamic payTo function that receives HTTP request context\n */\nexport type DynamicPayTo = (context: HTTPRequestContext) => string | Promise<string>;\n\n/**\n * Dynamic price function that receives HTTP request context\n */\nexport type DynamicPrice = (context: HTTPRequestContext) => Price | Promise<Price>;\n\n/**\n * Result of response body callbacks containing content type and body.\n */\nexport interface HTTPResponseBody {\n /**\n * The content type for the response (e.g., 'application/json', 'text/plain').\n */\n contentType: string;\n\n /**\n * The response body to include in the 402 response.\n */\n body: unknown;\n}\n\n/**\n * Dynamic function to generate a custom response for unpaid requests.\n * Receives the HTTP request context and returns the content type and body to include in the 402 response.\n */\nexport type UnpaidResponseBody = (\n context: HTTPRequestContext,\n) => HTTPResponseBody | Promise<HTTPResponseBody>;\n\n/**\n * Dynamic function to generate a custom response for settlement failures.\n * Receives the HTTP request context and settle failure result, returns the content type and body.\n */\nexport type SettlementFailedResponseBody = (\n context: HTTPRequestContext,\n settleResult: Omit<ProcessSettleFailureResponse, \"response\">,\n) => HTTPResponseBody | Promise<HTTPResponseBody>;\n\n/**\n * A single payment option for a route\n * Represents one way a client can pay for access to the resource\n */\nexport interface PaymentOption {\n scheme: string;\n payTo: string | DynamicPayTo;\n price: Price | DynamicPrice;\n network: Network;\n maxTimeoutSeconds?: number;\n extra?: Record<string, unknown>;\n}\n\n/**\n * Route configuration for HTTP endpoints\n *\n * The 'accepts' field defines payment options for the route.\n * Can be a single PaymentOption or an array of PaymentOptions for multiple payment methods.\n */\nexport interface RouteConfig {\n // Payment option(s): single or array\n accepts: PaymentOption | PaymentOption[];\n\n // HTTP-specific metadata\n resource?: string;\n description?: string;\n mimeType?: string;\n customPaywallHtml?: string;\n\n /**\n * Optional callback to generate a custom response for unpaid API requests.\n * This allows servers to return preview data, error messages, or other content\n * when a request lacks payment.\n *\n * For browser requests (Accept: text/html), the paywall HTML takes precedence.\n * This callback is only used for API clients.\n *\n * If not provided, defaults to { contentType: 'application/json', body: {} }.\n *\n * @param context - The HTTP request context\n * @returns An object containing both contentType and body for the 402 response\n */\n unpaidResponseBody?: UnpaidResponseBody;\n\n /**\n * Optional callback to generate a custom response for settlement failures.\n * If not provided, defaults to { contentType: 'application/json', body: {} }.\n *\n * @param context - The HTTP request context\n * @param settleResult - The settlement failure result\n * @returns An object containing both contentType and body for the 402 response\n */\n settlementFailedResponseBody?: SettlementFailedResponseBody;\n\n // Extensions\n extensions?: Record<string, unknown>;\n\n // ── period scheme additions (subscription-only) ──────────\n /**\n * When set, the route is a special-operation endpoint for the subscription\n * scheme:\n * - \"change\": two-stage upgrade/downgrade flow\n * - \"cancel\": cancel-subscription flow\n * Ignored by non-subscription schemes.\n */\n operation?: \"change\" | \"cancel\" | \"cancel-pending-change\";\n\n /**\n * Route-level hook fired AFTER `verifyAccess` succeeded (signature +\n * payer + plan allowlist + period math) but BEFORE the handler runs.\n * Seller uses it for custom access policy: rate limiting, quota, feature\n * flags, bans / blacklists (return `{ok:false, error:\"banned\"}`). Full\n * `Subscription` object is on the context so any field is inspectable.\n */\n onBeforeAccess?: import(\"../subscription\").OnBeforeAccessHook;\n}\n\n/**\n * Routes configuration - maps path patterns to route configs\n */\nexport type RoutesConfig = Record<string, RouteConfig> | RouteConfig;\n\n/**\n * Hook that runs on every request to a protected route, before payment processing.\n * Can grant access without payment, deny the request, or continue to payment flow.\n *\n * @returns\n * - `void` - Continue to payment processing (default behavior)\n * - `{ grantAccess: true }` - Grant access without requiring payment\n * - `{ abort: true; reason: string }` - Deny the request (returns 403)\n */\nexport type ProtectedRequestHook = (\n context: HTTPRequestContext,\n routeConfig: RouteConfig,\n) => Promise<void | { grantAccess: true } | { abort: true; reason: string }>;\n\n/**\n * Compiled route for efficient matching\n */\nexport interface CompiledRoute {\n verb: string;\n regex: RegExp;\n config: RouteConfig;\n pattern: string;\n}\n\n/**\n * HTTP request context that encapsulates all request data\n */\nexport interface HTTPRequestContext {\n adapter: HTTPAdapter;\n path: string;\n method: string;\n paymentHeader?: string;\n routePattern?: string;\n}\n\n/**\n * HTTP transport context contains both request context and optional response data.\n */\nexport interface HTTPTransportContext {\n /** The HTTP request context */\n request: HTTPRequestContext;\n /** The response body buffer */\n responseBody?: Buffer;\n /** Response headers set by the route handler (used for settlement overrides) */\n responseHeaders?: Record<string, string>;\n}\n\n/**\n * HTTP response instructions for the framework middleware\n */\nexport interface HTTPResponseInstructions {\n status: number;\n headers: Record<string, string>;\n body?: unknown; // e.g. Paywall for web browser requests, but could be any other type\n isHtml?: boolean; // e.g. if body is a paywall, then isHtml is true\n}\n\n/**\n * Result of processing an HTTP request for payment\n */\nexport type HTTPProcessResult =\n | { type: \"no-payment-required\" }\n | {\n type: \"payment-verified\";\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n declaredExtensions?: Record<string, unknown>;\n }\n | { type: \"payment-error\"; response: HTTPResponseInstructions }\n // ── period dispatch results (produced by subscription-aware branches) ──\n | {\n type: \"payment-presettle\";\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirements;\n /** Settle action to run AFTER verify; bound to scheme + operation. */\n settle: () => Promise<{\n success: boolean;\n headers?: Record<string, string>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data?: any;\n error?: string;\n }>;\n operation: \"subscribe\" | \"change\" | \"cancel\" | \"cancel-pending-change\";\n }\n | {\n type: \"access-verified\";\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n subscription: import(\"../subscription\").Subscription;\n headers?: Record<string, string>;\n };\n\n/**\n * Result of processSettlement\n */\nexport type ProcessSettleSuccessResponse = SettleResponse & {\n success: true;\n headers: Record<string, string>;\n requirements: PaymentRequirements;\n};\n\nexport type ProcessSettleFailureResponse = SettleResponse & {\n success: false;\n errorReason: string;\n errorMessage?: string;\n headers: Record<string, string>;\n response: HTTPResponseInstructions;\n};\n\nexport type ProcessSettleResultResponse =\n | ProcessSettleSuccessResponse\n | ProcessSettleFailureResponse;\n\n/**\n * Represents a validation error for a specific route's payment configuration.\n */\nexport interface RouteValidationError {\n /** The route pattern (e.g., \"GET /api/weather\") */\n routePattern: string;\n /** The payment scheme that failed validation */\n scheme: string;\n /** The network that failed validation */\n network: Network;\n /** The type of validation failure */\n reason: \"missing_scheme\" | \"missing_facilitator\";\n /** Human-readable error message */\n message: string;\n}\n\n/**\n * Error thrown when route configuration validation fails.\n */\nexport class RouteConfigurationError extends Error {\n /** The validation errors that caused this exception */\n public readonly errors: RouteValidationError[];\n\n /**\n * Creates a new RouteConfigurationError with the given validation errors.\n *\n * @param errors - The validation errors that caused this exception.\n */\n constructor(errors: RouteValidationError[]) {\n const message = `x402 Route Configuration Errors:\\n${errors.map(e => ` - ${e.message}`).join(\"\\n\")}`;\n super(message);\n this.name = \"RouteConfigurationError\";\n this.errors = errors;\n }\n}\n\n/**\n * Hook called when the facilitator returns status=\"timeout\".\n * Receives the tx hash and network so the server can verify on-chain.\n * Return { confirmed: true } to deliver the resource; { confirmed: false } to return 402.\n */\nexport type OnSettlementTimeoutHook = (\n txHash: string,\n network: string,\n) => Promise<{ confirmed: boolean }>;\n\n/**\n * HTTP-enhanced x402 resource server\n * Provides framework-agnostic HTTP protocol handling\n */\nexport class x402HTTPResourceServer {\n private ResourceServer: x402ResourceServer;\n private compiledRoutes: CompiledRoute[] = [];\n private routesConfig: RoutesConfig;\n private paywallProvider?: PaywallProvider;\n private protectedRequestHooks: ProtectedRequestHook[] = [];\n private timeoutRecoveryHook?: OnSettlementTimeoutHook;\n private beforeAccessHooks: import(\"../subscription\").OnBeforeAccessHook[] = [];\n private pollDeadlineMs: number = DEFAULT_POLL_DEADLINE_MS;\n\n /**\n * Creates a new x402HTTPResourceServer instance.\n *\n * @param ResourceServer - The core x402ResourceServer instance to use\n * @param routes - Route configuration for payment-protected endpoints\n */\n constructor(ResourceServer: x402ResourceServer, routes: RoutesConfig) {\n this.ResourceServer = ResourceServer;\n this.routesConfig = routes;\n\n // Handle both single route and multiple routes\n const normalizedRoutes =\n typeof routes === \"object\" && !(\"accepts\" in routes)\n ? (routes as Record<string, RouteConfig>)\n : { \"*\": routes as RouteConfig };\n\n for (const [pattern, config] of Object.entries(normalizedRoutes)) {\n const parsed = this.parseRoutePattern(pattern);\n this.compiledRoutes.push({\n verb: parsed.verb,\n regex: parsed.regex,\n config,\n pattern: parsed.path,\n });\n }\n }\n\n /**\n * Get the underlying x402ResourceServer instance.\n *\n * @returns The underlying x402ResourceServer instance\n */\n get server(): x402ResourceServer {\n return this.ResourceServer;\n }\n\n /**\n * Get the routes configuration.\n *\n * @returns The routes configuration\n */\n get routes(): RoutesConfig {\n return this.routesConfig;\n }\n\n /**\n * Initialize the HTTP resource server.\n *\n * This method initializes the underlying resource server (fetching facilitator support)\n * and then validates that all route payment configurations have corresponding\n * registered schemes and facilitator support.\n *\n * @throws RouteConfigurationError if any route's payment options don't have\n * corresponding registered schemes or facilitator support\n *\n * @example\n * ```typescript\n * const httpServer = new x402HTTPResourceServer(server, routes);\n * await httpServer.initialize();\n * ```\n */\n async initialize(): Promise<void> {\n // First, initialize the underlying resource server (fetches facilitator support)\n await this.ResourceServer.initialize();\n\n // Then validate route configuration\n const errors = this.validateRouteConfiguration();\n if (errors.length > 0) {\n throw new RouteConfigurationError(errors);\n }\n }\n\n /**\n * Register a custom paywall provider for generating HTML\n *\n * @param provider - PaywallProvider instance\n * @returns This service instance for chaining\n */\n registerPaywallProvider(provider: PaywallProvider): this {\n this.paywallProvider = provider;\n return this;\n }\n\n /**\n * Register a hook that runs on every request to a protected route, before payment processing.\n * Hooks are executed in order of registration. The first hook to return a non-void result wins.\n *\n * @param hook - The request hook function\n * @returns The x402HTTPResourceServer instance for chaining\n */\n onProtectedRequest(hook: ProtectedRequestHook): this {\n this.protectedRequestHooks.push(hook);\n return this;\n }\n\n /**\n * Register a seller-global `onBeforeAccess` hook fired on every access-\n * verified subscription request, AFTER `verifyAccess` (signature + payer\n * + plan allowlist + period math) but BEFORE the handler runs. Seller\n * uses it for cross-cutting access policy (quota / ban list / feature\n * gating). Hooks are executed in order of registration; the first one\n * to return `{ ok: false }` denies (→ 402). Route-level\n * `RouteConfig.onBeforeAccess` runs AFTER all global hooks.\n *\n * @param hook - The hook function\n * @returns The x402HTTPResourceServer instance for chaining\n */\n onBeforeAccess(hook: import(\"../subscription\").OnBeforeAccessHook): this {\n this.beforeAccessHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to call when the facilitator returns status=\"timeout\".\n * The hook should verify the tx on-chain and return { confirmed: boolean }.\n * If confirmed=true the resource is delivered (200); otherwise 402 is returned.\n *\n * @param hook - On-chain verification callback\n * @returns The x402HTTPResourceServer instance for chaining\n */\n onSettlementTimeout(hook: OnSettlementTimeoutHook): this {\n this.timeoutRecoveryHook = hook;\n return this;\n }\n\n /**\n * Set the poll deadline for settle/status polling on timeout recovery.\n * Default is 5000ms.\n *\n * @param deadlineMs - Maximum time to poll in milliseconds\n * @returns The x402HTTPResourceServer instance for chaining\n */\n setPollDeadline(deadlineMs: number): this {\n this.pollDeadlineMs = deadlineMs;\n return this;\n }\n\n /**\n * Process HTTP request and return response instructions\n * This is the main entry point for framework middleware\n *\n * @param context - HTTP request context\n * @param paywallConfig - Optional paywall configuration\n * @returns Process result indicating next action for middleware\n */\n async processHTTPRequest(\n context: HTTPRequestContext,\n paywallConfig?: PaywallConfig,\n ): Promise<HTTPProcessResult> {\n const { adapter, path, method } = context;\n\n // Find matching route\n const routeMatch = this.getRouteConfig(path, method);\n if (!routeMatch) {\n return { type: \"no-payment-required\" }; // No payment required for this route\n }\n const { config: routeConfig, pattern: routePattern } = routeMatch;\n const enrichedContext: HTTPRequestContext = { ...context, routePattern };\n\n // Execute request hooks before any payment processing\n for (const hook of this.protectedRequestHooks) {\n const result = await hook(enrichedContext, routeConfig);\n if (result && \"grantAccess\" in result) {\n return { type: \"no-payment-required\" };\n }\n if (result && \"abort\" in result) {\n return {\n type: \"payment-error\",\n response: {\n status: 403,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: result.reason },\n },\n };\n }\n }\n\n // Normalize accepts field to array of payment options\n const paymentOptions = this.normalizePaymentOptions(routeConfig);\n\n // Check for payment header (v1 or v2) — used by Branches A / B / D.\n const paymentPayload = this.extractPayment(adapter);\n\n // ── period Branch A: change endpoint ──────────────────\n // If the route is declared with operation:\"change\", drive the two-stage\n // Change route: no special dispatcher. Buyer follows the standard\n // x402 flow — GET the route → 402 with accepts → pick one → sign newTerms\n // with `changeFromSubId` set to the current sub → POST + APP-PAYMENT.\n // The presettle branch below routes to verifyChange / settleChange based\n // on routeConfig.operation.\n\n // ── period Branch B: cancel endpoint ──────────────────────────────────\n if (routeConfig.operation === \"cancel\") {\n const cancelResult = await this.tryDispatchCancelFlow(adapter, routeConfig, paymentOptions);\n if (cancelResult) return cancelResult;\n }\n\n // ── period Branch B2: cancel-pending-change endpoint ────────────────\n if (routeConfig.operation === \"cancel-pending-change\") {\n const r = await this.tryDispatchCancelPendingChangeFlow(adapter, routeConfig, paymentOptions);\n if (r) return r;\n }\n\n // ── period Branch C: APP-Access (access flow) ────────\n // Build PaymentRequired once. Subscribe presettle + classic verify path\n // both consume the same `accepts[]` — building it here (instead of inside\n // tryDispatchSubscriptionPresettle + again below) eliminates the duplicate\n // facilitator-supportedKinds lookup and parsePrice/enhance pipeline.\n //\n // access / change / cancel flows don't depend on this; they've already\n // short-circuited above. The cost of building requirements once on the\n // way to subscribe / classic dispatch is negligible.\n const resourceInfo = {\n url: routeConfig.resource || enrichedContext.adapter.getUrl(),\n description: routeConfig.description || \"\",\n mimeType: routeConfig.mimeType || \"\",\n };\n let requirements = await this.ResourceServer.buildPaymentRequirementsFromOptions(\n paymentOptions,\n enrichedContext,\n );\n\n // Change route: inject `extra.changeFrom` into each accept so the 402\n // tells the buyer exactly which sub they're switching from and which\n // direction (upgrade/downgrade). Same-tier accepts are filtered out\n // (a no-op change is illegal — `tier_same`).\n //\n // currentSubId source per phase:\n // - sniff phase (no PAYMENT-SIGNATURE) → APP-Access header carrying\n // a buyer-signed AccessProof; middleware ecrecovers it and reads\n // proof.subId. Prevents subId-only reconnaissance attacks.\n // - settle phase (PAYMENT-SIGNATURE) → `terms.changeFromSubId` from\n // the buyer-signed newTerms (tamper-proof, signature covers it).\n //\n // Both phases MUST produce the same enriched accepts so verifyChange's\n // `findMatchingRequirements` deepEqual succeeds.\n if (routeConfig.operation === \"change\") {\n // Resolve the subscription scheme first — both phases need it.\n let scheme: SubscriptionCapability | null = null;\n for (const opt of paymentOptions) {\n if (!opt.network || !opt.scheme) continue;\n scheme = await this.resolveSubscriptionScheme(opt.network, opt.scheme);\n if (scheme) break;\n }\n if (!scheme) {\n return {\n type: \"payment-error\",\n response: {\n status: 500,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"change route: no subscription scheme registered\" },\n },\n };\n }\n\n let currentSubId: string | undefined;\n if (paymentPayload) {\n const innerTerms = (\n paymentPayload.payload as { terms?: { changeFromSubId?: string } } | undefined\n )?.terms;\n currentSubId = innerTerms?.changeFromSubId;\n } else {\n const accessHeader = this.extractAccessProofHeader(enrichedContext.adapter);\n if (!accessHeader) {\n return {\n type: \"payment-error\",\n response: {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"change route: missing APP-Access header\" },\n },\n };\n }\n const { decodeAccessProof } = await this.loadSubscriptionModule();\n let proof;\n try {\n proof = decodeAccessProof(accessHeader);\n } catch {\n return {\n type: \"payment-error\",\n response: {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"change route: invalid APP-Access header\" },\n },\n };\n }\n // change-route sniff: prove ownership only. `verifyAccess`'s\n // plan-allowlist + period-math gating is meant for resource\n // consumption — it would (wrongly) reject a buyer whose current\n // period hasn't been charged yet from even seeing change offers.\n // `verifyOwnership` does just sig + store + payer match.\n const verify = await scheme.verifyOwnership(proof);\n if (!verify.ok) {\n return {\n type: \"payment-error\",\n response: {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: verify.error },\n },\n };\n }\n currentSubId = verify.subId;\n }\n if (!currentSubId) {\n return {\n type: \"payment-error\",\n response: {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"change route: cannot resolve currentSubId\" },\n },\n };\n }\n const enriched = await scheme.enrichAcceptsForChange(requirements, currentSubId);\n if (enriched === null) {\n return {\n type: \"payment-error\",\n response: {\n status: 404,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"sub_not_active_for_change\" },\n },\n };\n }\n requirements = enriched;\n }\n\n let extensions = routeConfig.extensions;\n if (extensions) {\n extensions = this.ResourceServer.enrichExtensions(extensions, enrichedContext);\n }\n const transportContext: HTTPTransportContext = { request: enrichedContext };\n const paymentRequired = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n !paymentPayload ? \"Payment required\" : undefined,\n extensions,\n transportContext,\n );\n\n // Access flow runs AFTER paymentRequired so that an AccessProof rejection\n // (sub not in this route's plan allowlist / expired / etc.) can return a\n // proper 402 + PAYMENT-REQUIRED body with the route's accepts — buyer\n // sees which plans they'd need to subscribe to gain access.\n //\n // Skip for change routes: APP-Access on a change route is the buyer's\n // identity for `extra.changeFrom` enrichment (above), NOT a request to\n // access the resource itself.\n if (routeConfig.operation !== \"change\") {\n const accessResult = await this.tryDispatchAccessFlow(\n adapter,\n routeConfig,\n paymentOptions,\n paymentRequired,\n );\n if (accessResult) return accessResult;\n }\n\n // ── period Branch D: APP-PAYMENT + scheme=\"pre\" ──────\n // If the buyer presented a subscription PaymentPayload (scheme tags itself\n // as `period` and the registered server declares\n // `settlementMode === \"pre\"`), run verify+settle BEFORE handler executes.\n if (paymentPayload) {\n const subResult = await this.tryDispatchSubscriptionPresettle(\n paymentPayload,\n paymentRequired.accepts,\n routeConfig.operation === \"change\" ? \"change\" : \"subscribe\",\n );\n if (subResult) return subResult;\n }\n\n // If no payment provided\n if (!paymentPayload) {\n // Resolve custom unpaid response body if provided\n const unpaidBody = routeConfig.unpaidResponseBody\n ? await routeConfig.unpaidResponseBody(enrichedContext)\n : undefined;\n\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(\n paymentRequired,\n this.isWebBrowser(adapter),\n paywallConfig,\n routeConfig.customPaywallHtml,\n unpaidBody,\n ),\n };\n }\n\n // Verify payment\n try {\n const matchingRequirements = this.ResourceServer.findMatchingRequirements(\n paymentRequired.accepts,\n paymentPayload,\n );\n\n if (!matchingRequirements) {\n const errorResponse = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n \"No matching payment requirements\",\n routeConfig.extensions,\n transportContext,\n );\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(errorResponse, false, paywallConfig),\n };\n }\n\n const verifyResult = await this.ResourceServer.verifyPayment(\n paymentPayload,\n matchingRequirements,\n );\n\n if (!verifyResult.isValid) {\n const errorResponse = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n verifyResult.invalidReason,\n routeConfig.extensions,\n transportContext,\n );\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(errorResponse, false, paywallConfig),\n };\n }\n\n // Payment is valid, return data needed for settlement\n return {\n type: \"payment-verified\",\n paymentPayload,\n paymentRequirements: matchingRequirements,\n declaredExtensions: routeConfig.extensions,\n };\n } catch (error) {\n if (error instanceof FacilitatorResponseError) {\n throw error;\n }\n const errorResponse = await this.ResourceServer.createPaymentRequiredResponse(\n requirements,\n resourceInfo,\n error instanceof Error ? error.message : \"Payment verification failed\",\n routeConfig.extensions,\n transportContext,\n );\n return {\n type: \"payment-error\",\n response: this.createHTTPResponse(errorResponse, false, paywallConfig),\n };\n }\n }\n\n /**\n * Process settlement after successful response\n *\n * @param paymentPayload - The verified payment payload\n * @param requirements - The matching payment requirements\n * @param declaredExtensions - Optional declared extensions (for per-key enrichment)\n * @param transportContext - Optional HTTP transport context\n * @param settlementOverrides - Optional settlement overrides (e.g., partial settlement amount)\n * @returns ProcessSettleResultResponse - SettleResponse with headers if success or errorReason if failure\n */\n async processSettlement(\n paymentPayload: PaymentPayload,\n requirements: PaymentRequirements,\n declaredExtensions?: Record<string, unknown>,\n transportContext?: HTTPTransportContext,\n settlementOverrides?: SettlementOverrides,\n ): Promise<ProcessSettleResultResponse> {\n try {\n // Resolve overrides: explicit param takes precedence, fall back to response header\n let resolvedOverrides = settlementOverrides;\n if (!resolvedOverrides && transportContext?.responseHeaders?.[SETTLEMENT_OVERRIDES_HEADER]) {\n try {\n resolvedOverrides = JSON.parse(\n transportContext.responseHeaders[SETTLEMENT_OVERRIDES_HEADER],\n );\n } catch {\n // Ignore malformed header\n }\n }\n\n const settleResponse = await this.ResourceServer.settlePayment(\n paymentPayload,\n requirements,\n declaredExtensions,\n transportContext,\n resolvedOverrides,\n );\n\n // status=\"timeout\" → facilitator gave up waiting for on-chain confirmation.\n // Step 1: Poll /settle/status (interval 1s, deadline from config).\n // Step 2: If polling fails/times out, try developer's timeout hook.\n if (settleResponse.status === \"timeout\") {\n if (settleResponse.transaction) {\n // Step 1: Poll settle/status\n const pollResult = await this.ResourceServer.pollSettleStatus(\n settleResponse.transaction,\n paymentPayload,\n requirements,\n this.pollDeadlineMs,\n );\n\n if (pollResult === \"success\") {\n // Poll confirmed on-chain → deliver resource\n const recovered = { ...settleResponse, status: \"success\" as const };\n return {\n ...recovered,\n success: true as const,\n headers: this.createSettlementHeaders(recovered),\n requirements,\n };\n }\n\n // Step 2: Poll unsuccessful → try developer's timeout hook\n if (this.timeoutRecoveryHook) {\n try {\n const { confirmed } = await this.timeoutRecoveryHook(\n settleResponse.transaction,\n settleResponse.network as string,\n );\n if (confirmed) {\n const recovered = { ...settleResponse, status: \"success\" as const };\n return {\n ...recovered,\n success: true as const,\n headers: this.createSettlementHeaders(recovered),\n requirements,\n };\n }\n } catch (err) {\n console.warn(\"[x402] onSettlementTimeout hook error:\", err);\n }\n }\n }\n\n // No transaction, or poll+hook both failed → 402\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason: \"settlement_timeout\",\n errorMessage: \"Settlement timed out waiting for on-chain confirmation\",\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n\n // status=\"success\" → on-chain confirmed (syncSettle=true), deliver resource\n // status=\"pending\" → async mode, Seller trusts Facilitator, deliver resource\n // no status → standard okx facilitator, check success field\n if (settleResponse.status === \"success\" || settleResponse.status === \"pending\") {\n return {\n ...settleResponse,\n success: true as const,\n headers: this.createSettlementHeaders(settleResponse),\n requirements,\n };\n }\n\n // Fallback: standard okx facilitator (no status field)\n if (!settleResponse.success) {\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason: settleResponse.errorReason || \"Settlement failed\",\n errorMessage:\n settleResponse.errorMessage || settleResponse.errorReason || \"Settlement failed\",\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n\n return {\n ...settleResponse,\n success: true,\n headers: this.createSettlementHeaders(settleResponse),\n requirements,\n };\n } catch (error) {\n if (error instanceof FacilitatorResponseError) {\n throw error;\n }\n if (error instanceof SettleError) {\n const errorReason = error.errorReason || error.message;\n const settleResponse: SettleResponse = {\n success: false,\n errorReason,\n errorMessage: error.errorMessage || errorReason,\n payer: error.payer,\n network: error.network,\n transaction: error.transaction,\n };\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason,\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n const errorReason = error instanceof Error ? error.message : \"Settlement failed\";\n const settleResponse: SettleResponse = {\n success: false,\n errorReason,\n errorMessage: errorReason,\n network: requirements.network as Network,\n transaction: \"\",\n };\n const failure = {\n ...settleResponse,\n success: false as const,\n errorReason,\n headers: this.createSettlementHeaders(settleResponse),\n };\n const response = await this.buildSettlementFailureResponse(failure, transportContext);\n return { ...failure, response };\n }\n }\n\n /**\n * Check if a request requires payment based on route configuration\n *\n * @param context - HTTP request context\n * @returns True if the route requires payment, false otherwise\n */\n requiresPayment(context: HTTPRequestContext): boolean {\n return this.getRouteConfig(context.path, context.method) !== undefined;\n }\n\n /**\n * Lazy loader for the subscription submodule. The `import()` cache makes\n * this effectively free after the first hit; isolating it in one place\n * keeps dispatch helpers free of dynamic-import boilerplate and lets\n * bundlers tree-shake the entire subscription path when no caller touches\n * it.\n */\n protected loadSubscriptionModule(): Promise<typeof import(\"../subscription\")> {\n return import(\"../subscription\");\n }\n\n /**\n * Single chokepoint for \"is this (network, scheme) backed by a\n * SubscriptionCapability-implementing scheme?\". Returns the narrowed\n * capability (so callers get full typing on `verifyAccess` / `verifySubscribe`\n * / etc.) or null if not registered or not a subscription scheme.\n */\n protected async resolveSubscriptionScheme(\n network: Network,\n schemeName: string,\n ): Promise<SubscriptionCapability | null> {\n const registered = this.ResourceServer.findScheme(network, schemeName);\n if (!registered) return null;\n const { hasSubscriptionCapability } = await this.loadSubscriptionModule();\n return hasSubscriptionCapability(registered) ? registered : null;\n }\n\n /**\n * period dispatch helper — Access flow.\n *\n * Returns an `access-verified` (or `payment-error`) HTTPProcessResult when\n * the request carries `APP-Access` AND a subscription-capable scheme is\n * registered for one of the route's accepted (scheme, network) pairs.\n * Returns `null` to indicate the dispatcher should fall through to classic\n * pay-per-request handling.\n */\n protected async tryDispatchAccessFlow(\n adapter: HTTPAdapter,\n routeConfig: RouteConfig,\n paymentOptions: PaymentOption[],\n paymentRequired: PaymentRequired,\n ): Promise<HTTPProcessResult | null> {\n const headerB64 = this.extractAccessProofHeader(adapter);\n if (!headerB64) return null;\n\n const { decodeAccessProof } = await this.loadSubscriptionModule();\n\n let proof;\n try {\n proof = decodeAccessProof(headerB64);\n } catch (err) {\n return {\n type: \"payment-error\",\n response: {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: `invalid APP-Access: ${(err as Error).message}` },\n },\n };\n }\n\n // Derive the route's allowed plan-id allowlist from its `accepts` —\n // every accept entry's `extra.plan.id` is one acceptable plan. A\n // subscription's `planId` must appear here to satisfy this route.\n const acceptedPlanIds = collectAcceptedPlanIds(paymentOptions);\n\n // First (scheme, network) in the route's accepts that resolves to a\n // SubscriptionCapability wins. v1 assumes one subscription scheme per\n // route.\n for (const opt of paymentOptions) {\n if (!opt.network || !opt.scheme) continue;\n const scheme = await this.resolveSubscriptionScheme(opt.network, opt.scheme);\n if (!scheme) continue;\n const result = await scheme.verifyAccess(proof, { acceptedPlanIds });\n if (!result.ok) {\n // 402: PAYMENT-REQUIRED header carries the route's accepts (so buyer\n // can subscribe / change to a satisfying plan); body carries the\n // specific reason code (subscription_not_active / signature_invalid\n // / payer_mismatch / …).\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: {\n \"Content-Type\": \"application/json\",\n \"PAYMENT-REQUIRED\": encodePaymentRequiredHeader(paymentRequired),\n },\n body: { error: result.error },\n },\n };\n }\n\n // `onBeforeAccess` hooks: seller-defined access policy\n // (quota, ban list, feature gating…). Full Subscription is passed so\n // arbitrary fields (subId / payer / planId / lastChargedPeriod / …)\n // can drive the decision. Return `{ok:false}` to deny. Global hook\n // (set via `httpServer.onBeforeAccess()`) runs FIRST; if it passes,\n // route-level hook (in `RouteConfig.onBeforeAccess`) runs after.\n const hooks: import(\"../subscription\").OnBeforeAccessHook[] = [\n ...this.beforeAccessHooks,\n ...(routeConfig.onBeforeAccess ? [routeConfig.onBeforeAccess] : []),\n ];\n for (const hook of hooks) {\n const decision = await hook({\n subscription: result.subscription,\n request: {\n path: adapter.getPath(),\n method: adapter.getMethod(),\n headers: adapter.getHeaders?.() ?? {},\n },\n route: { acceptedPlanIds, accepts: paymentRequired.accepts },\n });\n if (!decision.ok) {\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: { \"Content-Type\": \"application/json\" },\n body: {\n error: decision.error ?? \"access_denied\",\n retryAfter: decision.retryAfter,\n upgradeOffers: decision.upgradeOffers,\n },\n },\n };\n }\n }\n\n return {\n type: \"access-verified\",\n subscription: result.subscription,\n headers: {},\n };\n }\n\n // No subscription-capable scheme registered for any of the route's\n // accepted networks. Treat as unauthorized rather than fall through to a\n // 402 paywall, since the buyer clearly tried the access path.\n return {\n type: \"payment-error\",\n response: {\n status: 401,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"no subscription scheme registered for this route\" },\n },\n };\n }\n\n /**\n * period dispatch helper — Subscribe presettle flow.\n *\n * When the buyer presents a PaymentPayload whose `accepted.scheme` is a\n * subscription scheme with `settlementMode === \"pre\"`, this runs verify +\n * (settle on demand) and returns `payment-presettle`. The middleware is\n * expected to call `result.settle()` AFTER decision-time but BEFORE\n * `next()` so handler only runs when the chain creation succeeded.\n *\n * Returns `null` to fall through to classic post-settle path-verified flow.\n */\n protected async tryDispatchSubscriptionPresettle(\n paymentPayload: PaymentPayload,\n serverAccepts: PaymentRequirements[],\n operation: \"subscribe\" | \"change\",\n ): Promise<HTTPProcessResult | null> {\n const { accepted } = paymentPayload;\n const scheme = await this.resolveSubscriptionScheme(accepted.network, accepted.scheme);\n if (!scheme) return null;\n\n // ★ Security gate (anti-tampering): caller passes already-built\n // `serverAccepts` (the seller's authoritative requirements from route\n // config). We look up which entry the buyer's PaymentPayload matches —\n // returning the SERVER copy, not the buyer's. Divergence on base fields\n // or server-declared extra → 402 here, well before any facilitator call.\n const serverReq = this.ResourceServer.findMatchingRequirements(serverAccepts, paymentPayload);\n if (!serverReq) {\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"no_matching_requirements\" },\n },\n };\n }\n\n if (operation === \"change\") {\n const verifyResult = await scheme.verifyChange(paymentPayload, serverReq);\n if (!verifyResult.ok) {\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: verifyResult.error },\n },\n };\n }\n return {\n type: \"payment-presettle\",\n paymentPayload,\n paymentRequirements: serverReq,\n operation: \"change\",\n settle: async () => {\n const r = await scheme.settleChange(paymentPayload, serverReq);\n return r.success\n ? {\n success: true,\n headers: r.headers,\n data: {\n newSubId: r.newSubId,\n oldSubId: r.oldSubId,\n operationType: r.operationType,\n scheduledFromPeriod: r.scheduledFromPeriod,\n },\n }\n : { success: false, error: r.error };\n },\n };\n }\n\n const verifyResult = await scheme.verifySubscribe(paymentPayload, serverReq);\n if (!verifyResult.ok) {\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: verifyResult.error },\n },\n };\n }\n\n return {\n type: \"payment-presettle\",\n paymentPayload,\n paymentRequirements: serverReq,\n operation: \"subscribe\",\n settle: async () => {\n const r = await scheme.settleSubscribe(paymentPayload, serverReq);\n return r.success\n ? {\n success: true,\n headers: r.headers,\n data: { subId: r.subId, subscription: r.subscription },\n }\n : { success: false, error: r.error };\n },\n };\n }\n\n /**\n * period dispatch helper — Cancel flow.\n *\n * Reads JSON body { auth: CancelAuth, subId: string }, runs verifyCancel\n * then wraps settleCancel as a payment-presettle (settle-before-handler so\n * the cancelation is on-chain before the seller's response).\n */\n protected async tryDispatchCancelFlow(\n adapter: HTTPAdapter,\n routeConfig: RouteConfig,\n paymentOptions: PaymentOption[],\n ): Promise<HTTPProcessResult | null> {\n let scheme: SubscriptionCapability | null = null;\n for (const opt of paymentOptions) {\n if (!opt.network || !opt.scheme) continue;\n const resolved = await this.resolveSubscriptionScheme(opt.network as Network, opt.scheme);\n if (resolved) {\n scheme = resolved;\n break;\n }\n }\n if (!scheme) return null;\n\n const body = (adapter.getBody?.() ?? {}) as {\n auth?: import(\"../subscription\").CancelAuth;\n subId?: string;\n };\n if (!body.auth || !body.subId) {\n return {\n type: \"payment-error\",\n response: {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"cancel: body must include auth and subId\" },\n },\n };\n }\n\n const verifyResult = await scheme.verifyCancel(body.auth, body.subId);\n if (!verifyResult.ok) {\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: verifyResult.error },\n },\n };\n }\n\n void routeConfig;\n const settleScheme = scheme;\n const auth = body.auth;\n const subId = body.subId;\n return {\n type: \"payment-presettle\",\n paymentPayload: { x402Version: 2, accepted: null as never, payload: {} },\n paymentRequirements: null as never,\n operation: \"cancel\",\n settle: async () => {\n const r = await settleScheme.settleCancel(auth, subId);\n return r.success\n ? { success: true, headers: r.headers, data: { subId } }\n : { success: false, error: r.error };\n },\n };\n }\n\n /**\n * period dispatch helper — Cancel-Pending-Change flow.\n *\n * Reads JSON body `{ auth: PendingChangeCancelAuth, subId: string }`. The\n * auth must carry `newSubId` (matches the currently PENDING downgrade\n * target). Runs verifyCancelPendingChange then wraps\n * settleCancelPendingChange as a payment-presettle.\n */\n protected async tryDispatchCancelPendingChangeFlow(\n adapter: HTTPAdapter,\n routeConfig: RouteConfig,\n paymentOptions: PaymentOption[],\n ): Promise<HTTPProcessResult | null> {\n let scheme: SubscriptionCapability | null = null;\n for (const opt of paymentOptions) {\n if (!opt.network || !opt.scheme) continue;\n const resolved = await this.resolveSubscriptionScheme(opt.network as Network, opt.scheme);\n if (resolved) {\n scheme = resolved;\n break;\n }\n }\n if (!scheme) return null;\n\n const body = (adapter.getBody?.() ?? {}) as {\n auth?: import(\"../subscription\").PendingChangeCancelAuth;\n subId?: string;\n };\n if (!body.auth || !body.subId) {\n return {\n type: \"payment-error\",\n response: {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"cancel-pending-change: body must include auth and subId\" },\n },\n };\n }\n if (!body.auth.newSubId) {\n // Facilitator requires newSubId — reject early with a clear code.\n return {\n type: \"payment-error\",\n response: {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: \"cancel-pending-change: auth.newSubId is required\" },\n },\n };\n }\n\n const verifyResult = await scheme.verifyCancelPendingChange(body.auth, body.subId);\n if (!verifyResult.ok) {\n return {\n type: \"payment-error\",\n response: {\n status: 402,\n headers: { \"Content-Type\": \"application/json\" },\n body: { error: verifyResult.error },\n },\n };\n }\n\n void routeConfig;\n const settleScheme = scheme;\n const auth = body.auth;\n const subId = body.subId;\n return {\n type: \"payment-presettle\",\n paymentPayload: { x402Version: 2, accepted: null as never, payload: {} },\n paymentRequirements: null as never,\n operation: \"cancel-pending-change\",\n settle: async () => {\n const r = await settleScheme.settleCancelPendingChange(auth, subId);\n return r.success\n ? { success: true, headers: r.headers, data: { subId: r.subId } }\n : { success: false, error: r.error };\n },\n };\n }\n\n /**\n * Build HTTPResponseInstructions for settlement failure.\n * Uses settlementFailedResponseBody hook if configured, otherwise defaults to empty body.\n *\n * @param failure - Settlement failure result with headers\n * @param transportContext - Optional HTTP transport context for the request\n * @returns HTTP response instructions for the 402 settlement failure response\n */\n private async buildSettlementFailureResponse(\n failure: Omit<ProcessSettleFailureResponse, \"response\">,\n transportContext?: HTTPTransportContext,\n ): Promise<HTTPResponseInstructions> {\n const settlementHeaders = failure.headers;\n const routeConfig = transportContext\n ? this.getRouteConfig(transportContext.request.path, transportContext.request.method)\n : undefined;\n\n const customBody = routeConfig?.config.settlementFailedResponseBody\n ? await routeConfig.config.settlementFailedResponseBody(transportContext!.request, failure)\n : undefined;\n\n const contentType = customBody ? customBody.contentType : \"application/json\";\n const body = customBody ? customBody.body : {};\n\n return {\n status: 402,\n headers: {\n \"Content-Type\": contentType,\n ...settlementHeaders,\n },\n body,\n isHtml: contentType.includes(\"text/html\"),\n };\n }\n\n /**\n * Normalizes a RouteConfig's accepts field into an array of PaymentOptions\n * Handles both single PaymentOption and array formats\n *\n * @param routeConfig - Route configuration\n * @returns Array of payment options\n */\n private normalizePaymentOptions(routeConfig: RouteConfig): PaymentOption[] {\n return Array.isArray(routeConfig.accepts) ? routeConfig.accepts : [routeConfig.accepts];\n }\n\n /**\n * Validates that all payment options in routes have corresponding registered schemes\n * and facilitator support.\n *\n * @returns Array of validation errors (empty if all routes are valid)\n */\n private validateRouteConfiguration(): RouteValidationError[] {\n const errors: RouteValidationError[] = [];\n\n // Normalize routes to array of [pattern, config] pairs\n const normalizedRoutes =\n typeof this.routesConfig === \"object\" && !(\"accepts\" in this.routesConfig)\n ? Object.entries(this.routesConfig as Record<string, RouteConfig>)\n : [[\"*\", this.routesConfig as RouteConfig] as [string, RouteConfig]];\n\n for (const [pattern, config] of normalizedRoutes) {\n // Warn if wildcard routes are used with discovery extensions\n const pathPart = pattern.includes(\" \") ? pattern.split(/\\s+/)[1] : pattern;\n if (\n pathPart &&\n pathPart.includes(\"*\") &&\n config.extensions &&\n \"bazaar\" in config.extensions\n ) {\n console.warn(\n `[x402] Route \"${pattern}\": Wildcard (*) patterns with bazaar discovery extensions ` +\n `will auto-generate parameter names (var1, var2, ...). ` +\n `Consider using named parameters instead (e.g. /weather/:city) for better discovery metadata.`,\n );\n }\n\n const paymentOptions = this.normalizePaymentOptions(config);\n\n for (const option of paymentOptions) {\n // Check 1: Is scheme registered?\n if (!this.ResourceServer.hasRegisteredScheme(option.network, option.scheme)) {\n errors.push({\n routePattern: pattern,\n scheme: option.scheme,\n network: option.network,\n reason: \"missing_scheme\",\n message: `Route \"${pattern}\": No scheme implementation registered for \"${option.scheme}\" on network \"${option.network}\"`,\n });\n // Skip facilitator check if scheme isn't registered\n continue;\n }\n\n // Check 2: Does facilitator support this scheme/network combination?\n const supportedKind = this.ResourceServer.getSupportedKind(\n x402Version,\n option.network,\n option.scheme,\n );\n\n if (!supportedKind) {\n errors.push({\n routePattern: pattern,\n scheme: option.scheme,\n network: option.network,\n reason: \"missing_facilitator\",\n message: `Route \"${pattern}\": Facilitator does not support scheme \"${option.scheme}\" on network \"${option.network}\"`,\n });\n }\n }\n }\n\n return errors;\n }\n\n /**\n * Get route configuration for a request\n *\n * @param path - Request path\n * @param method - HTTP method\n * @returns Route configuration and pattern, or undefined if no match\n */\n private getRouteConfig(\n path: string,\n method: string,\n ): { config: RouteConfig; pattern: string } | undefined {\n const normalizedPath = this.normalizePath(path);\n const upperMethod = method.toUpperCase();\n\n const matchingRoute = this.compiledRoutes.find(\n route =>\n route.regex.test(normalizedPath) && (route.verb === \"*\" || route.verb === upperMethod),\n );\n\n if (!matchingRoute) return undefined;\n return { config: matchingRoute.config, pattern: matchingRoute.pattern };\n }\n\n /**\n * Extract payment from HTTP headers (handles v1 and v2)\n *\n * @param adapter - HTTP adapter\n * @returns Decoded payment payload or null\n */\n private extractPayment(adapter: HTTPAdapter): PaymentPayload | null {\n // Check v2 header first (PAYMENT-SIGNATURE)\n const header = adapter.getHeader(\"payment-signature\") || adapter.getHeader(\"PAYMENT-SIGNATURE\");\n\n if (header) {\n try {\n return decodePaymentSignatureHeader(header);\n } catch (error) {\n console.warn(\"Failed to decode PAYMENT-SIGNATURE header:\", error);\n }\n }\n\n // period uses APP-PAYMENT (base64-encoded JSON).\n const subHeader = adapter.getHeader(\"app-payment\") || adapter.getHeader(\"APP-PAYMENT\");\n if (subHeader) {\n try {\n const json = Buffer.from(subHeader, \"base64\").toString(\"utf8\");\n return JSON.parse(json) as PaymentPayload;\n } catch (error) {\n console.warn(\"Failed to decode APP-PAYMENT header:\", error);\n }\n }\n\n return null;\n }\n\n /**\n * Extract `APP-Access` header (subscription access-flow). Returns the raw\n * base64 string so callers can pass it through to `decodeAccessProof` in\n * the subscription codec.\n */\n private extractAccessProofHeader(adapter: HTTPAdapter): string | null {\n return adapter.getHeader(\"app-access\") || adapter.getHeader(\"APP-Access\") || null;\n }\n\n /**\n * Check if request is from a web browser\n *\n * @param adapter - HTTP adapter\n * @returns True if request appears to be from a browser\n */\n private isWebBrowser(adapter: HTTPAdapter): boolean {\n const accept = adapter.getAcceptHeader();\n const userAgent = adapter.getUserAgent();\n return accept.includes(\"text/html\") && userAgent.includes(\"Mozilla\");\n }\n\n /**\n * Create HTTP response instructions from payment required\n *\n * @param paymentRequired - Payment requirements\n * @param isWebBrowser - Whether request is from browser\n * @param paywallConfig - Paywall configuration\n * @param customHtml - Custom HTML template\n * @param unpaidResponse - Optional custom response (content type and body) for unpaid API requests\n * @returns Response instructions\n */\n private createHTTPResponse(\n paymentRequired: PaymentRequired,\n isWebBrowser: boolean,\n paywallConfig?: PaywallConfig,\n customHtml?: string,\n unpaidResponse?: HTTPResponseBody,\n ): HTTPResponseInstructions {\n // Use 412 Precondition Failed for permit2_allowance_required error\n // This signals client needs to approve Permit2 before retrying\n const status = paymentRequired.error === \"permit2_allowance_required\" ? 412 : 402;\n\n if (isWebBrowser) {\n const html = this.generatePaywallHTML(paymentRequired, paywallConfig, customHtml);\n return {\n status,\n headers: { \"Content-Type\": \"text/html\" },\n body: html,\n isHtml: true,\n };\n }\n\n const response = this.createHTTPPaymentRequiredResponse(paymentRequired);\n\n // Use callback result if provided, otherwise default to JSON with empty object\n const contentType = unpaidResponse ? unpaidResponse.contentType : \"application/json\";\n const body = unpaidResponse ? unpaidResponse.body : {};\n\n return {\n status,\n headers: {\n \"Content-Type\": contentType,\n ...response.headers,\n },\n body,\n };\n }\n\n /**\n * Create HTTP payment required response (v1 puts in body, v2 puts in header)\n *\n * @param paymentRequired - Payment required object\n * @returns Headers and body for the HTTP response\n */\n private createHTTPPaymentRequiredResponse(paymentRequired: PaymentRequired): {\n headers: Record<string, string>;\n } {\n return {\n headers: {\n \"PAYMENT-REQUIRED\": encodePaymentRequiredHeader(paymentRequired),\n },\n };\n }\n\n /**\n * Create settlement response headers\n *\n * @param settleResponse - Settlement response\n * @returns Headers to add to response\n */\n private createSettlementHeaders(settleResponse: SettleResponse): Record<string, string> {\n const encoded = encodePaymentResponseHeader(settleResponse);\n return { \"PAYMENT-RESPONSE\": encoded };\n }\n\n /**\n * Parse route pattern into verb and regex\n *\n * @param pattern - Route pattern like \"GET /api/*\", \"/api/[id]\", or \"/api/:id\"\n * @returns Parsed pattern with verb and regex\n */\n private parseRoutePattern(pattern: string): { verb: string; regex: RegExp; path: string } {\n const [verb, path] = pattern.includes(\" \") ? pattern.split(/\\s+/) : [\"*\", pattern];\n\n const regex = new RegExp(\n `^${\n path\n .replace(/[$()+.?^{|}]/g, \"\\\\$&\") // Escape regex special chars\n .replace(/\\*/g, \".*?\") // Wildcards\n .replace(/\\[([^\\]]+)\\]/g, \"[^/]+\") // Parameters (Next.js style [param])\n .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, \"[^/]+\") // Parameters (Express style :param)\n .replace(/\\//g, \"\\\\/\") // Escape slashes\n }$`,\n \"i\",\n );\n\n return { verb: verb.toUpperCase(), regex, path };\n }\n\n /**\n * Normalize path for matching\n *\n * @param path - Raw path from request\n * @returns Normalized path\n */\n private normalizePath(path: string): string {\n const pathWithoutQuery = path.split(/[?#]/)[0];\n\n let decodedOrRawPath: string;\n try {\n decodedOrRawPath = decodeURIComponent(pathWithoutQuery);\n } catch {\n decodedOrRawPath = pathWithoutQuery;\n }\n\n return decodedOrRawPath\n .replace(/\\\\/g, \"/\")\n .replace(/\\/+/g, \"/\")\n .replace(/(.+?)\\/+$/, \"$1\");\n }\n\n /**\n * Generate paywall HTML for browser requests\n *\n * @param paymentRequired - Payment required response\n * @param paywallConfig - Optional paywall configuration\n * @param customHtml - Optional custom HTML template\n * @returns HTML string\n */\n private generatePaywallHTML(\n paymentRequired: PaymentRequired,\n paywallConfig?: PaywallConfig,\n customHtml?: string,\n ): string {\n if (customHtml) {\n return customHtml;\n }\n\n // Use custom paywall provider if set\n if (this.paywallProvider) {\n return this.paywallProvider.generateHtml(paymentRequired, paywallConfig);\n }\n\n // Fallback: Basic HTML paywall\n const resource = paymentRequired.resource;\n const displayAmount = this.getDisplayAmount(paymentRequired);\n\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>Payment Required</title>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body>\n <div style=\"max-width: 600px; margin: 50px auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;\">\n ${paywallConfig?.appLogo ? `<img src=\"${paywallConfig.appLogo}\" alt=\"${paywallConfig.appName || \"App\"}\" style=\"max-width: 200px; margin-bottom: 20px;\">` : \"\"}\n <h1>Payment Required</h1>\n ${resource ? `<p><strong>Resource:</strong> ${resource.description || resource.url}</p>` : \"\"}\n <p><strong>Amount:</strong> $${displayAmount.toFixed(2)} USDC</p>\n <div id=\"payment-widget\" \n data-requirements='${JSON.stringify(paymentRequired)}'\n data-app-name=\"${paywallConfig?.appName || \"\"}\"\n data-testnet=\"${paywallConfig?.testnet || false}\">\n </div>\n </div>\n </body>\n </html>\n `;\n }\n\n /**\n * Extract display amount from payment requirements.\n *\n * @param paymentRequired - The payment required object\n * @returns The display amount in decimal format\n */\n private getDisplayAmount(paymentRequired: PaymentRequired): number {\n const accepts = paymentRequired.accepts;\n if (accepts && accepts.length > 0) {\n const firstReq = accepts[0];\n if (\"amount\" in firstReq) {\n // V2 format\n return parseFloat(firstReq.amount) / 1000000; // Assuming USDC with 6 decimals\n }\n }\n return 0;\n }\n}\n\n/**\n * Pull `extra.plan.id` out of every payment option, dedup, drop missing.\n * Used by the access-flow dispatcher to build the route's allowlist of\n * acceptable plans from `RouteConfig.accepts`.\n */\nfunction collectAcceptedPlanIds(options: PaymentOption[]): string[] {\n const seen = new Set<string>();\n for (const opt of options) {\n const extra = opt.extra as { plan?: { id?: unknown } } | undefined;\n const id = extra?.plan?.id;\n if (typeof id === \"string\" && id.length > 0) seen.add(id);\n }\n return Array.from(seen);\n}\n","import {\n decodePaymentRequiredHeader,\n decodePaymentResponseHeader,\n encodePaymentSignatureHeader,\n} from \".\";\nimport { SettleResponse } from \"../types\";\nimport { PaymentPayload, PaymentRequired } from \"../types/payments\";\nimport { x402Client } from \"../client/x402Client\";\n\n/**\n * Context provided to onPaymentRequired hooks.\n */\nexport interface PaymentRequiredContext {\n paymentRequired: PaymentRequired;\n}\n\n/**\n * Hook called when a 402 response is received, before payment processing.\n * Return headers to try before payment, or void to proceed directly to payment.\n */\nexport type PaymentRequiredHook = (\n context: PaymentRequiredContext,\n) => Promise<{ headers: Record<string, string> } | void>;\n\n/**\n * HTTP-specific client for handling x402 payment protocol over HTTP.\n *\n * Wraps a x402Client to provide HTTP-specific encoding/decoding functionality\n * for payment headers and responses while maintaining the builder pattern.\n */\nexport class x402HTTPClient {\n private paymentRequiredHooks: PaymentRequiredHook[] = [];\n\n /**\n * Creates a new x402HTTPClient instance.\n *\n * @param client - The underlying x402Client for payment logic\n */\n constructor(private readonly client: x402Client) {}\n\n /**\n * Register a hook to handle 402 responses before payment.\n * Hooks run in order; first to return headers wins.\n *\n * @param hook - The hook function to register\n * @returns This instance for chaining\n */\n onPaymentRequired(hook: PaymentRequiredHook): this {\n this.paymentRequiredHooks.push(hook);\n return this;\n }\n\n /**\n * Run hooks and return headers if any hook provides them.\n *\n * @param paymentRequired - The payment required response from the server\n * @returns Headers to use for retry, or null to proceed to payment\n */\n async handlePaymentRequired(\n paymentRequired: PaymentRequired,\n ): Promise<Record<string, string> | null> {\n for (const hook of this.paymentRequiredHooks) {\n const result = await hook({ paymentRequired });\n if (result?.headers) {\n return result.headers;\n }\n }\n return null;\n }\n\n /**\n * Encodes a payment payload into appropriate HTTP headers based on version.\n *\n * @param paymentPayload - The payment payload to encode\n * @returns HTTP headers containing the encoded payment signature\n */\n encodePaymentSignatureHeader(paymentPayload: PaymentPayload): Record<string, string> {\n return {\n \"PAYMENT-SIGNATURE\": encodePaymentSignatureHeader(paymentPayload),\n };\n }\n\n /**\n * Extracts payment required information from HTTP response.\n *\n * @param getHeader - Function to retrieve header value by name (case-insensitive)\n * @returns The payment required object\n */\n getPaymentRequiredResponse(\n getHeader: (name: string) => string | null | undefined,\n ): PaymentRequired {\n const paymentRequired = getHeader(\"PAYMENT-REQUIRED\");\n if (paymentRequired) {\n return decodePaymentRequiredHeader(paymentRequired);\n }\n\n throw new Error(\"Invalid payment required response\");\n }\n\n /**\n * Extracts payment settlement response from HTTP headers.\n *\n * @param getHeader - Function to retrieve header value by name (case-insensitive)\n * @returns The settlement response object\n */\n getPaymentSettleResponse(getHeader: (name: string) => string | null | undefined): SettleResponse {\n const paymentResponse = getHeader(\"PAYMENT-RESPONSE\");\n if (paymentResponse) {\n return decodePaymentResponseHeader(paymentResponse);\n }\n\n throw new Error(\"Payment response header not found\");\n }\n\n /**\n * Creates a payment payload for the given payment requirements.\n * Delegates to the underlying x402Client.\n *\n * @param paymentRequired - The payment required response from the server\n * @returns Promise resolving to the payment payload\n */\n async createPaymentPayload(paymentRequired: PaymentRequired): Promise<PaymentPayload> {\n return this.client.createPaymentPayload(paymentRequired);\n }\n}\n"],"mappings":"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","names":["import_viem","import_zod","decodeAccessProof","errorReason","settleResponse","failure","response","hasSubscriptionCapability","verifyResult"]}