x402-express-mantle 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +19 -1
  2. package/lib/cjs/index.d.ts +119 -81
  3. package/lib/cjs/index.js +3 -3
  4. package/lib/esm/index.d.mts +5 -5
  5. package/lib/esm/index.mjs +3 -3
  6. package/package.json +4 -3
  7. package/lib/cjs/client/index.d.ts +0 -243
  8. package/lib/cjs/client/index.js +0 -413
  9. package/lib/cjs/client/index.js.map +0 -1
  10. package/lib/cjs/exact/client/index.d.ts +0 -37
  11. package/lib/cjs/exact/client/index.js +0 -281
  12. package/lib/cjs/exact/client/index.js.map +0 -1
  13. package/lib/cjs/exact/facilitator/index.d.ts +0 -110
  14. package/lib/cjs/exact/facilitator/index.js +0 -714
  15. package/lib/cjs/exact/facilitator/index.js.map +0 -1
  16. package/lib/cjs/exact/server/index.d.ts +0 -87
  17. package/lib/cjs/exact/server/index.js +0 -209
  18. package/lib/cjs/exact/server/index.js.map +0 -1
  19. package/lib/cjs/exact/v1/client/index.d.ts +0 -33
  20. package/lib/cjs/exact/v1/client/index.js +0 -169
  21. package/lib/cjs/exact/v1/client/index.js.map +0 -1
  22. package/lib/cjs/exact/v1/facilitator/index.d.ts +0 -71
  23. package/lib/cjs/exact/v1/facilitator/index.js +0 -384
  24. package/lib/cjs/exact/v1/facilitator/index.js.map +0 -1
  25. package/lib/cjs/facilitator/index.d.ts +0 -192
  26. package/lib/cjs/facilitator/index.js +0 -398
  27. package/lib/cjs/facilitator/index.js.map +0 -1
  28. package/lib/cjs/http/index.d.ts +0 -52
  29. package/lib/cjs/http/index.js +0 -827
  30. package/lib/cjs/http/index.js.map +0 -1
  31. package/lib/cjs/mechanisms-CzuGzYsS.d.ts +0 -270
  32. package/lib/cjs/scheme-MoBRXFM8.d.ts +0 -29
  33. package/lib/cjs/server/index.d.ts +0 -2
  34. package/lib/cjs/server/index.js +0 -1305
  35. package/lib/cjs/server/index.js.map +0 -1
  36. package/lib/cjs/signer-5OVDxViv.d.ts +0 -79
  37. package/lib/cjs/signer-BMkbhFYE.d.ts +0 -123
  38. package/lib/cjs/types/index.d.ts +0 -1
  39. package/lib/cjs/types/index.js +0 -66
  40. package/lib/cjs/types/index.js.map +0 -1
  41. package/lib/cjs/types/v1/index.d.ts +0 -1
  42. package/lib/cjs/types/v1/index.js +0 -19
  43. package/lib/cjs/types/v1/index.js.map +0 -1
  44. package/lib/cjs/utils/index.d.ts +0 -48
  45. package/lib/cjs/utils/index.js +0 -116
  46. package/lib/cjs/utils/index.js.map +0 -1
  47. package/lib/cjs/v1/index.d.ts +0 -12
  48. package/lib/cjs/v1/index.js +0 -180
  49. package/lib/cjs/v1/index.js.map +0 -1
  50. package/lib/cjs/x402HTTPResourceServer-D1YtlH_r.d.ts +0 -719
  51. package/lib/esm/chunk-3CEIVWNN.mjs +0 -339
  52. package/lib/esm/chunk-3CEIVWNN.mjs.map +0 -1
  53. package/lib/esm/chunk-BJTO5JO5.mjs +0 -11
  54. package/lib/esm/chunk-BJTO5JO5.mjs.map +0 -1
  55. package/lib/esm/chunk-EEA7DKZI.mjs +0 -111
  56. package/lib/esm/chunk-EEA7DKZI.mjs.map +0 -1
  57. package/lib/esm/chunk-FOUXRQAV.mjs +0 -88
  58. package/lib/esm/chunk-FOUXRQAV.mjs.map +0 -1
  59. package/lib/esm/chunk-IKSTWKEM.mjs +0 -157
  60. package/lib/esm/chunk-IKSTWKEM.mjs.map +0 -1
  61. package/lib/esm/chunk-JYZWCLMP.mjs +0 -305
  62. package/lib/esm/chunk-JYZWCLMP.mjs.map +0 -1
  63. package/lib/esm/chunk-PNSAJQCF.mjs +0 -108
  64. package/lib/esm/chunk-PNSAJQCF.mjs.map +0 -1
  65. package/lib/esm/chunk-PSA4YVU2.mjs +0 -92
  66. package/lib/esm/chunk-PSA4YVU2.mjs.map +0 -1
  67. package/lib/esm/chunk-QLXM7BIB.mjs +0 -23
  68. package/lib/esm/chunk-QLXM7BIB.mjs.map +0 -1
  69. package/lib/esm/chunk-TDLQZ6MP.mjs +0 -86
  70. package/lib/esm/chunk-TDLQZ6MP.mjs.map +0 -1
  71. package/lib/esm/chunk-VE37GDG2.mjs +0 -7
  72. package/lib/esm/chunk-VE37GDG2.mjs.map +0 -1
  73. package/lib/esm/chunk-WWACQNRQ.mjs +0 -7
  74. package/lib/esm/chunk-WWACQNRQ.mjs.map +0 -1
  75. package/lib/esm/chunk-X4W4S5RB.mjs +0 -39
  76. package/lib/esm/chunk-X4W4S5RB.mjs.map +0 -1
  77. package/lib/esm/chunk-Z4QX3O5V.mjs +0 -748
  78. package/lib/esm/chunk-Z4QX3O5V.mjs.map +0 -1
  79. package/lib/esm/chunk-ZYXTTU74.mjs +0 -88
  80. package/lib/esm/chunk-ZYXTTU74.mjs.map +0 -1
  81. package/lib/esm/client/index.d.mts +0 -243
  82. package/lib/esm/client/index.mjs +0 -260
  83. package/lib/esm/client/index.mjs.map +0 -1
  84. package/lib/esm/exact/client/index.d.mts +0 -37
  85. package/lib/esm/exact/client/index.mjs +0 -36
  86. package/lib/esm/exact/client/index.mjs.map +0 -1
  87. package/lib/esm/exact/facilitator/index.d.mts +0 -110
  88. package/lib/esm/exact/facilitator/index.mjs +0 -350
  89. package/lib/esm/exact/facilitator/index.mjs.map +0 -1
  90. package/lib/esm/exact/server/index.d.mts +0 -87
  91. package/lib/esm/exact/server/index.mjs +0 -129
  92. package/lib/esm/exact/server/index.mjs.map +0 -1
  93. package/lib/esm/exact/v1/client/index.d.mts +0 -33
  94. package/lib/esm/exact/v1/client/index.mjs +0 -8
  95. package/lib/esm/exact/v1/client/index.mjs.map +0 -1
  96. package/lib/esm/exact/v1/facilitator/index.d.mts +0 -71
  97. package/lib/esm/exact/v1/facilitator/index.mjs +0 -8
  98. package/lib/esm/exact/v1/facilitator/index.mjs.map +0 -1
  99. package/lib/esm/facilitator/index.d.mts +0 -192
  100. package/lib/esm/facilitator/index.mjs +0 -373
  101. package/lib/esm/facilitator/index.mjs.map +0 -1
  102. package/lib/esm/http/index.d.mts +0 -52
  103. package/lib/esm/http/index.mjs +0 -29
  104. package/lib/esm/http/index.mjs.map +0 -1
  105. package/lib/esm/mechanisms-CzuGzYsS.d.mts +0 -270
  106. package/lib/esm/scheme-fjF-9LhT.d.mts +0 -29
  107. package/lib/esm/server/index.d.mts +0 -2
  108. package/lib/esm/server/index.mjs +0 -563
  109. package/lib/esm/server/index.mjs.map +0 -1
  110. package/lib/esm/signer-5OVDxViv.d.mts +0 -79
  111. package/lib/esm/signer-BMkbhFYE.d.mts +0 -123
  112. package/lib/esm/types/index.d.mts +0 -1
  113. package/lib/esm/types/index.mjs +0 -10
  114. package/lib/esm/types/index.mjs.map +0 -1
  115. package/lib/esm/types/v1/index.d.mts +0 -1
  116. package/lib/esm/types/v1/index.mjs +0 -1
  117. package/lib/esm/types/v1/index.mjs.map +0 -1
  118. package/lib/esm/utils/index.d.mts +0 -48
  119. package/lib/esm/utils/index.mjs +0 -20
  120. package/lib/esm/utils/index.mjs.map +0 -1
  121. package/lib/esm/v1/index.d.mts +0 -12
  122. package/lib/esm/v1/index.mjs +0 -13
  123. package/lib/esm/v1/index.mjs.map +0 -1
  124. package/lib/esm/x402HTTPResourceServer-BIfIK5HS.d.mts +0 -719
  125. package/src/index.js +0 -4
