@dexterai/x402 1.7.2 → 1.8.1

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.
@@ -107,25 +107,77 @@ function decodeBase64Json(encoded) {
107
107
  }
108
108
 
109
109
  // src/server/facilitator-client.ts
110
+ function isRetryable(error) {
111
+ if (error instanceof TypeError) return true;
112
+ if (error && typeof error === "object" && "status" in error) {
113
+ const status = error.status;
114
+ return status >= 500 && status < 600;
115
+ }
116
+ return false;
117
+ }
118
+ var HttpError = class extends Error {
119
+ status;
120
+ body;
121
+ constructor(status, body) {
122
+ super(`HTTP ${status}`);
123
+ this.status = status;
124
+ this.body = body;
125
+ }
126
+ };
110
127
  var FacilitatorClient = class {
111
128
  facilitatorUrl;
112
129
  cachedSupported = null;
113
130
  cacheTime = 0;
114
131
  CACHE_TTL_MS = 6e4;
115
- // 1 minute cache
116
- constructor(facilitatorUrl = DEXTER_FACILITATOR_URL) {
132
+ timeoutMs;
133
+ maxRetries;
134
+ retryBaseMs;
135
+ constructor(facilitatorUrl = DEXTER_FACILITATOR_URL, config) {
117
136
  this.facilitatorUrl = facilitatorUrl.replace(/\/$/, "");
137
+ this.timeoutMs = config?.timeoutMs ?? 1e4;
138
+ this.maxRetries = config?.maxRetries ?? 3;
139
+ this.retryBaseMs = config?.retryBaseMs ?? 500;
140
+ }
141
+ async fetchWithTimeout(url, init) {
142
+ const controller = new AbortController();
143
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
144
+ try {
145
+ return await fetch(url, { ...init, signal: controller.signal });
146
+ } finally {
147
+ clearTimeout(timer);
148
+ }
149
+ }
150
+ async fetchWithRetry(url, init) {
151
+ let lastError;
152
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
153
+ try {
154
+ const response = await this.fetchWithTimeout(url, init);
155
+ if (!response.ok && response.status >= 500) {
156
+ throw new HttpError(response.status, await response.text());
157
+ }
158
+ return response;
159
+ } catch (error) {
160
+ lastError = error;
161
+ if (attempt < this.maxRetries - 1 && isRetryable(error)) {
162
+ const delay = this.retryBaseMs * Math.pow(2, attempt);
163
+ await new Promise((r) => setTimeout(r, delay));
164
+ continue;
165
+ }
166
+ throw error;
167
+ }
168
+ }
169
+ throw lastError;
118
170
  }
119
171
  /**
120
- * Get supported payment kinds from the facilitator
121
- * Results are cached for 1 minute to reduce network calls
172
+ * Get supported payment kinds from the facilitator.
173
+ * Results are cached for 1 minute to reduce network calls.
122
174
  */
123
175
  async getSupported() {
124
176
  const now = Date.now();
125
177
  if (this.cachedSupported && now - this.cacheTime < this.CACHE_TTL_MS) {
126
178
  return this.cachedSupported;
127
179
  }
128
- const response = await fetch(`${this.facilitatorUrl}/supported`);
180
+ const response = await this.fetchWithTimeout(`${this.facilitatorUrl}/supported`);
129
181
  if (!response.ok) {
130
182
  throw new Error(`Facilitator /supported returned ${response.status}`);
131
183
  }
@@ -135,9 +187,6 @@ var FacilitatorClient = class {
135
187
  }
136
188
  /**
137
189
  * Get the fee payer address for a specific network
138
- *
139
- * @param network - CAIP-2 network identifier
140
- * @returns Fee payer address
141
190
  */
142
191
  async getFeePayer(network) {
143
192
  const supported = await this.getSupported();
@@ -153,9 +202,6 @@ var FacilitatorClient = class {
153
202
  }
154
203
  /**
155
204
  * Get extra data for a network (feePayer, decimals, EIP-712 data, etc.)
156
- *
157
- * @param network - CAIP-2 network identifier
158
- * @returns Extra data from /supported
159
205
  */
160
206
  async getNetworkExtra(network) {
161
207
  const supported = await this.getSupported();
@@ -165,30 +211,22 @@ var FacilitatorClient = class {
165
211
  return kind?.extra;
166
212
  }
167
213
  /**
168
- * Verify a payment with the facilitator
169
- *
170
- * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value
171
- * @param requirements - The payment requirements that were sent to the client
172
- * @returns Verification response
214
+ * Verify a payment with the facilitator.
215
+ * Retries on 5xx and network errors with exponential backoff.
173
216
  */
174
217
  async verifyPayment(paymentSignatureHeader, requirements) {
175
218
  try {
176
219
  const paymentPayload = decodeBase64Json(paymentSignatureHeader);
177
- const verifyPayload = {
178
- x402Version: 2,
179
- paymentPayload,
180
- paymentRequirements: requirements
181
- };
182
- const response = await fetch(`${this.facilitatorUrl}/verify`, {
220
+ const response = await this.fetchWithRetry(`${this.facilitatorUrl}/verify`, {
183
221
  method: "POST",
184
- headers: {
185
- "Content-Type": "application/json"
186
- },
187
- body: JSON.stringify(verifyPayload)
222
+ headers: { "Content-Type": "application/json" },
223
+ body: JSON.stringify({
224
+ x402Version: 2,
225
+ paymentPayload,
226
+ paymentRequirements: requirements
227
+ })
188
228
  });
189
229
  if (!response.ok) {
190
- const errorText = await response.text();
191
- console.error(`Facilitator /verify returned ${response.status}:`, errorText);
192
230
  return {
193
231
  isValid: false,
194
232
  invalidReason: `facilitator_error_${response.status}`
@@ -196,38 +234,27 @@ var FacilitatorClient = class {
196
234
  }
197
235
  return await response.json();
198
236
  } catch (error) {
199
- console.error("Payment verification failed:", error);
200
- return {
201
- isValid: false,
202
- invalidReason: error instanceof Error ? error.message : "unexpected_verify_error"
203
- };
237
+ const reason = error instanceof HttpError ? `facilitator_error_${error.status}` : error instanceof Error && error.name === "AbortError" ? "facilitator_timeout" : error instanceof Error ? error.message : "unexpected_verify_error";
238
+ return { isValid: false, invalidReason: reason };
204
239
  }
205
240
  }
206
241
  /**
207
- * Settle a payment with the facilitator
208
- *
209
- * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value
210
- * @param requirements - The payment requirements that were sent to the client
211
- * @returns Settlement response with transaction signature on success
242
+ * Settle a payment with the facilitator.
243
+ * Retries on 5xx and network errors with exponential backoff.
212
244
  */
213
245
  async settlePayment(paymentSignatureHeader, requirements) {
214
246
  try {
215
247
  const paymentPayload = decodeBase64Json(paymentSignatureHeader);
216
- const settlePayload = {
217
- x402Version: 2,
218
- paymentPayload,
219
- paymentRequirements: requirements
220
- };
221
- const response = await fetch(`${this.facilitatorUrl}/settle`, {
248
+ const response = await this.fetchWithRetry(`${this.facilitatorUrl}/settle`, {
222
249
  method: "POST",
223
- headers: {
224
- "Content-Type": "application/json"
225
- },
226
- body: JSON.stringify(settlePayload)
250
+ headers: { "Content-Type": "application/json" },
251
+ body: JSON.stringify({
252
+ x402Version: 2,
253
+ paymentPayload,
254
+ paymentRequirements: requirements
255
+ })
227
256
  });
228
257
  if (!response.ok) {
229
- const errorText = await response.text();
230
- console.error(`Facilitator /settle returned ${response.status}:`, errorText);
231
258
  return {
232
259
  success: false,
233
260
  network: requirements.network,
@@ -235,22 +262,27 @@ var FacilitatorClient = class {
235
262
  };
236
263
  }
237
264
  const result = await response.json();
238
- return {
239
- ...result,
240
- network: requirements.network
241
- };
265
+ return { ...result, network: requirements.network };
242
266
  } catch (error) {
243
- console.error("Payment settlement failed:", error);
267
+ const reason = error instanceof HttpError ? `facilitator_error_${error.status}` : error instanceof Error && error.name === "AbortError" ? "facilitator_timeout" : error instanceof Error ? error.message : "unexpected_settle_error";
244
268
  return {
245
269
  success: false,
246
270
  network: requirements.network,
247
- errorReason: error instanceof Error ? error.message : "unexpected_settle_error"
271
+ errorReason: reason
248
272
  };
249
273
  }
250
274
  }
251
275
  };
252
276
 
253
277
  // src/server/x402-server.ts
278
+ function extractAmountFromHeader(paymentSignatureHeader) {
279
+ try {
280
+ const decoded = decodeBase64Json(paymentSignatureHeader);
281
+ return decoded?.accepted?.amount ?? decoded?.accepted?.maxAmountRequired;
282
+ } catch {
283
+ return void 0;
284
+ }
285
+ }
254
286
  function createX402Server(config) {
255
287
  const {
256
288
  payTo,
@@ -261,6 +293,29 @@ function createX402Server(config) {
261
293
  } = config;
262
294
  const facilitator = new FacilitatorClient(facilitatorUrl);
263
295
  let cachedExtra = null;
296
+ const requirementsCache = /* @__PURE__ */ new Map();
297
+ const CACHE_PRUNE_INTERVAL = 3e4;
298
+ let lastPrune = Date.now();
299
+ function cacheRequirements(accept) {
300
+ const ttl = (accept.maxTimeoutSeconds || defaultTimeoutSeconds) * 1e3;
301
+ requirementsCache.set(accept.payTo, { accept, expiresAt: Date.now() + ttl });
302
+ if (Date.now() - lastPrune > CACHE_PRUNE_INTERVAL) {
303
+ const now = Date.now();
304
+ for (const [key, entry] of requirementsCache) {
305
+ if (entry.expiresAt < now) requirementsCache.delete(key);
306
+ }
307
+ lastPrune = now;
308
+ }
309
+ }
310
+ function getCachedRequirements(address) {
311
+ const entry = requirementsCache.get(address);
312
+ if (!entry) return void 0;
313
+ if (entry.expiresAt < Date.now()) {
314
+ requirementsCache.delete(address);
315
+ return void 0;
316
+ }
317
+ return entry.accept;
318
+ }
264
319
  async function resolvePayTo(context) {
265
320
  if (typeof payTo === "string") return payTo;
266
321
  return payTo(context || {});
@@ -269,15 +324,15 @@ function createX402Server(config) {
269
324
  if (!cachedExtra) {
270
325
  cachedExtra = await facilitator.getNetworkExtra(network);
271
326
  }
272
- if (!cachedExtra?.feePayer) {
327
+ const isSvm = network.startsWith("solana:");
328
+ if (isSvm && !cachedExtra?.feePayer) {
273
329
  throw new Error(`Facilitator does not provide feePayer for network "${network}"`);
274
330
  }
275
331
  return {
276
- feePayer: cachedExtra.feePayer,
277
- decimals: cachedExtra.decimals ?? asset.decimals,
278
- // Include any additional EIP-712 data for EVM chains
279
- name: cachedExtra.name,
280
- version: cachedExtra.version
332
+ ...cachedExtra?.feePayer ? { feePayer: cachedExtra.feePayer } : {},
333
+ decimals: cachedExtra?.decimals ?? asset.decimals,
334
+ name: cachedExtra?.name,
335
+ version: cachedExtra?.version
281
336
  };
282
337
  }
283
338
  async function buildPaymentAccept(resolvedPayTo, options) {
@@ -286,7 +341,7 @@ function createX402Server(config) {
286
341
  timeoutSeconds = defaultTimeoutSeconds
287
342
  } = options;
288
343
  const extra = await getNetworkExtra();
289
- return {
344
+ const accept = {
290
345
  scheme: "exact",
291
346
  network,
292
347
  amount: amountAtomic,
@@ -296,6 +351,8 @@ function createX402Server(config) {
296
351
  maxTimeoutSeconds: timeoutSeconds,
297
352
  extra
298
353
  };
354
+ cacheRequirements(accept);
355
+ return accept;
299
356
  }
300
357
  async function getPaymentAccept(options) {
301
358
  const address = await resolvePayTo({
@@ -338,14 +395,26 @@ function createX402Server(config) {
338
395
  async function verifyPayment(paymentSignatureHeader, requirements) {
339
396
  if (!requirements) {
340
397
  const address = await resolvePayTo({ paymentHeader: paymentSignatureHeader });
341
- requirements = await buildPaymentAccept(address, { amountAtomic: "0", resourceUrl: "" });
398
+ requirements = getCachedRequirements(address);
399
+ if (!requirements) {
400
+ requirements = await buildPaymentAccept(address, {
401
+ amountAtomic: extractAmountFromHeader(paymentSignatureHeader) ?? "0",
402
+ resourceUrl: ""
403
+ });
404
+ }
342
405
  }
343
406
  return facilitator.verifyPayment(paymentSignatureHeader, requirements);
344
407
  }
345
408
  async function settlePayment(paymentSignatureHeader, requirements) {
346
409
  if (!requirements) {
347
410
  const address = await resolvePayTo({ paymentHeader: paymentSignatureHeader });
348
- requirements = await buildPaymentAccept(address, { amountAtomic: "0", resourceUrl: "" });
411
+ requirements = getCachedRequirements(address);
412
+ if (!requirements) {
413
+ requirements = await buildPaymentAccept(address, {
414
+ amountAtomic: extractAmountFromHeader(paymentSignatureHeader) ?? "0",
415
+ resourceUrl: ""
416
+ });
417
+ }
349
418
  }
350
419
  return facilitator.settlePayment(paymentSignatureHeader, requirements);
351
420
  }
@@ -364,6 +433,15 @@ function createX402Server(config) {
364
433
  // src/server/middleware.ts
365
434
  var DEFAULT_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
366
435
  var USDC_DECIMALS = 6;
436
+ function resolvePayToForNetwork(payTo, network) {
437
+ if (typeof payTo === "string" || typeof payTo === "function") return payTo;
438
+ if (network in payTo) return payTo[network];
439
+ const prefix = network.split(":")[0];
440
+ const globKey = `${prefix}:*`;
441
+ if (globKey in payTo) return payTo[globKey];
442
+ if ("*" in payTo) return payTo["*"];
443
+ throw new Error(`No payTo configured for network "${network}"`);
444
+ }
367
445
  function x402Middleware(config) {
368
446
  const {
369
447
  payTo,
@@ -378,18 +456,37 @@ function x402Middleware(config) {
378
456
  getAmount,
379
457
  getDescription
380
458
  } = config;
381
- const providerDefaults = typeof payTo !== "string" ? payTo._x402Defaults : void 0;
382
- const network = config.network ?? providerDefaults?.network ?? DEFAULT_NETWORK;
383
- const facilitatorUrl = config.facilitatorUrl ?? providerDefaults?.facilitatorUrl;
384
459
  const log = verbose ? console.log.bind(console, "[x402:middleware]") : () => {
385
460
  };
386
- const server = createX402Server({
387
- payTo,
388
- network,
389
- asset,
390
- facilitatorUrl,
391
- defaultTimeoutSeconds: timeoutSeconds
392
- });
461
+ const singleProviderDefaults = typeof payTo === "function" ? payTo._x402Defaults : void 0;
462
+ const facilitatorUrl = config.facilitatorUrl ?? singleProviderDefaults?.facilitatorUrl;
463
+ const configuredNetworks = (() => {
464
+ if (config.network) {
465
+ return Array.isArray(config.network) ? config.network : [config.network];
466
+ }
467
+ if (singleProviderDefaults?.network) return [singleProviderDefaults.network];
468
+ return [DEFAULT_NETWORK];
469
+ })();
470
+ const servers = /* @__PURE__ */ new Map();
471
+ for (const net of configuredNetworks) {
472
+ const netPayTo = resolvePayToForNetwork(payTo, net);
473
+ if (typeof netPayTo === "function" && netPayTo._stripeNetwork) {
474
+ const stripeNet = netPayTo._stripeNetwork;
475
+ if (net !== stripeNet) {
476
+ throw new Error(
477
+ `stripePayTo is configured for "${stripeNet}" but middleware includes network "${net}". Stripe only supports Base deposit addresses. Use a static payTo for other chains.`
478
+ );
479
+ }
480
+ }
481
+ servers.set(net, createX402Server({
482
+ payTo: netPayTo,
483
+ network: net,
484
+ asset,
485
+ facilitatorUrl,
486
+ defaultTimeoutSeconds: timeoutSeconds
487
+ }));
488
+ }
489
+ const primaryServer = servers.get(configuredNetworks[0]);
393
490
  return async (req, res, next) => {
394
491
  try {
395
492
  const paymentSignature = req.headers["payment-signature"];
@@ -407,8 +504,23 @@ function x402Middleware(config) {
407
504
  mimeType,
408
505
  timeoutSeconds
409
506
  };
410
- const requirements = await server.buildRequirements(requirementsOptions);
411
- const encoded = server.encodeRequirements(requirements);
507
+ const allAccepts = [];
508
+ let requirements = null;
509
+ for (const [, srv] of servers) {
510
+ try {
511
+ const reqs = await srv.buildRequirements(requirementsOptions);
512
+ allAccepts.push(...reqs.accepts);
513
+ if (!requirements) requirements = reqs;
514
+ } catch (e) {
515
+ log("Failed to build requirements for a network:", e);
516
+ }
517
+ }
518
+ if (!requirements || allAccepts.length === 0) {
519
+ res.status(500).json({ error: "Failed to build payment requirements" });
520
+ return;
521
+ }
522
+ requirements = { ...requirements, accepts: allAccepts };
523
+ const encoded = primaryServer.encodeRequirements(requirements);
412
524
  res.setHeader("PAYMENT-REQUIRED", encoded);
413
525
  res.status(402).json({
414
526
  error: "Payment required",
@@ -418,7 +530,16 @@ function x402Middleware(config) {
418
530
  return;
419
531
  }
420
532
  log("Payment signature received, verifying...");
421
- const verifyResult = await server.verifyPayment(paymentSignature);
533
+ let targetServer = primaryServer;
534
+ try {
535
+ const decoded = JSON.parse(Buffer.from(paymentSignature, "base64").toString());
536
+ const paymentNetwork = decoded?.accepted?.network;
537
+ if (paymentNetwork && servers.has(paymentNetwork)) {
538
+ targetServer = servers.get(paymentNetwork);
539
+ }
540
+ } catch {
541
+ }
542
+ const verifyResult = await targetServer.verifyPayment(paymentSignature);
422
543
  if (!verifyResult.isValid) {
423
544
  log("Payment verification failed:", verifyResult.invalidReason);
424
545
  res.status(402).json({
@@ -428,7 +549,7 @@ function x402Middleware(config) {
428
549
  return;
429
550
  }
430
551
  log("Payment verified, settling...");
431
- const settleResult = await server.settlePayment(paymentSignature);
552
+ const settleResult = await targetServer.settlePayment(paymentSignature);
432
553
  if (!settleResult.success) {
433
554
  log("Payment settlement failed:", settleResult.errorReason);
434
555
  res.status(402).json({
@@ -438,15 +559,16 @@ function x402Middleware(config) {
438
559
  return;
439
560
  }
440
561
  log("Payment settled:", settleResult.transaction);
562
+ const settledNetwork = settleResult.network || configuredNetworks[0];
441
563
  req.x402 = {
442
564
  transaction: settleResult.transaction,
443
565
  payer: verifyResult.payer ?? "",
444
- network
566
+ network: settledNetwork
445
567
  };
446
568
  const paymentResponseData = {
447
569
  success: true,
448
570
  transaction: settleResult.transaction,
449
- network,
571
+ network: settledNetwork,
450
572
  payer: verifyResult.payer ?? ""
451
573
  };
452
574
  if (settleResult.extensions) {
@@ -482,6 +604,9 @@ function x402Middleware(config) {
482
604
  }
483
605
 
484
606
  // src/server/browser-support.ts
607
+ function esc(s) {
608
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
609
+ }
485
610
  var USDC_ICON_SVG = `<svg width="18" height="18" viewBox="0 0 2000 2000" xmlns="http://www.w3.org/2000/svg"><path d="M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z" fill="#2775ca"/><path d="M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z" fill="#fff"/><path d="M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z" fill="#fff"/></svg>`;
486
611
  var DEXTER_CREST_SVG = `<svg width="36" height="36" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg"><g><path fill="#F2681A" d="m324.93,313.11c-115.5,0-231,0-350,0l350,0z"/><path fill="#FDFAF5" d="m230.43,50.62c1.1.85 2.19 1.7 3.32 2.57 6.02 4.8 11.77 9.88 17.46 15.07.92.84.92.84 1.86 1.69 1.82 1.69 3.59 3.42 5.35 5.16.61.56 1.22 1.13 1.84 1.71 5.66 5.76 6.18 10.43 6.13 18.3.02 1.16.04 2.32.06 3.52.06 3.83.06 7.65.07 11.48.02 2.68.05 5.35.08 8.03.05 5.6.09 11.21.1 16.81.02 7.15.09 14.31.17 21.46.06 5.53.1 11.05.13 16.58.02 2.64.04 5.27.07 7.91.18 17.58.12 32.82-11.24 47.32-7.35 7.27-16.54 12.06-25.42 17.22-1.97 1.16-3.94 2.33-5.91 3.49-7.16 4.24-14.34 8.44-21.53 12.62-4.8 2.79-9.59 5.6-14.38 8.42-1.25.73-2.5 1.47-3.79 2.23-2.32 1.36-4.64 2.73-6.96 4.1-27.47 16.09-27.47 16.09-42.16 12.93-8.06-2.28-14.94-5.82-22.16-10.02-1.17-.67-2.34-1.34-3.54-2.04-24.55-14.25-43.58-27.03-51.9-55.58-1.07-4.58-1.54-8.92-1.52-13.61.28-9.5.28-9.5-3.3-17.97-1.81-1.49-3.68-2.92-5.59-4.28-9.19-7.06-12.7-20.03-14.18-31.06-.54-5.77-.55-11.56-.6-17.35-.03-1.32-.07-2.63-.1-3.99-.01-1.26-.02-2.53-.03-3.83-.02-1.15-.03-2.29-.05-3.47.72-4.02 1.94-5.36 5.21-7.74 2.89-.53 2.89-.53 6.07-.46 1.71.02 1.71.02 3.46.05 1.19.04 2.37.08 3.59.12 1.2.02 2.41.04 3.65.06 2.97.05 5.93.13 8.9.23.14-1.35.29-2.7.43-4.08.63-5 1.78-9.74 3.14-14.58.22-.79.43-1.59.66-2.4.53-1.92 1.06-3.84 1.6-5.76-1.55-.45-1.55-.45-3.13-.9-9.52-3.52-17.1-10.95-21.37-20.1-3.81-9.26-3.87-20.34-.29-29.68 6.49-13.99 16.36-23.23 30.66-29.01 49.81-17.69 115.79 8.35 155.13 38.85z"/><path fill="#F2671A" d="m142.93,22.62c.86.19 1.73.39 2.62.59 36.12 8.21 68.79 24.98 95.38 50.75 1.02.98 2.03 1.97 3.08 2.98 10.84 10.66 10.84 10.66 11.05 14.62-2.06 3.55-5.44 4.18-9.17 5.3-.79.25-1.59.49-2.41.75-28.13 8.43-60.95 6.37-87.13-7.16-.86-.49-1.71-.97-2.6-1.48-7.37-4.05-12.59-3.36-20.59-1.54-22.76 4-48.47 1.53-68.69-9.74-4.88-3.88-8.23-8.29-10.21-14.22-.93-10.38-.67-18.44 5.83-26.83 19.57-23.38 55.99-20.36 82.83-14z"/><path fill="#F16619" d="m44.93,129.12c27.36-.03 54.72-.05 82.08-.06 12.7-.01 25.41-.01 38.11-.03 11.07-.01 22.14-.02 33.2-.02 5.86 0 11.73-.01 17.59-.01 5.51-.01 11.03-.01 16.54-.01 2.03 0 4.06 0 6.09-.01 2.76-.01 5.52 0 8.28 0 .81 0 1.63-.01 2.47-.01 5.51.02 5.51.02 6.81 1.32.22 3.43.22 3.43 0 7-2.75 2.75-3.42 2.66-7.15 2.82-1.41.07-1.41.07-2.85.14-1.47.05-1.47.05-2.98.11-1.49.07-1.49.07-3 .14-2.45.11-4.9.21-7.35.3-.2 1.3-.4 2.59-.6 3.93-2.57 16.08-5.93 29.89-18.89 40.86-10.35 7.28-21.87 8.49-34.17 7.71-13.11-2.33-22.52-9.19-30.33-19.83-4.49-7.64-4.8-17.05-5.83-25.67-4.24.39-8.47.77-12.83 1.17-.28 1.84-.28 1.84-.56 3.71-2.32 14.39-5.63 23.35-16.95 33.11-2.32 1.67-2.32 1.67-4.65 1.67 4 4.67 9.06 6.59 14.87 8.24 3.79 1.09 3.79 1.09 6.12 3.43-.65 5.31-.65 5.31-2.33 7-8.42-.27-15.13-2.29-22.17-7-1.09-1.21-2.17-2.43-3.25-3.65-2.72-2.81-4.45-3.84-8.36-4.16-1.67-.02-3.34-.02-5.01.01-1.77-.04-3.54-.09-5.3-.15-1.27-.04-1.27-.04-2.56-.08-9.26-.54-17.6-4.56-24.51-10.64-9.58-11.11-11.03-22.56-10.72-36.82.02-1.4.03-2.8.05-4.24.04-3.42.1-6.85.17-10.27z"/><path fill="#F26117" d="m172.68,203.08c7.27.09 13.23 1.97 18.87 6.65 2.88 3.07 3.86 5.12 4.25 9.32-.12 1.01-.24 2.02-.36 3.06-2.55.95-2.55.95-5.83 1.17-3.28-2.84-3.28-2.84-5.83-5.83-.36.58-.71 1.16-1.08 1.75-7.6 11.29-20.06 17.74-33.05 21.09-20.36 3.1-36.81-1.66-53.37-13.73-2.33-2.11-2.33-2.11-4.67-5.61.42-3.45.99-4.49 3.5-7 4.07.37 5.95 2.13 8.75 4.96 9.81 8.93 22.53 11.87 35.51 11.69 11.74-1.05 22.38-5.85 31.57-13.15 2.06-2.45 2.06-2.45 3.5-4.67-1.66.07-1.66.07-3.35.15-3.65-.15-3.65-.15-5.98-2.48.75-6.18 1.46-7.19 7.58-7.36z"/></g></svg>`;
487
612
  var DEXTER_STYLES = `
@@ -741,22 +866,22 @@ function generatePaywallHtml(paymentRequiredHeader, requestUrl, method, config,
741
866
  } catch {
742
867
  }
743
868
  const chainName = network.includes("solana") ? "Solana" : network.includes("eip155") ? "Base" : "";
744
- const endpointSection = config.showEndpoint ? `<div class="endpoint"><code>${method} ${requestUrl}</code></div>` : "";
869
+ const endpointSection = config.showEndpoint ? `<div class="endpoint"><code>${esc(method)} ${esc(requestUrl)}</code></div>` : "";
745
870
  return `<!DOCTYPE html>
746
871
  <html lang="en">
747
872
  <head>
748
873
  <meta charset="utf-8">
749
874
  <meta name="viewport" content="width=device-width,initial-scale=1">
750
- <title>${config.title} \u2014 ${price} USDC</title>
875
+ <title>${esc(config.title)} \u2014 ${esc(price)} USDC</title>
751
876
  <style>${DEXTER_STYLES}${PAY_BUTTON_STYLES}</style>
752
877
  </head>
753
878
  <body>
754
879
  <div class="card">
755
880
  <div class="crest">${DEXTER_CREST_SVG}</div>
756
- <h1>${config.title}</h1>
757
- <p class="desc">${description}</p>
758
- <div class="price">${USDC_ICON_SVG}<span id="price-value">${price}</span></div>
759
- <div class="chain">${chainName}${chainName ? " network" : ""}</div>
881
+ <h1>${esc(config.title)}</h1>
882
+ <p class="desc">${esc(description)}</p>
883
+ <div class="price">${USDC_ICON_SVG}<span id="price-value">${esc(price)}</span></div>
884
+ <div class="chain">${esc(chainName)}${chainName ? " network" : ""}</div>
760
885
  ${endpointSection}
761
886
 
762
887
  <div id="pay-section" class="pay-section" style="display:none">
@@ -890,11 +1015,15 @@ function x402AccessPass(config) {
890
1015
  facilitatorUrl,
891
1016
  tiers: tierPrices,
892
1017
  ratePerHour,
893
- secret = import_crypto.default.randomBytes(32),
1018
+ secret: explicitSecret,
894
1019
  issuer = "x402-access-pass",
895
1020
  verbose = false,
896
1021
  description
897
1022
  } = config;
1023
+ const secret = explicitSecret ?? import_crypto.default.randomBytes(32);
1024
+ if (!explicitSecret) {
1025
+ console.warn("[x402:access-pass] No secret provided \u2014 access passes will be invalidated on server restart. Set `secret` for production use.");
1026
+ }
898
1027
  if (!tierPrices && !ratePerHour) {
899
1028
  throw new Error("x402AccessPass: at least one of `tiers` or `ratePerHour` is required");
900
1029
  }
@@ -1903,13 +2032,9 @@ function stripePayTo(secretKeyOrConfig) {
1903
2032
  amount: amountInCents,
1904
2033
  currency: "usd",
1905
2034
  payment_method_types: ["crypto"],
1906
- payment_method_data: {
1907
- type: "crypto"
1908
- },
2035
+ payment_method_data: { type: "crypto" },
1909
2036
  payment_method_options: {
1910
- crypto: {
1911
- mode: "custom"
1912
- }
2037
+ crypto: { mode: "custom" }
1913
2038
  },
1914
2039
  confirm: true
1915
2040
  });
@@ -1932,6 +2057,7 @@ function stripePayTo(secretKeyOrConfig) {
1932
2057
  network: caip2Network,
1933
2058
  facilitatorUrl: "https://x402.dexter.cash"
1934
2059
  };
2060
+ provider._stripeNetwork = caip2Network;
1935
2061
  return provider;
1936
2062
  }
1937
2063
  // Annotate the CommonJS export names for ESM import in node: