@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.
- package/dist/cjs/OKXFacilitatorClient-Bqyw9fzj.d.ts +69 -0
- package/dist/cjs/client/index.d.ts +1 -1
- package/dist/cjs/client/index.js +34 -0
- package/dist/cjs/client/index.js.map +1 -1
- package/dist/cjs/facilitator/index.d.ts +2 -2
- package/dist/cjs/facilitator/index.js +166 -4
- package/dist/cjs/facilitator/index.js.map +1 -1
- package/dist/cjs/http/index.d.ts +5 -3
- package/dist/cjs/http/index.js +1241 -7
- package/dist/cjs/http/index.js.map +1 -1
- package/dist/cjs/index-2gWfiUbK.d.ts +713 -0
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +166 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/{mechanisms-sojpSwWW.d.ts → mechanisms-LhI9qkRo.d.ts} +509 -1
- package/dist/cjs/server/index.d.ts +4 -2
- package/dist/cjs/server/index.js +1256 -7
- package/dist/cjs/server/index.js.map +1 -1
- package/dist/cjs/subscription/index.d.ts +3 -0
- package/dist/cjs/subscription/index.js +600 -0
- package/dist/cjs/subscription/index.js.map +1 -0
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/{x402HTTPResourceServer-CcsAkcgI.d.ts → x402HTTPResourceServer-B0mXzV8r.d.ts} +114 -1
- package/dist/esm/OKXFacilitatorClient-z-cCE5Db.d.mts +69 -0
- package/dist/esm/chunk-4KASWSSY.mjs +257 -0
- package/dist/esm/chunk-4KASWSSY.mjs.map +1 -0
- package/dist/esm/chunk-CKXR4QVD.mjs +274 -0
- package/dist/esm/chunk-CKXR4QVD.mjs.map +1 -0
- package/dist/esm/{chunk-XBQG2CDV.mjs → chunk-EYS4TWVA.mjs} +617 -9
- package/dist/esm/chunk-EYS4TWVA.mjs.map +1 -0
- package/dist/esm/client/index.d.mts +1 -1
- package/dist/esm/client/index.mjs +3 -2
- package/dist/esm/client/index.mjs.map +1 -1
- package/dist/esm/facilitator/index.d.mts +2 -2
- package/dist/esm/facilitator/index.mjs +2 -1
- package/dist/esm/facilitator/index.mjs.map +1 -1
- package/dist/esm/http/index.d.mts +5 -3
- package/dist/esm/http/index.mjs +3 -2
- package/dist/esm/index-DKbqlTu_.d.mts +713 -0
- package/dist/esm/index.d.mts +2 -2
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/{mechanisms-sojpSwWW.d.mts → mechanisms-LhI9qkRo.d.mts} +509 -1
- package/dist/esm/server/index.d.mts +4 -2
- package/dist/esm/server/index.mjs +3 -2
- package/dist/esm/subscription/index.d.mts +3 -0
- package/dist/esm/subscription/index.mjs +309 -0
- package/dist/esm/subscription/index.mjs.map +1 -0
- package/dist/esm/types/index.d.mts +1 -1
- package/dist/esm/utils/index.d.mts +1 -1
- package/dist/esm/{x402HTTPResourceServer-DBeutKxq.d.mts → x402HTTPResourceServer-56Tq3Jup.d.mts} +114 -1
- package/package.json +12 -1
- package/dist/cjs/OKXFacilitatorClient-BvyQB1QM.d.ts +0 -59
- package/dist/esm/OKXFacilitatorClient-D5E3LX50.d.mts +0 -59
- package/dist/esm/chunk-O3IYMTNT.mjs +0 -118
- package/dist/esm/chunk-O3IYMTNT.mjs.map +0 -1
- package/dist/esm/chunk-XBQG2CDV.mjs.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { d as FacilitatorClient, h as SupportedResponse, P as PaymentPayload, a as PaymentRequirements, V as VerifyResponse, S as SettleResponse, i as SettleStatusResponse, j as FacilitatorEnvelope, k as FacilitatorSubscribeData, l as FacilitatorChangeData, C as CancelAuth, m as FacilitatorCancelData, n as PendingChangeCancelAuth, o as FacilitatorCancelPendingData, p as FacilitatorChargeData, q as FacilitatorFinalizeExpiredData, r as FacilitatorGetChargesData, s as FacilitatorPendingChangeRow, t as FacilitatorGetSubscriptionData } from './mechanisms-LhI9qkRo.js';
|
|
2
|
+
|
|
3
|
+
interface OKXConfig {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
secretKey: string;
|
|
6
|
+
passphrase: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/**
|
|
9
|
+
* OKX exact-scheme extension: when true, the settle call tells the facilitator to
|
|
10
|
+
* wait for on-chain confirmation before responding (syncSettle=true in request body).
|
|
11
|
+
* The facilitator then returns status="success" directly (no polling needed).
|
|
12
|
+
* When false (default), the facilitator responds with status="pending" immediately.
|
|
13
|
+
*/
|
|
14
|
+
syncSettle?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* OKX facilitator client implementing the FacilitatorClient interface.
|
|
18
|
+
* Uses HMAC-SHA256 signing per OKX REST API authentication spec.
|
|
19
|
+
*/
|
|
20
|
+
declare class OKXFacilitatorClient implements FacilitatorClient {
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: OKXConfig);
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param method
|
|
26
|
+
* @param path
|
|
27
|
+
* @param body
|
|
28
|
+
*/
|
|
29
|
+
private createHeaders;
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
getSupported(): Promise<SupportedResponse>;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param payload
|
|
37
|
+
* @param requirements
|
|
38
|
+
*/
|
|
39
|
+
verify(payload: PaymentPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param payload
|
|
43
|
+
* @param requirements
|
|
44
|
+
*/
|
|
45
|
+
settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
|
|
46
|
+
/**
|
|
47
|
+
* Query on-chain settlement status by transaction hash.
|
|
48
|
+
*
|
|
49
|
+
* @param txHash - The transaction hash to query
|
|
50
|
+
* @returns Settlement status response
|
|
51
|
+
*/
|
|
52
|
+
getSettleStatus(txHash: string): Promise<SettleStatusResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* Build `{chainIndex, terms, permit, termsSig, permitSig, syncSettle}` —
|
|
55
|
+
* request body shared by subscribe / change endpoints.
|
|
56
|
+
*/
|
|
57
|
+
private buildWriteBody;
|
|
58
|
+
subscribe(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorSubscribeData>>;
|
|
59
|
+
changeSubscription(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements, oldSubId: string, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorChangeData>>;
|
|
60
|
+
cancelSubscription(subId: string, cancelAuth: CancelAuth, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorCancelData>>;
|
|
61
|
+
cancelPendingChange(subId: string, cancelAuth: PendingChangeCancelAuth, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorCancelPendingData>>;
|
|
62
|
+
chargeSubscription(subId: string, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorChargeData>>;
|
|
63
|
+
finalizeExpired(subId: string, syncSettle?: boolean): Promise<FacilitatorEnvelope<FacilitatorFinalizeExpiredData>>;
|
|
64
|
+
getCharges(subId: string, limit?: number, offset?: number): Promise<FacilitatorEnvelope<FacilitatorGetChargesData>>;
|
|
65
|
+
getPendingChange(subId: string): Promise<FacilitatorEnvelope<FacilitatorPendingChangeRow | null>>;
|
|
66
|
+
getSubscription(subId: string): Promise<FacilitatorEnvelope<FacilitatorGetSubscriptionData>>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { type OKXConfig as O, OKXFacilitatorClient as a };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as PaymentRequired, a as PaymentRequirements, P as PaymentPayload, N as Network,
|
|
1
|
+
import { c as PaymentRequired, a as PaymentRequirements, P as PaymentPayload, N as Network, a9 as SchemeNetworkClient, S as SettleResponse } from '../mechanisms-LhI9qkRo.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Client Hook Context Interfaces
|
package/dist/cjs/client/index.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,31 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/subscription/codec/typed-data.ts
|
|
34
|
+
var import_viem, ZERO_BYTES32;
|
|
35
|
+
var init_typed_data = __esm({
|
|
36
|
+
"src/subscription/codec/typed-data.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
import_viem = require("viem");
|
|
39
|
+
ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// src/subscription/codec/base64.ts
|
|
44
|
+
var init_base64 = __esm({
|
|
45
|
+
"src/subscription/codec/base64.ts"() {
|
|
46
|
+
"use strict";
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// src/subscription/codec/payload.ts
|
|
51
|
+
var init_payload = __esm({
|
|
52
|
+
"src/subscription/codec/payload.ts"() {
|
|
53
|
+
"use strict";
|
|
54
|
+
init_base64();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
30
58
|
// src/client/index.ts
|
|
31
59
|
var client_exports = {};
|
|
32
60
|
__export(client_exports, {
|
|
@@ -37,6 +65,8 @@ module.exports = __toCommonJS(client_exports);
|
|
|
37
65
|
|
|
38
66
|
// src/facilitator/OKXFacilitatorClient.ts
|
|
39
67
|
var import_node_crypto = __toESM(require("crypto"));
|
|
68
|
+
init_typed_data();
|
|
69
|
+
init_payload();
|
|
40
70
|
|
|
41
71
|
// src/index.ts
|
|
42
72
|
var x402Version = 2;
|
|
@@ -382,6 +412,10 @@ var x402Client = class _x402Client {
|
|
|
382
412
|
}
|
|
383
413
|
};
|
|
384
414
|
|
|
415
|
+
// src/http/httpFacilitatorClient.ts
|
|
416
|
+
init_typed_data();
|
|
417
|
+
init_payload();
|
|
418
|
+
|
|
385
419
|
// src/schemas/index.ts
|
|
386
420
|
var import_zod = require("zod");
|
|
387
421
|
var import_zod2 = require("zod");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/client/index.ts","../../../src/facilitator/OKXFacilitatorClient.ts","../../../src/index.ts","../../../src/utils/index.ts","../../../src/client/x402Client.ts","../../../src/schemas/index.ts","../../../src/http/httpFacilitatorClient.ts","../../../src/http/index.ts","../../../src/http/x402HTTPClient.ts"],"sourcesContent":["export * from \"./x402Client\";\nexport * from \"../http/x402HTTPClient\";","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 { 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 { x402Version } from \"..\";\nimport { SchemeNetworkClient } from \"../types/mechanisms\";\nimport { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport { Network, PaymentRequired } from \"../types\";\nimport { findByNetworkAndScheme, findSchemesByNetwork } from \"../utils\";\n\n/**\n * Client Hook Context Interfaces\n */\n\nexport interface PaymentCreationContext {\n paymentRequired: PaymentRequired;\n selectedRequirements: PaymentRequirements;\n}\n\nexport interface PaymentCreatedContext extends PaymentCreationContext {\n paymentPayload: PaymentPayload;\n}\n\nexport interface PaymentCreationFailureContext extends PaymentCreationContext {\n error: Error;\n}\n\n/**\n * Client Hook Type Definitions\n */\n\nexport type BeforePaymentCreationHook = (\n context: PaymentCreationContext,\n) => Promise<void | { abort: true; reason: string }>;\n\nexport type AfterPaymentCreationHook = (context: PaymentCreatedContext) => Promise<void>;\n\nexport type OnPaymentCreationFailureHook = (\n context: PaymentCreationFailureContext,\n) => Promise<void | { recovered: true; payload: PaymentPayload }>;\n\nexport type SelectPaymentRequirements = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements;\n\n/**\n * Extension that can enrich payment payloads on the client side.\n *\n * Client extensions are invoked after the scheme creates the base payment payload\n * but before it is returned. This allows mechanism-specific logic (e.g., EVM EIP-2612\n * permit signing) to enrich the payload's extensions data.\n */\nexport interface ClientExtension {\n /**\n * Unique key identifying this extension (e.g., \"eip2612GasSponsoring\").\n * Must match the extension key used in PaymentRequired.extensions.\n */\n key: string;\n\n /**\n * Called after payload creation when the extension key is present in\n * paymentRequired.extensions. Allows the extension to enrich the payload\n * with extension-specific data (e.g., signing an EIP-2612 permit).\n *\n * @param paymentPayload - The payment payload to enrich\n * @param paymentRequired - The original PaymentRequired response\n * @returns The enriched payment payload\n */\n enrichPaymentPayload?: (\n paymentPayload: PaymentPayload,\n paymentRequired: PaymentRequired,\n ) => Promise<PaymentPayload>;\n}\n\n/**\n * A policy function that filters or transforms payment requirements.\n * Policies are applied in order before the selector chooses the final option.\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - Array of payment requirements to filter/transform\n * @returns Filtered array of payment requirements\n */\nexport type PaymentPolicy = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements[];\n\n\n/**\n * Configuration for registering a payment scheme with a specific network\n */\nexport interface SchemeRegistration {\n /**\n * The network identifier (e.g., 'eip155:196', 'eip155:196')\n */\n network: Network;\n\n /**\n * The scheme client implementation for this network\n */\n client: SchemeNetworkClient;\n\n /**\n * The x402 protocol version to use for this scheme\n *\n * @default 2\n */\n x402Version?: number;\n}\n\n/**\n * Configuration options for the fetch wrapper\n */\nexport interface x402ClientConfig {\n /**\n * Array of scheme registrations defining which payment methods are supported\n */\n schemes: SchemeRegistration[];\n\n /**\n * Policies to apply to the client\n */\n policies?: PaymentPolicy[];\n\n /**\n * Custom payment requirements selector function\n * If not provided, uses the default selector (first available option)\n */\n paymentRequirementsSelector?: SelectPaymentRequirements;\n}\n\n/**\n * Core client for managing x402 payment schemes and creating payment payloads.\n *\n * Handles registration of payment schemes, policy-based filtering of payment requirements,\n * and creation of payment payloads based on server requirements.\n */\nexport class x402Client {\n private readonly paymentRequirementsSelector: SelectPaymentRequirements;\n private readonly registeredClientSchemes: Map<number, Map<string, Map<string, SchemeNetworkClient>>> = new Map();\n private readonly policies: PaymentPolicy[] = [];\n private readonly registeredExtensions: Map<string, ClientExtension> = new Map();\n\n private beforePaymentCreationHooks: BeforePaymentCreationHook[] = [];\n private afterPaymentCreationHooks: AfterPaymentCreationHook[] = [];\n private onPaymentCreationFailureHooks: OnPaymentCreationFailureHook[] = [];\n\n /**\n * Creates a new x402Client instance.\n *\n * @param paymentRequirementsSelector - Function to select payment requirements from available options\n */\n constructor(paymentRequirementsSelector?: SelectPaymentRequirements) {\n this.paymentRequirementsSelector = paymentRequirementsSelector || ((x402Version, accepts) => accepts[0]);\n }\n\n /**\n * Creates a new x402Client instance from a configuration object.\n *\n * @param config - The client configuration including schemes, policies, and payment requirements selector\n * @returns A configured x402Client instance\n */\n static fromConfig(config: x402ClientConfig): x402Client {\n const client = new x402Client(config.paymentRequirementsSelector);\n config.schemes.forEach(scheme => {\n client.register(scheme.network, scheme.client);\n });\n config.policies?.forEach(policy => {\n client.registerPolicy(policy);\n });\n return client;\n }\n\n /**\n * Registers a scheme client for the current x402 version.\n *\n * @param network - The network to register the client for\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n register(network: Network, client: SchemeNetworkClient): x402Client {\n return this._registerScheme(x402Version, network, client);\n }\n\n /**\n * Registers a policy to filter or transform payment requirements.\n *\n * Policies are applied in order after filtering by registered schemes\n * and before the selector chooses the final payment requirement.\n *\n * @param policy - Function to filter/transform payment requirements\n * @returns The x402Client instance for chaining\n *\n * @example\n * ```typescript\n * // Prefer cheaper options\n * client.registerPolicy((version, reqs) =>\n * reqs.filter(r => BigInt(r.value) < BigInt('1000000'))\n * );\n *\n * // Prefer specific networks\n * client.registerPolicy((version, reqs) =>\n * reqs.filter(r => r.network.startsWith('eip155:'))\n * );\n * ```\n */\n registerPolicy(policy: PaymentPolicy): x402Client {\n this.policies.push(policy);\n return this;\n }\n\n /**\n * Registers a client extension that can enrich payment payloads.\n *\n * Extensions are invoked after the scheme creates the base payload and the\n * payload is wrapped with extensions/resource/accepted data. If the extension's\n * key is present in `paymentRequired.extensions`, the extension's\n * `enrichPaymentPayload` hook is called to modify the payload.\n *\n * @param extension - The client extension to register\n * @returns The x402Client instance for chaining\n */\n registerExtension(extension: ClientExtension): x402Client {\n this.registeredExtensions.set(extension.key, extension);\n return this;\n }\n\n /**\n * Register a hook to execute before payment payload creation.\n * Can abort creation by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onBeforePaymentCreation(hook: BeforePaymentCreationHook): x402Client {\n this.beforePaymentCreationHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment payload creation.\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onAfterPaymentCreation(hook: AfterPaymentCreationHook): x402Client {\n this.afterPaymentCreationHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment payload creation fails.\n * Can recover from failure by returning { recovered: true, payload: PaymentPayload }\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onPaymentCreationFailure(hook: OnPaymentCreationFailureHook): x402Client {\n this.onPaymentCreationFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Creates a payment payload based on a PaymentRequired response.\n *\n * Automatically extracts x402Version, resource, and extensions from the PaymentRequired\n * response and constructs a complete PaymentPayload with the accepted requirements.\n *\n * @param paymentRequired - The PaymentRequired response from the server\n * @returns Promise resolving to the complete payment payload\n */\n async createPaymentPayload(\n paymentRequired: PaymentRequired,\n ): Promise<PaymentPayload> {\n const clientSchemesByNetwork = this.registeredClientSchemes.get(paymentRequired.x402Version);\n if (!clientSchemesByNetwork) {\n throw new Error(`No client registered for x402 version: ${paymentRequired.x402Version}`);\n }\n\n const requirements = this.selectPaymentRequirements(paymentRequired.x402Version, paymentRequired.accepts);\n\n const context: PaymentCreationContext = {\n paymentRequired,\n selectedRequirements: requirements,\n };\n\n // Execute beforePaymentCreation hooks\n for (const hook of this.beforePaymentCreationHooks) {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n throw new Error(`Payment creation aborted: ${result.reason}`);\n }\n }\n\n try {\n const schemeNetworkClient = findByNetworkAndScheme(clientSchemesByNetwork, requirements.scheme, requirements.network);\n if (!schemeNetworkClient) {\n throw new Error(`No client registered for scheme: ${requirements.scheme} and network: ${requirements.network}`);\n }\n\n const partialPayload = await schemeNetworkClient.createPaymentPayload(\n paymentRequired.x402Version,\n requirements,\n { extensions: paymentRequired.extensions },\n );\n\n // Merge server-declared extensions with any scheme-provided extensions.\n // Scheme extensions overlay on top (e.g., EIP-2612 info enriches server declaration).\n const mergedExtensions = this.mergeExtensions(\n paymentRequired.extensions,\n partialPayload.extensions,\n );\n\n // Apply acceptedExtraOverrides: OKX extension for injecting scheme-specific\n // fields (e.g. sessionCert) into accepted.extra per the OKX API spec.\n const acceptedRequirements =\n partialPayload.acceptedExtraOverrides && Object.keys(partialPayload.acceptedExtraOverrides).length > 0\n ? {\n ...requirements,\n extra: {\n ...requirements.extra,\n ...partialPayload.acceptedExtraOverrides,\n },\n }\n : requirements;\n\n let paymentPayload: PaymentPayload = {\n x402Version: partialPayload.x402Version,\n payload: partialPayload.payload,\n extensions: mergedExtensions,\n resource: paymentRequired.resource,\n accepted: acceptedRequirements,\n };\n\n // Enrich payload via registered client extensions (for non-scheme extensions)\n paymentPayload = await this.enrichPaymentPayloadWithExtensions(paymentPayload, paymentRequired);\n\n // Execute afterPaymentCreation hooks\n const createdContext: PaymentCreatedContext = {\n ...context,\n paymentPayload,\n };\n\n for (const hook of this.afterPaymentCreationHooks) {\n await hook(createdContext);\n }\n\n return paymentPayload;\n } catch (error) {\n const failureContext: PaymentCreationFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onPaymentCreationFailure hooks\n for (const hook of this.onPaymentCreationFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.payload;\n }\n }\n\n throw error;\n }\n }\n\n\n\n /**\n * Merges server-declared extensions with scheme-provided extensions.\n * Scheme extensions overlay on top of server extensions at each key,\n * preserving server-provided schema while overlaying scheme-provided info.\n *\n * @param serverExtensions - Extensions declared by the server in the 402 response\n * @param schemeExtensions - Extensions provided by the scheme client (e.g. EIP-2612)\n * @returns The merged extensions object, or undefined if both inputs are undefined\n */\n private mergeExtensions(\n serverExtensions?: Record<string, unknown>,\n schemeExtensions?: Record<string, unknown>,\n ): Record<string, unknown> | undefined {\n if (!schemeExtensions) return serverExtensions;\n if (!serverExtensions) return schemeExtensions;\n\n const merged = { ...serverExtensions };\n for (const [key, schemeValue] of Object.entries(schemeExtensions)) {\n const serverValue = merged[key];\n if (\n serverValue &&\n typeof serverValue === \"object\" &&\n schemeValue &&\n typeof schemeValue === \"object\"\n ) {\n // Deep merge: scheme info overlays server info, schema preserved\n merged[key] = { ...serverValue as Record<string, unknown>, ...schemeValue as Record<string, unknown> };\n } else {\n merged[key] = schemeValue;\n }\n }\n return merged;\n }\n\n /**\n * Enriches a payment payload by calling registered extension hooks.\n * For each extension key present in the PaymentRequired response,\n * invokes the corresponding extension's enrichPaymentPayload callback.\n *\n * @param paymentPayload - The payment payload to enrich with extension data\n * @param paymentRequired - The PaymentRequired response containing extension declarations\n * @returns The enriched payment payload with extension data applied\n */\n private async enrichPaymentPayloadWithExtensions(\n paymentPayload: PaymentPayload,\n paymentRequired: PaymentRequired,\n ): Promise<PaymentPayload> {\n if (!paymentRequired.extensions || this.registeredExtensions.size === 0) {\n return paymentPayload;\n }\n\n let enriched = paymentPayload;\n for (const [key, extension] of this.registeredExtensions) {\n if (key in paymentRequired.extensions && extension.enrichPaymentPayload) {\n enriched = await extension.enrichPaymentPayload(enriched, paymentRequired);\n }\n }\n\n return enriched;\n }\n\n /**\n * Selects appropriate payment requirements based on registered clients and policies.\n *\n * Selection process:\n * 1. Filter by registered schemes (network + scheme support)\n * 2. Apply all registered policies in order\n * 3. Use selector to choose final requirement\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - Array of available payment requirements\n * @returns The selected payment requirements\n */\n private selectPaymentRequirements(x402Version: number, paymentRequirements: PaymentRequirements[]): PaymentRequirements {\n const clientSchemesByNetwork = this.registeredClientSchemes.get(x402Version);\n if (!clientSchemesByNetwork) {\n throw new Error(`No client registered for x402 version: ${x402Version}`);\n }\n\n // Step 1: Filter by registered schemes\n const supportedPaymentRequirements = paymentRequirements.filter(requirement => {\n let clientSchemes = findSchemesByNetwork(clientSchemesByNetwork, requirement.network);\n if (!clientSchemes) {\n return false;\n }\n\n return clientSchemes.has(requirement.scheme);\n })\n\n if (supportedPaymentRequirements.length === 0) {\n throw new Error(`No network/scheme registered for x402 version: ${x402Version} which comply with the payment requirements. ${JSON.stringify({\n x402Version,\n paymentRequirements,\n x402Versions: Array.from(this.registeredClientSchemes.keys()),\n networks: Array.from(clientSchemesByNetwork.keys()),\n schemes: Array.from(clientSchemesByNetwork.values()).map(schemes => Array.from(schemes.keys())).flat(),\n })}`);\n }\n\n // Step 2: Apply all policies in order\n let filteredRequirements = supportedPaymentRequirements;\n for (const policy of this.policies) {\n filteredRequirements = policy(x402Version, filteredRequirements);\n\n if (filteredRequirements.length === 0) {\n throw new Error(`All payment requirements were filtered out by policies for x402 version: ${x402Version}`);\n }\n }\n\n // Step 3: Use selector to choose final requirement\n return this.paymentRequirementsSelector(x402Version, filteredRequirements);\n }\n\n /**\n * Internal method to register a scheme client.\n *\n * @param x402Version - The x402 protocol version\n * @param network - The network to register the client for\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n private _registerScheme(x402Version: number, network: Network, client: SchemeNetworkClient): x402Client {\n if (!this.registeredClientSchemes.has(x402Version)) {\n this.registeredClientSchemes.set(x402Version, new Map());\n }\n const clientSchemesByNetwork = this.registeredClientSchemes.get(x402Version)!;\n if (!clientSchemesByNetwork.has(network)) {\n clientSchemesByNetwork.set(network, new Map());\n }\n\n const clientByScheme = clientSchemesByNetwork.get(network)!;\n if (!clientByScheme.has(client.scheme)) {\n clientByScheme.set(client.scheme, client);\n }\n\n return this;\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 { 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 { 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 {\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":["x402Version","import_zod"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/subscription/codec/typed-data.ts","../../../src/subscription/codec/base64.ts","../../../src/subscription/codec/payload.ts","../../../src/client/index.ts","../../../src/facilitator/OKXFacilitatorClient.ts","../../../src/index.ts","../../../src/utils/index.ts","../../../src/client/x402Client.ts","../../../src/http/httpFacilitatorClient.ts","../../../src/schemas/index.ts","../../../src/http/index.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","export * from \"./x402Client\";\nexport * from \"../http/x402HTTPClient\";","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 { 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 { x402Version } from \"..\";\nimport { SchemeNetworkClient } from \"../types/mechanisms\";\nimport { PaymentPayload, PaymentRequirements } from \"../types/payments\";\nimport { Network, PaymentRequired } from \"../types\";\nimport { findByNetworkAndScheme, findSchemesByNetwork } from \"../utils\";\n\n/**\n * Client Hook Context Interfaces\n */\n\nexport interface PaymentCreationContext {\n paymentRequired: PaymentRequired;\n selectedRequirements: PaymentRequirements;\n}\n\nexport interface PaymentCreatedContext extends PaymentCreationContext {\n paymentPayload: PaymentPayload;\n}\n\nexport interface PaymentCreationFailureContext extends PaymentCreationContext {\n error: Error;\n}\n\n/**\n * Client Hook Type Definitions\n */\n\nexport type BeforePaymentCreationHook = (\n context: PaymentCreationContext,\n) => Promise<void | { abort: true; reason: string }>;\n\nexport type AfterPaymentCreationHook = (context: PaymentCreatedContext) => Promise<void>;\n\nexport type OnPaymentCreationFailureHook = (\n context: PaymentCreationFailureContext,\n) => Promise<void | { recovered: true; payload: PaymentPayload }>;\n\nexport type SelectPaymentRequirements = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements;\n\n/**\n * Extension that can enrich payment payloads on the client side.\n *\n * Client extensions are invoked after the scheme creates the base payment payload\n * but before it is returned. This allows mechanism-specific logic (e.g., EVM EIP-2612\n * permit signing) to enrich the payload's extensions data.\n */\nexport interface ClientExtension {\n /**\n * Unique key identifying this extension (e.g., \"eip2612GasSponsoring\").\n * Must match the extension key used in PaymentRequired.extensions.\n */\n key: string;\n\n /**\n * Called after payload creation when the extension key is present in\n * paymentRequired.extensions. Allows the extension to enrich the payload\n * with extension-specific data (e.g., signing an EIP-2612 permit).\n *\n * @param paymentPayload - The payment payload to enrich\n * @param paymentRequired - The original PaymentRequired response\n * @returns The enriched payment payload\n */\n enrichPaymentPayload?: (\n paymentPayload: PaymentPayload,\n paymentRequired: PaymentRequired,\n ) => Promise<PaymentPayload>;\n}\n\n/**\n * A policy function that filters or transforms payment requirements.\n * Policies are applied in order before the selector chooses the final option.\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - Array of payment requirements to filter/transform\n * @returns Filtered array of payment requirements\n */\nexport type PaymentPolicy = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements[];\n\n\n/**\n * Configuration for registering a payment scheme with a specific network\n */\nexport interface SchemeRegistration {\n /**\n * The network identifier (e.g., 'eip155:196', 'eip155:196')\n */\n network: Network;\n\n /**\n * The scheme client implementation for this network\n */\n client: SchemeNetworkClient;\n\n /**\n * The x402 protocol version to use for this scheme\n *\n * @default 2\n */\n x402Version?: number;\n}\n\n/**\n * Configuration options for the fetch wrapper\n */\nexport interface x402ClientConfig {\n /**\n * Array of scheme registrations defining which payment methods are supported\n */\n schemes: SchemeRegistration[];\n\n /**\n * Policies to apply to the client\n */\n policies?: PaymentPolicy[];\n\n /**\n * Custom payment requirements selector function\n * If not provided, uses the default selector (first available option)\n */\n paymentRequirementsSelector?: SelectPaymentRequirements;\n}\n\n/**\n * Core client for managing x402 payment schemes and creating payment payloads.\n *\n * Handles registration of payment schemes, policy-based filtering of payment requirements,\n * and creation of payment payloads based on server requirements.\n */\nexport class x402Client {\n private readonly paymentRequirementsSelector: SelectPaymentRequirements;\n private readonly registeredClientSchemes: Map<number, Map<string, Map<string, SchemeNetworkClient>>> = new Map();\n private readonly policies: PaymentPolicy[] = [];\n private readonly registeredExtensions: Map<string, ClientExtension> = new Map();\n\n private beforePaymentCreationHooks: BeforePaymentCreationHook[] = [];\n private afterPaymentCreationHooks: AfterPaymentCreationHook[] = [];\n private onPaymentCreationFailureHooks: OnPaymentCreationFailureHook[] = [];\n\n /**\n * Creates a new x402Client instance.\n *\n * @param paymentRequirementsSelector - Function to select payment requirements from available options\n */\n constructor(paymentRequirementsSelector?: SelectPaymentRequirements) {\n this.paymentRequirementsSelector = paymentRequirementsSelector || ((x402Version, accepts) => accepts[0]);\n }\n\n /**\n * Creates a new x402Client instance from a configuration object.\n *\n * @param config - The client configuration including schemes, policies, and payment requirements selector\n * @returns A configured x402Client instance\n */\n static fromConfig(config: x402ClientConfig): x402Client {\n const client = new x402Client(config.paymentRequirementsSelector);\n config.schemes.forEach(scheme => {\n client.register(scheme.network, scheme.client);\n });\n config.policies?.forEach(policy => {\n client.registerPolicy(policy);\n });\n return client;\n }\n\n /**\n * Registers a scheme client for the current x402 version.\n *\n * @param network - The network to register the client for\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n register(network: Network, client: SchemeNetworkClient): x402Client {\n return this._registerScheme(x402Version, network, client);\n }\n\n /**\n * Registers a policy to filter or transform payment requirements.\n *\n * Policies are applied in order after filtering by registered schemes\n * and before the selector chooses the final payment requirement.\n *\n * @param policy - Function to filter/transform payment requirements\n * @returns The x402Client instance for chaining\n *\n * @example\n * ```typescript\n * // Prefer cheaper options\n * client.registerPolicy((version, reqs) =>\n * reqs.filter(r => BigInt(r.value) < BigInt('1000000'))\n * );\n *\n * // Prefer specific networks\n * client.registerPolicy((version, reqs) =>\n * reqs.filter(r => r.network.startsWith('eip155:'))\n * );\n * ```\n */\n registerPolicy(policy: PaymentPolicy): x402Client {\n this.policies.push(policy);\n return this;\n }\n\n /**\n * Registers a client extension that can enrich payment payloads.\n *\n * Extensions are invoked after the scheme creates the base payload and the\n * payload is wrapped with extensions/resource/accepted data. If the extension's\n * key is present in `paymentRequired.extensions`, the extension's\n * `enrichPaymentPayload` hook is called to modify the payload.\n *\n * @param extension - The client extension to register\n * @returns The x402Client instance for chaining\n */\n registerExtension(extension: ClientExtension): x402Client {\n this.registeredExtensions.set(extension.key, extension);\n return this;\n }\n\n /**\n * Register a hook to execute before payment payload creation.\n * Can abort creation by returning { abort: true, reason: string }\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onBeforePaymentCreation(hook: BeforePaymentCreationHook): x402Client {\n this.beforePaymentCreationHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute after successful payment payload creation.\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onAfterPaymentCreation(hook: AfterPaymentCreationHook): x402Client {\n this.afterPaymentCreationHooks.push(hook);\n return this;\n }\n\n /**\n * Register a hook to execute when payment payload creation fails.\n * Can recover from failure by returning { recovered: true, payload: PaymentPayload }\n *\n * @param hook - The hook function to register\n * @returns The x402Client instance for chaining\n */\n onPaymentCreationFailure(hook: OnPaymentCreationFailureHook): x402Client {\n this.onPaymentCreationFailureHooks.push(hook);\n return this;\n }\n\n /**\n * Creates a payment payload based on a PaymentRequired response.\n *\n * Automatically extracts x402Version, resource, and extensions from the PaymentRequired\n * response and constructs a complete PaymentPayload with the accepted requirements.\n *\n * @param paymentRequired - The PaymentRequired response from the server\n * @returns Promise resolving to the complete payment payload\n */\n async createPaymentPayload(\n paymentRequired: PaymentRequired,\n ): Promise<PaymentPayload> {\n const clientSchemesByNetwork = this.registeredClientSchemes.get(paymentRequired.x402Version);\n if (!clientSchemesByNetwork) {\n throw new Error(`No client registered for x402 version: ${paymentRequired.x402Version}`);\n }\n\n const requirements = this.selectPaymentRequirements(paymentRequired.x402Version, paymentRequired.accepts);\n\n const context: PaymentCreationContext = {\n paymentRequired,\n selectedRequirements: requirements,\n };\n\n // Execute beforePaymentCreation hooks\n for (const hook of this.beforePaymentCreationHooks) {\n const result = await hook(context);\n if (result && \"abort\" in result && result.abort) {\n throw new Error(`Payment creation aborted: ${result.reason}`);\n }\n }\n\n try {\n const schemeNetworkClient = findByNetworkAndScheme(clientSchemesByNetwork, requirements.scheme, requirements.network);\n if (!schemeNetworkClient) {\n throw new Error(`No client registered for scheme: ${requirements.scheme} and network: ${requirements.network}`);\n }\n\n const partialPayload = await schemeNetworkClient.createPaymentPayload(\n paymentRequired.x402Version,\n requirements,\n { extensions: paymentRequired.extensions },\n );\n\n // Merge server-declared extensions with any scheme-provided extensions.\n // Scheme extensions overlay on top (e.g., EIP-2612 info enriches server declaration).\n const mergedExtensions = this.mergeExtensions(\n paymentRequired.extensions,\n partialPayload.extensions,\n );\n\n // Apply acceptedExtraOverrides: OKX extension for injecting scheme-specific\n // fields (e.g. sessionCert) into accepted.extra per the OKX API spec.\n const acceptedRequirements =\n partialPayload.acceptedExtraOverrides && Object.keys(partialPayload.acceptedExtraOverrides).length > 0\n ? {\n ...requirements,\n extra: {\n ...requirements.extra,\n ...partialPayload.acceptedExtraOverrides,\n },\n }\n : requirements;\n\n let paymentPayload: PaymentPayload = {\n x402Version: partialPayload.x402Version,\n payload: partialPayload.payload,\n extensions: mergedExtensions,\n resource: paymentRequired.resource,\n accepted: acceptedRequirements,\n };\n\n // Enrich payload via registered client extensions (for non-scheme extensions)\n paymentPayload = await this.enrichPaymentPayloadWithExtensions(paymentPayload, paymentRequired);\n\n // Execute afterPaymentCreation hooks\n const createdContext: PaymentCreatedContext = {\n ...context,\n paymentPayload,\n };\n\n for (const hook of this.afterPaymentCreationHooks) {\n await hook(createdContext);\n }\n\n return paymentPayload;\n } catch (error) {\n const failureContext: PaymentCreationFailureContext = {\n ...context,\n error: error as Error,\n };\n\n // Execute onPaymentCreationFailure hooks\n for (const hook of this.onPaymentCreationFailureHooks) {\n const result = await hook(failureContext);\n if (result && \"recovered\" in result && result.recovered) {\n return result.payload;\n }\n }\n\n throw error;\n }\n }\n\n\n\n /**\n * Merges server-declared extensions with scheme-provided extensions.\n * Scheme extensions overlay on top of server extensions at each key,\n * preserving server-provided schema while overlaying scheme-provided info.\n *\n * @param serverExtensions - Extensions declared by the server in the 402 response\n * @param schemeExtensions - Extensions provided by the scheme client (e.g. EIP-2612)\n * @returns The merged extensions object, or undefined if both inputs are undefined\n */\n private mergeExtensions(\n serverExtensions?: Record<string, unknown>,\n schemeExtensions?: Record<string, unknown>,\n ): Record<string, unknown> | undefined {\n if (!schemeExtensions) return serverExtensions;\n if (!serverExtensions) return schemeExtensions;\n\n const merged = { ...serverExtensions };\n for (const [key, schemeValue] of Object.entries(schemeExtensions)) {\n const serverValue = merged[key];\n if (\n serverValue &&\n typeof serverValue === \"object\" &&\n schemeValue &&\n typeof schemeValue === \"object\"\n ) {\n // Deep merge: scheme info overlays server info, schema preserved\n merged[key] = { ...serverValue as Record<string, unknown>, ...schemeValue as Record<string, unknown> };\n } else {\n merged[key] = schemeValue;\n }\n }\n return merged;\n }\n\n /**\n * Enriches a payment payload by calling registered extension hooks.\n * For each extension key present in the PaymentRequired response,\n * invokes the corresponding extension's enrichPaymentPayload callback.\n *\n * @param paymentPayload - The payment payload to enrich with extension data\n * @param paymentRequired - The PaymentRequired response containing extension declarations\n * @returns The enriched payment payload with extension data applied\n */\n private async enrichPaymentPayloadWithExtensions(\n paymentPayload: PaymentPayload,\n paymentRequired: PaymentRequired,\n ): Promise<PaymentPayload> {\n if (!paymentRequired.extensions || this.registeredExtensions.size === 0) {\n return paymentPayload;\n }\n\n let enriched = paymentPayload;\n for (const [key, extension] of this.registeredExtensions) {\n if (key in paymentRequired.extensions && extension.enrichPaymentPayload) {\n enriched = await extension.enrichPaymentPayload(enriched, paymentRequired);\n }\n }\n\n return enriched;\n }\n\n /**\n * Selects appropriate payment requirements based on registered clients and policies.\n *\n * Selection process:\n * 1. Filter by registered schemes (network + scheme support)\n * 2. Apply all registered policies in order\n * 3. Use selector to choose final requirement\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - Array of available payment requirements\n * @returns The selected payment requirements\n */\n private selectPaymentRequirements(x402Version: number, paymentRequirements: PaymentRequirements[]): PaymentRequirements {\n const clientSchemesByNetwork = this.registeredClientSchemes.get(x402Version);\n if (!clientSchemesByNetwork) {\n throw new Error(`No client registered for x402 version: ${x402Version}`);\n }\n\n // Step 1: Filter by registered schemes\n const supportedPaymentRequirements = paymentRequirements.filter(requirement => {\n let clientSchemes = findSchemesByNetwork(clientSchemesByNetwork, requirement.network);\n if (!clientSchemes) {\n return false;\n }\n\n return clientSchemes.has(requirement.scheme);\n })\n\n if (supportedPaymentRequirements.length === 0) {\n throw new Error(`No network/scheme registered for x402 version: ${x402Version} which comply with the payment requirements. ${JSON.stringify({\n x402Version,\n paymentRequirements,\n x402Versions: Array.from(this.registeredClientSchemes.keys()),\n networks: Array.from(clientSchemesByNetwork.keys()),\n schemes: Array.from(clientSchemesByNetwork.values()).map(schemes => Array.from(schemes.keys())).flat(),\n })}`);\n }\n\n // Step 2: Apply all policies in order\n let filteredRequirements = supportedPaymentRequirements;\n for (const policy of this.policies) {\n filteredRequirements = policy(x402Version, filteredRequirements);\n\n if (filteredRequirements.length === 0) {\n throw new Error(`All payment requirements were filtered out by policies for x402 version: ${x402Version}`);\n }\n }\n\n // Step 3: Use selector to choose final requirement\n return this.paymentRequirementsSelector(x402Version, filteredRequirements);\n }\n\n /**\n * Internal method to register a scheme client.\n *\n * @param x402Version - The x402 protocol version\n * @param network - The network to register the client for\n * @param client - The scheme network client to register\n * @returns The x402Client instance for chaining\n */\n private _registerScheme(x402Version: number, network: Network, client: SchemeNetworkClient): x402Client {\n if (!this.registeredClientSchemes.has(x402Version)) {\n this.registeredClientSchemes.set(x402Version, new Map());\n }\n const clientSchemesByNetwork = this.registeredClientSchemes.get(x402Version)!;\n if (!clientSchemesByNetwork.has(network)) {\n clientSchemesByNetwork.set(network, new Map());\n }\n\n const clientByScheme = clientSchemesByNetwork.get(network)!;\n if (!clientByScheme.has(client.scheme)) {\n clientByScheme.set(client.scheme, client);\n }\n\n return this;\n }\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 { 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 {\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":["x402Version","import_zod"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as PaymentPayload, a as PaymentRequirements, S as SettleResponse, V as VerifyResponse, N as Network, b as SchemeNetworkFacilitator, F as FacilitatorExtension } from '../mechanisms-
|
|
2
|
-
export { O as OKXConfig, a as OKXFacilitatorClient } from '../OKXFacilitatorClient-
|
|
1
|
+
import { P as PaymentPayload, a as PaymentRequirements, S as SettleResponse, V as VerifyResponse, N as Network, b as SchemeNetworkFacilitator, F as FacilitatorExtension } from '../mechanisms-LhI9qkRo.js';
|
|
2
|
+
export { O as OKXConfig, a as OKXFacilitatorClient } from '../OKXFacilitatorClient-Bqyw9fzj.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Facilitator Hook Context Interfaces
|