@@ -1,1305 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/server/index.ts
21
- var server_exports = {};
22
- __export(server_exports, {
23
- HTTPFacilitatorClient: () => HTTPFacilitatorClient,
24
- RouteConfigurationError: () => RouteConfigurationError,
25
- x402HTTPResourceServer: () => x402HTTPResourceServer,
26
- x402ResourceServer: () => x402ResourceServer
27
- });
28
- module.exports = __toCommonJS(server_exports);
29
-
30
- // src/utils/index.ts
31
- var findSchemesByNetwork = (map, network) => {
32
- let implementationsByScheme = map.get(network);
33
- if (!implementationsByScheme) {
34
- for (const [registeredNetworkPattern, implementations] of map.entries()) {
35
- const pattern = registeredNetworkPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, ".*");
36
- const regex = new RegExp(`^${pattern}$`);
37
- if (regex.test(network)) {
38
- implementationsByScheme = implementations;
39
- break;
40
- }
41
- }
42
- }
43
- return implementationsByScheme;
44
- };
45
- var findByNetworkAndScheme = (map, scheme, network) => {
46
- return findSchemesByNetwork(map, network)?.get(scheme);
47
- };
48
- var Base64EncodedRegex = /^[A-Za-z0-9+/]*={0,2}$/;
49
- function safeBase64Encode(data) {
50
- if (typeof globalThis !== "undefined" && typeof globalThis.btoa === "function") {
51
- const bytes = new TextEncoder().encode(data);
52
- const binaryString = Array.from(bytes, (byte) => String.fromCharCode(byte)).join("");
53
- return globalThis.btoa(binaryString);
54
- }
55
- return Buffer.from(data, "utf8").toString("base64");
56
- }
57
- function safeBase64Decode(data) {
58
- if (typeof globalThis !== "undefined" && typeof globalThis.atob === "function") {
59
- const binaryString = globalThis.atob(data);
60
- const bytes = new Uint8Array(binaryString.length);
61
- for (let i = 0; i < binaryString.length; i++) {
62
- bytes[i] = binaryString.charCodeAt(i);
63
- }
64
- const decoder = new TextDecoder("utf-8");
65
- return decoder.decode(bytes);
66
- }
67
- return Buffer.from(data, "base64").toString("utf-8");
68
- }
69
- function deepEqual(obj1, obj2) {
70
- const normalize = (obj) => {
71
- if (obj === null || obj === void 0) return JSON.stringify(obj);
72
- if (typeof obj !== "object") return JSON.stringify(obj);
73
- if (Array.isArray(obj)) {
74
- return JSON.stringify(
75
- obj.map(
76
- (item) => typeof item === "object" && item !== null ? JSON.parse(normalize(item)) : item
77
- )
78
- );
79
- }
80
- const sorted = {};
81
- Object.keys(obj).sort().forEach((key) => {
82
- const value = obj[key];
83
- sorted[key] = typeof value === "object" && value !== null ? JSON.parse(normalize(value)) : value;
84
- });
85
- return JSON.stringify(sorted);
86
- };
87
- try {
88
- return normalize(obj1) === normalize(obj2);
89
- } catch {
90
- return JSON.stringify(obj1) === JSON.stringify(obj2);
91
- }
92
- }
93
-
94
- // src/types/facilitator.ts
95
- var VerifyError = class extends Error {
96
- /**
97
- * Creates a VerifyError from a failed verification response.
98
- *
99
- * @param statusCode - HTTP status code from the facilitator
100
- * @param response - The verify response containing error details
101
- */
102
- constructor(statusCode, response) {
103
- super(`verification failed: ${response.invalidReason || "unknown reason"}`);
104
- this.name = "VerifyError";
105
- this.statusCode = statusCode;
106
- this.invalidReason = response.invalidReason;
107
- this.payer = response.payer;
108
- }
109
- };
110
- var SettleError = class extends Error {
111
- /**
112
- * Creates a SettleError from a failed settlement response.
113
- *
114
- * @param statusCode - HTTP status code from the facilitator
115
- * @param response - The settle response containing error details
116
- */
117
- constructor(statusCode, response) {
118
- super(`settlement failed: ${response.errorReason || "unknown reason"}`);
119
- this.name = "SettleError";
120
- this.statusCode = statusCode;
121
- this.errorReason = response.errorReason;
122
- this.payer = response.payer;
123
- this.transaction = response.transaction;
124
- this.network = response.network;
125
- }
126
- };
127
-
128
- // src/http/httpFacilitatorClient.ts
129
- var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
130
- var HTTPFacilitatorClient = class {
131
- /**
132
- * Creates a new HTTPFacilitatorClient instance.
133
- *
134
- * @param config - Configuration options for the facilitator client
135
- */
136
- constructor(config) {
137
- this.url = config?.url || DEFAULT_FACILITATOR_URL;
138
- this._createAuthHeaders = config?.createAuthHeaders;
139
- }
140
- /**
141
- * Verify a payment with the facilitator
142
- *
143
- * @param paymentPayload - The payment to verify
144
- * @param paymentRequirements - The requirements to verify against
145
- * @returns Verification response
146
- */
147
- async verify(paymentPayload, paymentRequirements) {
148
- let headers = {
149
- "Content-Type": "application/json"
150
- };
151
- if (this._createAuthHeaders) {
152
- const authHeaders = await this.createAuthHeaders("verify");
153
- headers = { ...headers, ...authHeaders.headers };
154
- }
155
- const response = await fetch(`${this.url}/verify`, {
156
- method: "POST",
157
- headers,
158
- body: JSON.stringify({
159
- x402Version: paymentPayload.x402Version,
160
- paymentPayload: this.toJsonSafe(paymentPayload),
161
- paymentRequirements: this.toJsonSafe(paymentRequirements)
162
- })
163
- });
164
- const data = await response.json();
165
- if (typeof data === "object" && data !== null && "isValid" in data) {
166
- const verifyResponse = data;
167
- if (!response.ok) {
168
- throw new VerifyError(response.status, verifyResponse);
169
- }
170
- return verifyResponse;
171
- }
172
- throw new Error(`Facilitator verify failed (${response.status}): ${JSON.stringify(data)}`);
173
- }
174
- /**
175
- * Settle a payment with the facilitator
176
- *
177
- * @param paymentPayload - The payment to settle
178
- * @param paymentRequirements - The requirements for settlement
179
- * @returns Settlement response
180
- */
181
- async settle(paymentPayload, paymentRequirements) {
182
- let headers = {
183
- "Content-Type": "application/json"
184
- };
185
- if (this._createAuthHeaders) {
186
- const authHeaders = await this.createAuthHeaders("settle");
187
- headers = { ...headers, ...authHeaders.headers };
188
- }
189
- const response = await fetch(`${this.url}/settle`, {
190
- method: "POST",
191
- headers,
192
- body: JSON.stringify({
193
- x402Version: paymentPayload.x402Version,
194
- paymentPayload: this.toJsonSafe(paymentPayload),
195
- paymentRequirements: this.toJsonSafe(paymentRequirements)
196
- })
197
- });
198
- const data = await response.json();
199
- if (typeof data === "object" && data !== null && "success" in data) {
200
- const settleResponse = data;
201
- if (!response.ok) {
202
- throw new SettleError(response.status, settleResponse);
203
- }
204
- return settleResponse;
205
- }
206
- throw new Error(`Facilitator settle failed (${response.status}): ${JSON.stringify(data)}`);
207
- }
208
- /**
209
- * Get supported payment kinds and extensions from the facilitator
210
- *
211
- * @returns Supported payment kinds and extensions
212
- */
213
- async getSupported() {
214
- let headers = {
215
- "Content-Type": "application/json"
216
- };
217
- if (this._createAuthHeaders) {
218
- const authHeaders = await this.createAuthHeaders("supported");
219
- headers = { ...headers, ...authHeaders.headers };
220
- }
221
- const response = await fetch(`${this.url}/supported`, {
222
- method: "GET",
223
- headers
224
- });
225
- if (!response.ok) {
226
- const errorText = await response.text().catch(() => response.statusText);
227
- throw new Error(`Facilitator getSupported failed (${response.status}): ${errorText}`);
228
- }
229
- return await response.json();
230
- }
231
- /**
232
- * Creates authentication headers for a specific path.
233
- *
234
- * @param path - The path to create authentication headers for (e.g., "verify", "settle", "supported")
235
- * @returns An object containing the authentication headers for the specified path
236
- */
237
- async createAuthHeaders(path) {
238
- if (this._createAuthHeaders) {
239
- const authHeaders = await this._createAuthHeaders();
240
- return {
241
- headers: authHeaders[path] ?? {}
242
- };
243
- }
244
- return {
245
- headers: {}
246
- };
247
- }
248
- /**
249
- * Helper to convert objects to JSON-safe format.
250
- * Handles BigInt and other non-JSON types.
251
- *
252
- * @param obj - The object to convert
253
- * @returns The JSON-safe representation of the object
254
- */
255
- toJsonSafe(obj) {
256
- return JSON.parse(
257
- JSON.stringify(obj, (_, value) => typeof value === "bigint" ? value.toString() : value)
258
- );
259
- }
260
- };
261
-
262
- // src/index.ts
263
- var x402Version = 2;
264
-
265
- // src/server/x402ResourceServer.ts
266
- var x402ResourceServer = class {
267
- /**
268
- * Creates a new x402ResourceServer instance.
269
- *
270
- * @param facilitatorClients - Optional facilitator client(s) for payment processing
271
- */
272
- constructor(facilitatorClients) {
273
- this.registeredServerSchemes = /* @__PURE__ */ new Map();
274
- this.supportedResponsesMap = /* @__PURE__ */ new Map();
275
- this.facilitatorClientsMap = /* @__PURE__ */ new Map();
276
- this.registeredExtensions = /* @__PURE__ */ new Map();
277
- this.beforeVerifyHooks = [];
278
- this.afterVerifyHooks = [];
279
- this.onVerifyFailureHooks = [];
280
- this.beforeSettleHooks = [];
281
- this.afterSettleHooks = [];
282
- this.onSettleFailureHooks = [];
283
- if (!facilitatorClients) {
284
- this.facilitatorClients = [new HTTPFacilitatorClient()];
285
- } else if (Array.isArray(facilitatorClients)) {
286
- this.facilitatorClients = facilitatorClients.length > 0 ? facilitatorClients : [new HTTPFacilitatorClient()];
287
- } else {
288
- this.facilitatorClients = [facilitatorClients];
289
- }
290
- }
291
- /**
292
- * Register a scheme/network server implementation.
293
- *
294
- * @param network - The network identifier
295
- * @param server - The scheme/network server implementation
296
- * @returns The x402ResourceServer instance for chaining
297
- */
298
- register(network, server) {
299
- if (!this.registeredServerSchemes.has(network)) {
300
- this.registeredServerSchemes.set(network, /* @__PURE__ */ new Map());
301
- }
302
- const serverByScheme = this.registeredServerSchemes.get(network);
303
- if (!serverByScheme.has(server.scheme)) {
304
- serverByScheme.set(server.scheme, server);
305
- }
306
- return this;
307
- }
308
- /**
309
- * Check if a scheme is registered for a given network.
310
- *
311
- * @param network - The network identifier
312
- * @param scheme - The payment scheme name
313
- * @returns True if the scheme is registered for the network, false otherwise
314
- */
315
- hasRegisteredScheme(network, scheme) {
316
- return !!findByNetworkAndScheme(this.registeredServerSchemes, scheme, network);
317
- }
318
- /**
319
- * Registers a resource service extension that can enrich extension declarations.
320
- *
321
- * @param extension - The extension to register
322
- * @returns The x402ResourceServer instance for chaining
323
- */
324
- registerExtension(extension) {
325
- this.registeredExtensions.set(extension.key, extension);
326
- return this;
327
- }
328
- /**
329
- * Enriches declared extensions using registered extension hooks.
330
- *
331
- * @param declaredExtensions - Extensions declared on the route
332
- * @param transportContext - Transport-specific context (HTTP, A2A, MCP, etc.)
333
- * @returns Enriched extensions map
334
- */
335
- enrichExtensions(declaredExtensions, transportContext) {
336
- const enriched = {};
337
- for (const [key, declaration] of Object.entries(declaredExtensions)) {
338
- const extension = this.registeredExtensions.get(key);
339
- if (extension?.enrichDeclaration) {
340
- enriched[key] = extension.enrichDeclaration(declaration, transportContext);
341
- } else {
342
- enriched[key] = declaration;
343
- }
344
- }
345
- return enriched;
346
- }
347
- /**
348
- * Register a hook to execute before payment verification.
349
- * Can abort verification by returning { abort: true, reason: string }
350
- *
351
- * @param hook - The hook function to register
352
- * @returns The x402ResourceServer instance for chaining
353
- */
354
- onBeforeVerify(hook) {
355
- this.beforeVerifyHooks.push(hook);
356
- return this;
357
- }
358
- /**
359
- * Register a hook to execute after successful payment verification.
360
- *
361
- * @param hook - The hook function to register
362
- * @returns The x402ResourceServer instance for chaining
363
- */
364
- onAfterVerify(hook) {
365
- this.afterVerifyHooks.push(hook);
366
- return this;
367
- }
368
- /**
369
- * Register a hook to execute when payment verification fails.
370
- * Can recover from failure by returning { recovered: true, result: VerifyResponse }
371
- *
372
- * @param hook - The hook function to register
373
- * @returns The x402ResourceServer instance for chaining
374
- */
375
- onVerifyFailure(hook) {
376
- this.onVerifyFailureHooks.push(hook);
377
- return this;
378
- }
379
- /**
380
- * Register a hook to execute before payment settlement.
381
- * Can abort settlement by returning { abort: true, reason: string }
382
- *
383
- * @param hook - The hook function to register
384
- * @returns The x402ResourceServer instance for chaining
385
- */
386
- onBeforeSettle(hook) {
387
- this.beforeSettleHooks.push(hook);
388
- return this;
389
- }
390
- /**
391
- * Register a hook to execute after successful payment settlement.
392
- *
393
- * @param hook - The hook function to register
394
- * @returns The x402ResourceServer instance for chaining
395
- */
396
- onAfterSettle(hook) {
397
- this.afterSettleHooks.push(hook);
398
- return this;
399
- }
400
- /**
401
- * Register a hook to execute when payment settlement fails.
402
- * Can recover from failure by returning { recovered: true, result: SettleResponse }
403
- *
404
- * @param hook - The hook function to register
405
- * @returns The x402ResourceServer instance for chaining
406
- */
407
- onSettleFailure(hook) {
408
- this.onSettleFailureHooks.push(hook);
409
- return this;
410
- }
411
- /**
412
- * Initialize by fetching supported kinds from all facilitators
413
- * Creates mappings for supported responses and facilitator clients
414
- * Earlier facilitators in the array get precedence
415
- */
416
- async initialize() {
417
- this.supportedResponsesMap.clear();
418
- this.facilitatorClientsMap.clear();
419
- for (const facilitatorClient of this.facilitatorClients) {
420
- try {
421
- const supported = await facilitatorClient.getSupported();
422
- for (const kind of supported.kinds) {
423
- const x402Version2 = kind.x402Version;
424
- if (!this.supportedResponsesMap.has(x402Version2)) {
425
- this.supportedResponsesMap.set(x402Version2, /* @__PURE__ */ new Map());
426
- }
427
- const responseVersionMap = this.supportedResponsesMap.get(x402Version2);
428
- if (!this.facilitatorClientsMap.has(x402Version2)) {
429
- this.facilitatorClientsMap.set(x402Version2, /* @__PURE__ */ new Map());
430
- }
431
- const clientVersionMap = this.facilitatorClientsMap.get(x402Version2);
432
- if (!responseVersionMap.has(kind.network)) {
433
- responseVersionMap.set(kind.network, /* @__PURE__ */ new Map());
434
- }
435
- const responseNetworkMap = responseVersionMap.get(kind.network);
436
- if (!clientVersionMap.has(kind.network)) {
437
- clientVersionMap.set(kind.network, /* @__PURE__ */ new Map());
438
- }
439
- const clientNetworkMap = clientVersionMap.get(kind.network);
440
- if (!responseNetworkMap.has(kind.scheme)) {
441
- responseNetworkMap.set(kind.scheme, supported);
442
- clientNetworkMap.set(kind.scheme, facilitatorClient);
443
- }
444
- }
445
- } catch (error) {
446
- console.warn(`Failed to fetch supported kinds from facilitator: ${error}`);
447
- }
448
- }
449
- }
450
- /**
451
- * Get supported kind for a specific version, network, and scheme
452
- *
453
- * @param x402Version - The x402 version
454
- * @param network - The network identifier
455
- * @param scheme - The payment scheme
456
- * @returns The supported kind or undefined if not found
457
- */
458
- getSupportedKind(x402Version2, network, scheme) {
459
- const versionMap = this.supportedResponsesMap.get(x402Version2);
460
- if (!versionMap) return void 0;
461
- const supportedResponse = findByNetworkAndScheme(versionMap, scheme, network);
462
- if (!supportedResponse) return void 0;
463
- return supportedResponse.kinds.find(
464
- (kind) => kind.x402Version === x402Version2 && kind.network === network && kind.scheme === scheme
465
- );
466
- }
467
- /**
468
- * Get facilitator extensions for a specific version, network, and scheme
469
- *
470
- * @param x402Version - The x402 version
471
- * @param network - The network identifier
472
- * @param scheme - The payment scheme
473
- * @returns The facilitator extensions or empty array if not found
474
- */
475
- getFacilitatorExtensions(x402Version2, network, scheme) {
476
- const versionMap = this.supportedResponsesMap.get(x402Version2);
477
- if (!versionMap) return [];
478
- const supportedResponse = findByNetworkAndScheme(versionMap, scheme, network);
479
- return supportedResponse?.extensions || [];
480
- }
481
- /**
482
- * Build payment requirements for a protected resource
483
- *
484
- * @param resourceConfig - Configuration for the protected resource
485
- * @returns Array of payment requirements
486
- */
487
- async buildPaymentRequirements(resourceConfig) {
488
- const requirements = [];
489
- const scheme = resourceConfig.scheme;
490
- const SchemeNetworkServer = findByNetworkAndScheme(
491
- this.registeredServerSchemes,
492
- scheme,
493
- resourceConfig.network
494
- );
495
- if (!SchemeNetworkServer) {
496
- console.warn(
497
- `No server implementation registered for scheme: ${scheme}, network: ${resourceConfig.network}`
498
- );
499
- return requirements;
500
- }
501
- const supportedKind = this.getSupportedKind(
502
- x402Version,
503
- resourceConfig.network,
504
- SchemeNetworkServer.scheme
505
- );
506
- if (!supportedKind) {
507
- throw new Error(
508
- `Facilitator does not support ${SchemeNetworkServer.scheme} on ${resourceConfig.network}. Make sure to call initialize() to fetch supported kinds from facilitators.`
509
- );
510
- }
511
- const facilitatorExtensions = this.getFacilitatorExtensions(
512
- x402Version,
513
- resourceConfig.network,
514
- SchemeNetworkServer.scheme
515
- );
516
- const parsedPrice = await SchemeNetworkServer.parsePrice(
517
- resourceConfig.price,
518
- resourceConfig.network
519
- );
520
- const baseRequirements = {
521
- scheme: SchemeNetworkServer.scheme,
522
- network: resourceConfig.network,
523
- amount: parsedPrice.amount,
524
- asset: parsedPrice.asset,
525
- payTo: resourceConfig.payTo,
526
- maxTimeoutSeconds: resourceConfig.maxTimeoutSeconds || 300,
527
- // Default 5 minutes
528
- extra: {
529
- ...parsedPrice.extra
530
- }
531
- };
532
- const requirement = await SchemeNetworkServer.enhancePaymentRequirements(
533
- baseRequirements,
534
- {
535
- ...supportedKind,
536
- x402Version
537
- },
538
- facilitatorExtensions
539
- );
540
- requirements.push(requirement);
541
- return requirements;
542
- }
543
- /**
544
- * Build payment requirements from multiple payment options
545
- * This method handles resolving dynamic payTo/price functions and builds requirements for each option
546
- *
547
- * @param paymentOptions - Array of payment options to convert
548
- * @param context - HTTP request context for resolving dynamic functions
549
- * @returns Array of payment requirements (one per option)
550
- */
551
- async buildPaymentRequirementsFromOptions(paymentOptions, context) {
552
- const allRequirements = [];
553
- for (const option of paymentOptions) {
554
- const resolvedPayTo = typeof option.payTo === "function" ? await option.payTo(context) : option.payTo;
555
- const resolvedPrice = typeof option.price === "function" ? await option.price(context) : option.price;
556
- const resourceConfig = {
557
- scheme: option.scheme,
558
- payTo: resolvedPayTo,
559
- price: resolvedPrice,
560
- network: option.network,
561
- maxTimeoutSeconds: option.maxTimeoutSeconds
562
- };
563
- const requirements = await this.buildPaymentRequirements(resourceConfig);
564
- allRequirements.push(...requirements);
565
- }
566
- return allRequirements;
567
- }
568
- /**
569
- * Create a payment required response
570
- *
571
- * @param requirements - Payment requirements
572
- * @param resourceInfo - Resource information
573
- * @param error - Error message
574
- * @param extensions - Optional extensions
575
- * @returns Payment required response object
576
- */
577
- createPaymentRequiredResponse(requirements, resourceInfo, error, extensions) {
578
- const response = {
579
- x402Version: 2,
580
- error,
581
- resource: resourceInfo,
582
- accepts: requirements
583
- };
584
- if (extensions && Object.keys(extensions).length > 0) {
585
- response.extensions = extensions;
586
- }
587
- return response;
588
- }
589
- /**
590
- * Verify a payment against requirements
591
- *
592
- * @param paymentPayload - The payment payload to verify
593
- * @param requirements - The payment requirements
594
- * @returns Verification response
595
- */
596
- async verifyPayment(paymentPayload, requirements) {
597
- const context = {
598
- paymentPayload,
599
- requirements
600
- };
601
- for (const hook of this.beforeVerifyHooks) {
602
- const result = await hook(context);
603
- if (result && "abort" in result && result.abort) {
604
- return {
605
- isValid: false,
606
- invalidReason: result.reason
607
- };
608
- }
609
- }
610
- try {
611
- const facilitatorClient = this.getFacilitatorClient(
612
- paymentPayload.x402Version,
613
- requirements.network,
614
- requirements.scheme
615
- );
616
- let verifyResult;
617
- if (!facilitatorClient) {
618
- let lastError;
619
- for (const client of this.facilitatorClients) {
620
- try {
621
- verifyResult = await client.verify(paymentPayload, requirements);
622
- break;
623
- } catch (error) {
624
- lastError = error;
625
- }
626
- }
627
- if (!verifyResult) {
628
- throw lastError || new Error(
629
- `No facilitator supports ${requirements.scheme} on ${requirements.network} for v${paymentPayload.x402Version}`
630
- );
631
- }
632
- } else {
633
- verifyResult = await facilitatorClient.verify(paymentPayload, requirements);
634
- }
635
- const resultContext = {
636
- ...context,
637
- result: verifyResult
638
- };
639
- for (const hook of this.afterVerifyHooks) {
640
- await hook(resultContext);
641
- }
642
- return verifyResult;
643
- } catch (error) {
644
- const failureContext = {
645
- ...context,
646
- error
647
- };
648
- for (const hook of this.onVerifyFailureHooks) {
649
- const result = await hook(failureContext);
650
- if (result && "recovered" in result && result.recovered) {
651
- return result.result;
652
- }
653
- }
654
- throw error;
655
- }
656
- }
657
- /**
658
- * Settle a verified payment
659
- *
660
- * @param paymentPayload - The payment payload to settle
661
- * @param requirements - The payment requirements
662
- * @returns Settlement response
663
- */
664
- async settlePayment(paymentPayload, requirements) {
665
- const context = {
666
- paymentPayload,
667
- requirements
668
- };
669
- for (const hook of this.beforeSettleHooks) {
670
- const result = await hook(context);
671
- if (result && "abort" in result && result.abort) {
672
- throw new Error(`Settlement aborted: ${result.reason}`);
673
- }
674
- }
675
- try {
676
- const facilitatorClient = this.getFacilitatorClient(
677
- paymentPayload.x402Version,
678
- requirements.network,
679
- requirements.scheme
680
- );
681
- let settleResult;
682
- if (!facilitatorClient) {
683
- let lastError;
684
- for (const client of this.facilitatorClients) {
685
- try {
686
- settleResult = await client.settle(paymentPayload, requirements);
687
- break;
688
- } catch (error) {
689
- lastError = error;
690
- }
691
- }
692
- if (!settleResult) {
693
- throw lastError || new Error(
694
- `No facilitator supports ${requirements.scheme} on ${requirements.network} for v${paymentPayload.x402Version}`
695
- );
696
- }
697
- } else {
698
- settleResult = await facilitatorClient.settle(paymentPayload, requirements);
699
- }
700
- const resultContext = {
701
- ...context,
702
- result: settleResult
703
- };
704
- for (const hook of this.afterSettleHooks) {
705
- await hook(resultContext);
706
- }
707
- return settleResult;
708
- } catch (error) {
709
- const failureContext = {
710
- ...context,
711
- error
712
- };
713
- for (const hook of this.onSettleFailureHooks) {
714
- const result = await hook(failureContext);
715
- if (result && "recovered" in result && result.recovered) {
716
- return result.result;
717
- }
718
- }
719
- throw error;
720
- }
721
- }
722
- /**
723
- * Find matching payment requirements for a payment
724
- *
725
- * @param availableRequirements - Array of available payment requirements
726
- * @param paymentPayload - The payment payload
727
- * @returns Matching payment requirements or undefined
728
- */
729
- findMatchingRequirements(availableRequirements, paymentPayload) {
730
- switch (paymentPayload.x402Version) {
731
- case 2:
732
- return availableRequirements.find(
733
- (paymentRequirements) => deepEqual(paymentRequirements, paymentPayload.accepted)
734
- );
735
- case 1:
736
- return availableRequirements.find(
737
- (req) => req.scheme === paymentPayload.accepted.scheme && req.network === paymentPayload.accepted.network
738
- );
739
- default:
740
- throw new Error(
741
- `Unsupported x402 version: ${paymentPayload.x402Version}`
742
- );
743
- }
744
- }
745
- /**
746
- * Process a payment request
747
- *
748
- * @param paymentPayload - Optional payment payload if provided
749
- * @param resourceConfig - Configuration for the protected resource
750
- * @param resourceInfo - Information about the resource being accessed
751
- * @param extensions - Optional extensions to include in the response
752
- * @returns Processing result
753
- */
754
- async processPaymentRequest(paymentPayload, resourceConfig, resourceInfo, extensions) {
755
- const requirements = await this.buildPaymentRequirements(resourceConfig);
756
- if (!paymentPayload) {
757
- return {
758
- success: false,
759
- requiresPayment: this.createPaymentRequiredResponse(
760
- requirements,
761
- resourceInfo,
762
- "Payment required",
763
- extensions
764
- )
765
- };
766
- }
767
- const matchingRequirements = this.findMatchingRequirements(requirements, paymentPayload);
768
- if (!matchingRequirements) {
769
- return {
770
- success: false,
771
- requiresPayment: this.createPaymentRequiredResponse(
772
- requirements,
773
- resourceInfo,
774
- "No matching payment requirements found",
775
- extensions
776
- )
777
- };
778
- }
779
- const verificationResult = await this.verifyPayment(paymentPayload, matchingRequirements);
780
- if (!verificationResult.isValid) {
781
- return {
782
- success: false,
783
- error: verificationResult.invalidReason,
784
- verificationResult
785
- };
786
- }
787
- return {
788
- success: true,
789
- verificationResult
790
- };
791
- }
792
- /**
793
- * Get facilitator client for a specific version, network, and scheme
794
- *
795
- * @param x402Version - The x402 version
796
- * @param network - The network identifier
797
- * @param scheme - The payment scheme
798
- * @returns The facilitator client or undefined if not found
799
- */
800
- getFacilitatorClient(x402Version2, network, scheme) {
801
- const versionMap = this.facilitatorClientsMap.get(x402Version2);
802
- if (!versionMap) return void 0;
803
- return findByNetworkAndScheme(versionMap, scheme, network);
804
- }
805
- };
806
-
807
- // src/http/index.ts
808
- function decodePaymentSignatureHeader(paymentSignatureHeader) {
809
- if (!Base64EncodedRegex.test(paymentSignatureHeader)) {
810
- throw new Error("Invalid payment signature header");
811
- }
812
- return JSON.parse(safeBase64Decode(paymentSignatureHeader));
813
- }
814
- function encodePaymentRequiredHeader(paymentRequired) {
815
- return safeBase64Encode(JSON.stringify(paymentRequired));
816
- }
817
- function encodePaymentResponseHeader(paymentResponse) {
818
- return safeBase64Encode(JSON.stringify(paymentResponse));
819
- }
820
-
821
- // src/http/x402HTTPResourceServer.ts
822
- var RouteConfigurationError = class extends Error {
823
- /**
824
- * Creates a new RouteConfigurationError with the given validation errors.
825
- *
826
- * @param errors - The validation errors that caused this exception.
827
- */
828
- constructor(errors) {
829
- const message = `x402 Route Configuration Errors:
830
- ${errors.map((e) => ` - ${e.message}`).join("\n")}`;
831
- super(message);
832
- this.name = "RouteConfigurationError";
833
- this.errors = errors;
834
- }
835
- };
836
- var x402HTTPResourceServer = class {
837
- /**
838
- * Creates a new x402HTTPResourceServer instance.
839
- *
840
- * @param ResourceServer - The core x402ResourceServer instance to use
841
- * @param routes - Route configuration for payment-protected endpoints
842
- */
843
- constructor(ResourceServer, routes) {
844
- this.compiledRoutes = [];
845
- this.ResourceServer = ResourceServer;
846
- this.routesConfig = routes;
847
- const normalizedRoutes = typeof routes === "object" && !("accepts" in routes) ? routes : { "*": routes };
848
- for (const [pattern, config] of Object.entries(normalizedRoutes)) {
849
- const parsed = this.parseRoutePattern(pattern);
850
- this.compiledRoutes.push({
851
- verb: parsed.verb,
852
- regex: parsed.regex,
853
- config
854
- });
855
- }
856
- }
857
- /**
858
- * Initialize the HTTP resource server.
859
- *
860
- * This method initializes the underlying resource server (fetching facilitator support)
861
- * and then validates that all route payment configurations have corresponding
862
- * registered schemes and facilitator support.
863
- *
864
- * @throws RouteConfigurationError if any route's payment options don't have
865
- * corresponding registered schemes or facilitator support
866
- *
867
- * @example
868
- * ```typescript
869
- * const httpServer = new x402HTTPResourceServer(server, routes);
870
- * await httpServer.initialize();
871
- * ```
872
- */
873
- async initialize() {
874
- await this.ResourceServer.initialize();
875
- const errors = this.validateRouteConfiguration();
876
- if (errors.length > 0) {
877
- throw new RouteConfigurationError(errors);
878
- }
879
- }
880
- /**
881
- * Register a custom paywall provider for generating HTML
882
- *
883
- * @param provider - PaywallProvider instance
884
- * @returns This service instance for chaining
885
- */
886
- registerPaywallProvider(provider) {
887
- this.paywallProvider = provider;
888
- return this;
889
- }
890
- /**
891
- * Process HTTP request and return response instructions
892
- * This is the main entry point for framework middleware
893
- *
894
- * @param context - HTTP request context
895
- * @param paywallConfig - Optional paywall configuration
896
- * @returns Process result indicating next action for middleware
897
- */
898
- async processHTTPRequest(context, paywallConfig) {
899
- const { adapter, path, method } = context;
900
- const routeConfig = this.getRouteConfig(path, method);
901
- if (!routeConfig) {
902
- return { type: "no-payment-required" };
903
- }
904
- const paymentOptions = this.normalizePaymentOptions(routeConfig);
905
- const paymentPayload = this.extractPayment(adapter);
906
- const resourceInfo = {
907
- url: routeConfig.resource || context.adapter.getUrl(),
908
- description: routeConfig.description || "",
909
- mimeType: routeConfig.mimeType || ""
910
- };
911
- const requirements = await this.ResourceServer.buildPaymentRequirementsFromOptions(
912
- paymentOptions,
913
- context
914
- );
915
- let extensions = routeConfig.extensions;
916
- if (extensions) {
917
- extensions = this.ResourceServer.enrichExtensions(extensions, context);
918
- }
919
- const paymentRequired = this.ResourceServer.createPaymentRequiredResponse(
920
- requirements,
921
- resourceInfo,
922
- !paymentPayload ? "Payment required" : void 0,
923
- extensions
924
- );
925
- if (!paymentPayload) {
926
- const unpaidBody = routeConfig.unpaidResponseBody ? await routeConfig.unpaidResponseBody(context) : void 0;
927
- return {
928
- type: "payment-error",
929
- response: this.createHTTPResponse(
930
- paymentRequired,
931
- this.isWebBrowser(adapter),
932
- paywallConfig,
933
- routeConfig.customPaywallHtml,
934
- unpaidBody
935
- )
936
- };
937
- }
938
- try {
939
- const matchingRequirements = this.ResourceServer.findMatchingRequirements(
940
- paymentRequired.accepts,
941
- paymentPayload
942
- );
943
- if (!matchingRequirements) {
944
- const errorResponse = this.ResourceServer.createPaymentRequiredResponse(
945
- requirements,
946
- resourceInfo,
947
- "No matching payment requirements",
948
- routeConfig.extensions
949
- );
950
- return {
951
- type: "payment-error",
952
- response: this.createHTTPResponse(errorResponse, false, paywallConfig)
953
- };
954
- }
955
- const verifyResult = await this.ResourceServer.verifyPayment(
956
- paymentPayload,
957
- matchingRequirements
958
- );
959
- if (!verifyResult.isValid) {
960
- const errorResponse = this.ResourceServer.createPaymentRequiredResponse(
961
- requirements,
962
- resourceInfo,
963
- verifyResult.invalidReason,
964
- routeConfig.extensions
965
- );
966
- return {
967
- type: "payment-error",
968
- response: this.createHTTPResponse(errorResponse, false, paywallConfig)
969
- };
970
- }
971
- return {
972
- type: "payment-verified",
973
- paymentPayload,
974
- paymentRequirements: matchingRequirements
975
- };
976
- } catch (error) {
977
- const errorResponse = this.ResourceServer.createPaymentRequiredResponse(
978
- requirements,
979
- resourceInfo,
980
- error instanceof Error ? error.message : "Payment verification failed",
981
- routeConfig.extensions
982
- );
983
- return {
984
- type: "payment-error",
985
- response: this.createHTTPResponse(errorResponse, false, paywallConfig)
986
- };
987
- }
988
- }
989
- /**
990
- * Process settlement after successful response
991
- *
992
- * @param paymentPayload - The verified payment payload
993
- * @param requirements - The matching payment requirements
994
- * @returns ProcessSettleResultResponse - SettleResponse with headers if success or errorReason if failure
995
- */
996
- async processSettlement(paymentPayload, requirements) {
997
- try {
998
- const settleResponse = await this.ResourceServer.settlePayment(paymentPayload, requirements);
999
- if (!settleResponse.success) {
1000
- return {
1001
- ...settleResponse,
1002
- success: false,
1003
- errorReason: settleResponse.errorReason || "Settlement failed"
1004
- };
1005
- }
1006
- return {
1007
- ...settleResponse,
1008
- success: true,
1009
- headers: this.createSettlementHeaders(settleResponse, requirements),
1010
- requirements
1011
- };
1012
- } catch (error) {
1013
- if (error instanceof SettleError) {
1014
- return {
1015
- success: false,
1016
- errorReason: error.errorReason || error.message,
1017
- payer: error.payer,
1018
- network: error.network,
1019
- transaction: error.transaction
1020
- };
1021
- }
1022
- return {
1023
- success: false,
1024
- errorReason: error instanceof Error ? error.message : "Settlement failed",
1025
- network: requirements.network,
1026
- transaction: ""
1027
- };
1028
- }
1029
- }
1030
- /**
1031
- * Check if a request requires payment based on route configuration
1032
- *
1033
- * @param context - HTTP request context
1034
- * @returns True if the route requires payment, false otherwise
1035
- */
1036
- requiresPayment(context) {
1037
- const routeConfig = this.getRouteConfig(context.path, context.method);
1038
- return routeConfig !== void 0;
1039
- }
1040
- /**
1041
- * Normalizes a RouteConfig's accepts field into an array of PaymentOptions
1042
- * Handles both single PaymentOption and array formats
1043
- *
1044
- * @param routeConfig - Route configuration
1045
- * @returns Array of payment options
1046
- */
1047
- normalizePaymentOptions(routeConfig) {
1048
- return Array.isArray(routeConfig.accepts) ? routeConfig.accepts : [routeConfig.accepts];
1049
- }
1050
- /**
1051
- * Validates that all payment options in routes have corresponding registered schemes
1052
- * and facilitator support.
1053
- *
1054
- * @returns Array of validation errors (empty if all routes are valid)
1055
- */
1056
- validateRouteConfiguration() {
1057
- const errors = [];
1058
- const normalizedRoutes = typeof this.routesConfig === "object" && !("accepts" in this.routesConfig) ? Object.entries(this.routesConfig) : [["*", this.routesConfig]];
1059
- for (const [pattern, config] of normalizedRoutes) {
1060
- const paymentOptions = this.normalizePaymentOptions(config);
1061
- for (const option of paymentOptions) {
1062
- if (!this.ResourceServer.hasRegisteredScheme(option.network, option.scheme)) {
1063
- errors.push({
1064
- routePattern: pattern,
1065
- scheme: option.scheme,
1066
- network: option.network,
1067
- reason: "missing_scheme",
1068
- message: `Route "${pattern}": No scheme implementation registered for "${option.scheme}" on network "${option.network}"`
1069
- });
1070
- continue;
1071
- }
1072
- const supportedKind = this.ResourceServer.getSupportedKind(
1073
- x402Version,
1074
- option.network,
1075
- option.scheme
1076
- );
1077
- if (!supportedKind) {
1078
- errors.push({
1079
- routePattern: pattern,
1080
- scheme: option.scheme,
1081
- network: option.network,
1082
- reason: "missing_facilitator",
1083
- message: `Route "${pattern}": Facilitator does not support scheme "${option.scheme}" on network "${option.network}"`
1084
- });
1085
- }
1086
- }
1087
- }
1088
- return errors;
1089
- }
1090
- /**
1091
- * Get route configuration for a request
1092
- *
1093
- * @param path - Request path
1094
- * @param method - HTTP method
1095
- * @returns Route configuration or undefined if no match
1096
- */
1097
- getRouteConfig(path, method) {
1098
- const normalizedPath = this.normalizePath(path);
1099
- const upperMethod = method.toUpperCase();
1100
- const matchingRoute = this.compiledRoutes.find(
1101
- (route) => route.regex.test(normalizedPath) && (route.verb === "*" || route.verb === upperMethod)
1102
- );
1103
- return matchingRoute?.config;
1104
- }
1105
- /**
1106
- * Extract payment from HTTP headers (handles v1 and v2)
1107
- *
1108
- * @param adapter - HTTP adapter
1109
- * @returns Decoded payment payload or null
1110
- */
1111
- extractPayment(adapter) {
1112
- const header = adapter.getHeader("payment-signature") || adapter.getHeader("PAYMENT-SIGNATURE");
1113
- if (header) {
1114
- try {
1115
- return decodePaymentSignatureHeader(header);
1116
- } catch (error) {
1117
- console.warn("Failed to decode PAYMENT-SIGNATURE header:", error);
1118
- }
1119
- }
1120
- return null;
1121
- }
1122
- /**
1123
- * Check if request is from a web browser
1124
- *
1125
- * @param adapter - HTTP adapter
1126
- * @returns True if request appears to be from a browser
1127
- */
1128
- isWebBrowser(adapter) {
1129
- const accept = adapter.getAcceptHeader();
1130
- const userAgent = adapter.getUserAgent();
1131
- return accept.includes("text/html") && userAgent.includes("Mozilla");
1132
- }
1133
- /**
1134
- * Create HTTP response instructions from payment required
1135
- *
1136
- * @param paymentRequired - Payment requirements
1137
- * @param isWebBrowser - Whether request is from browser
1138
- * @param paywallConfig - Paywall configuration
1139
- * @param customHtml - Custom HTML template
1140
- * @param unpaidResponse - Optional custom response (content type and body) for unpaid API requests
1141
- * @returns Response instructions
1142
- */
1143
- createHTTPResponse(paymentRequired, isWebBrowser, paywallConfig, customHtml, unpaidResponse) {
1144
- if (isWebBrowser) {
1145
- const html = this.generatePaywallHTML(paymentRequired, paywallConfig, customHtml);
1146
- return {
1147
- status: 402,
1148
- headers: { "Content-Type": "text/html" },
1149
- body: html,
1150
- isHtml: true
1151
- };
1152
- }
1153
- const response = this.createHTTPPaymentRequiredResponse(paymentRequired);
1154
- const contentType = unpaidResponse ? unpaidResponse.contentType : "application/json";
1155
- const body = unpaidResponse ? unpaidResponse.body : {};
1156
- return {
1157
- status: 402,
1158
- headers: {
1159
- "Content-Type": contentType,
1160
- ...response.headers
1161
- },
1162
- body
1163
- };
1164
- }
1165
- /**
1166
- * Create HTTP payment required response (v1 puts in body, v2 puts in header)
1167
- *
1168
- * @param paymentRequired - Payment required object
1169
- * @returns Headers and body for the HTTP response
1170
- */
1171
- createHTTPPaymentRequiredResponse(paymentRequired) {
1172
- return {
1173
- headers: {
1174
- "PAYMENT-REQUIRED": encodePaymentRequiredHeader(paymentRequired)
1175
- }
1176
- };
1177
- }
1178
- /**
1179
- * Create settlement response headers
1180
- *
1181
- * @param settleResponse - Settlement response
1182
- * @param requirements - Payment requirements that were settled
1183
- * @returns Headers to add to response
1184
- */
1185
- createSettlementHeaders(settleResponse, requirements) {
1186
- const encoded = encodePaymentResponseHeader({
1187
- ...settleResponse,
1188
- requirements
1189
- });
1190
- return { "PAYMENT-RESPONSE": encoded };
1191
- }
1192
- /**
1193
- * Parse route pattern into verb and regex
1194
- *
1195
- * @param pattern - Route pattern like "GET /api/*" or "/api/[id]"
1196
- * @returns Parsed pattern with verb and regex
1197
- */
1198
- parseRoutePattern(pattern) {
1199
- const [verb, path] = pattern.includes(" ") ? pattern.split(/\s+/) : ["*", pattern];
1200
- const regex = new RegExp(
1201
- `^${path.replace(/[$()+.?^{|}]/g, "\\$&").replace(/\*/g, ".*?").replace(/\[([^\]]+)\]/g, "[^/]+").replace(/\//g, "\\/")}$`,
1202
- "i"
1203
- );
1204
- return { verb: verb.toUpperCase(), regex };
1205
- }
1206
- /**
1207
- * Normalize path for matching
1208
- *
1209
- * @param path - Raw path from request
1210
- * @returns Normalized path
1211
- */
1212
- normalizePath(path) {
1213
- try {
1214
- const pathWithoutQuery = path.split(/[?#]/)[0];
1215
- const decodedPath = decodeURIComponent(pathWithoutQuery);
1216
- return decodedPath.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/(.+?)\/+$/, "$1");
1217
- } catch {
1218
- return path;
1219
- }
1220
- }
1221
- /**
1222
- * Generate paywall HTML for browser requests
1223
- *
1224
- * @param paymentRequired - Payment required response
1225
- * @param paywallConfig - Optional paywall configuration
1226
- * @param customHtml - Optional custom HTML template
1227
- * @returns HTML string
1228
- */
1229
- generatePaywallHTML(paymentRequired, paywallConfig, customHtml) {
1230
- if (customHtml) {
1231
- return customHtml;
1232
- }
1233
- if (this.paywallProvider) {
1234
- return this.paywallProvider.generateHtml(paymentRequired, paywallConfig);
1235
- }
1236
- try {
1237
- const paywall = require("@x402/paywall");
1238
- const displayAmount2 = this.getDisplayAmount(paymentRequired);
1239
- const resource2 = paymentRequired.resource;
1240
- return paywall.getPaywallHtml({
1241
- amount: displayAmount2,
1242
- paymentRequired,
1243
- currentUrl: resource2?.url || paywallConfig?.currentUrl || "",
1244
- testnet: paywallConfig?.testnet ?? true,
1245
- appName: paywallConfig?.appName,
1246
- appLogo: paywallConfig?.appLogo,
1247
- sessionTokenEndpoint: paywallConfig?.sessionTokenEndpoint
1248
- });
1249
- } catch {
1250
- }
1251
- const resource = paymentRequired.resource;
1252
- const displayAmount = this.getDisplayAmount(paymentRequired);
1253
- return `
1254
- <!DOCTYPE html>
1255
- <html>
1256
- <head>
1257
- <title>Payment Required</title>
1258
- <meta charset="UTF-8">
1259
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1260
- </head>
1261
- <body>
1262
- <div style="max-width: 600px; margin: 50px auto; padding: 20px; font-family: system-ui, -apple-system, sans-serif;">
1263
- ${paywallConfig?.appLogo ? `<img src="${paywallConfig.appLogo}" alt="${paywallConfig.appName || "App"}" style="max-width: 200px; margin-bottom: 20px;">` : ""}
1264
- <h1>Payment Required</h1>
1265
- ${resource ? `<p><strong>Resource:</strong> ${resource.description || resource.url}</p>` : ""}
1266
- <p><strong>Amount:</strong> $${displayAmount.toFixed(2)} USDC</p>
1267
- <div id="payment-widget"
1268
- data-requirements='${JSON.stringify(paymentRequired)}'
1269
- data-app-name="${paywallConfig?.appName || ""}"
1270
- data-testnet="${paywallConfig?.testnet || false}">
1271
- <!-- Install @x402/paywall for full wallet integration -->
1272
- <p style="margin-top: 2rem; padding: 1rem; background: #fef3c7; border-radius: 0.5rem;">
1273
- <strong>Note:</strong> Install <code>@x402/paywall</code> for full wallet connection and payment UI.
1274
- </p>
1275
- </div>
1276
- </div>
1277
- </body>
1278
- </html>
1279
- `;
1280
- }
1281
- /**
1282
- * Extract display amount from payment requirements.
1283
- *
1284
- * @param paymentRequired - The payment required object
1285
- * @returns The display amount in decimal format
1286
- */
1287
- getDisplayAmount(paymentRequired) {
1288
- const accepts = paymentRequired.accepts;
1289
- if (accepts && accepts.length > 0) {
1290
- const firstReq = accepts[0];
1291
- if ("amount" in firstReq) {
1292
- return parseFloat(firstReq.amount) / 1e6;
1293
- }
1294
- }
1295
- return 0;
1296
- }
1297
- };
1298
- // Annotate the CommonJS export names for ESM import in node:
1299
- 0 && (module.exports = {
1300
- HTTPFacilitatorClient,
1301
- RouteConfigurationError,
1302
- x402HTTPResourceServer,
1303
- x402ResourceServer
1304
- });
1305
- //# sourceMappingURL=index.js.map