@parallel-protocol/x402 0.7.1 → 0.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.
@@ -1,4 +1,4 @@
1
- import { X402_ERROR_CODES, X402RuntimeError, X402ConfigError, isPriceRejection } from './chunk-AFRDHGDT.js';
1
+ import { X402_ERROR_CODES, X402ConfigError, X402RuntimeError, isPriceRejection } from './chunk-QAECRSWF.js';
2
2
  import { getTokenDecimals as getTokenDecimals$1 } from '@parallel-protocol/chains';
3
3
  import { z } from 'zod';
4
4
 
@@ -127,8 +127,18 @@ var priceSchema = z.union([
127
127
  "Price must be a string, a bigint or a function of the request"
128
128
  )
129
129
  ]);
130
+ var LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
131
+ function isFacilitatorUrl(value) {
132
+ if (!URL.canParse(value)) return false;
133
+ const { protocol, hostname } = new URL(value);
134
+ return protocol === "https:" || protocol === "http:" && LOCAL_HOSTNAMES.has(hostname);
135
+ }
136
+ var facilitatorUrlSchema = z.string().refine(
137
+ isFacilitatorUrl,
138
+ "The facilitator URL must use https (plain http only on localhost, 127.0.0.1 or [::1])"
139
+ );
130
140
  var facilitatorConfigSchema = z.object({
131
- url: z.string().refine((v) => URL.canParse(v), "Invalid facilitator URL"),
141
+ url: facilitatorUrlSchema,
132
142
  apiKey: z.string().optional()
133
143
  });
134
144
  var UPTO_MAX_TIMEOUT_SECONDS = 3600;
@@ -170,26 +180,32 @@ var facilitatorResponseSchema = z.discriminatedUnion("success", [
170
180
  chain: z.string(),
171
181
  gasSponsored: z.boolean(),
172
182
  networkId: z.string(),
173
- amountSettled: z.string().optional()
183
+ amountSettled: z.string().optional(),
184
+ alreadySettled: z.boolean().optional()
174
185
  }),
175
186
  z.object({
176
187
  success: z.literal(false),
177
188
  error: z.object({
178
189
  code: z.string(),
179
190
  message: z.string(),
180
- hint: z.string().optional()
191
+ hint: z.string().optional(),
192
+ status: z.number().optional(),
193
+ retryAfter: z.string().optional()
181
194
  })
182
195
  })
183
196
  ]);
184
197
  var verifyResponseSchema = z.object({
185
- isValid: z.literal(true)
198
+ isValid: z.literal(true),
199
+ settleToken: z.string().min(1)
186
200
  });
187
201
  var settleSuccessSchema = z.object({
188
202
  txHash: txHashSchema,
189
203
  route: z.string(),
190
204
  gasSponsored: z.boolean(),
191
205
  // Metered routes: the amount actually charged (smallest unit).
192
- amountSettled: z.string().optional()
206
+ amountSettled: z.string().optional(),
207
+ // The facilitator answered from a recorded outcome, nothing was broadcast.
208
+ alreadySettled: z.boolean().optional()
193
209
  });
194
210
  var settleErrorSchema = z.object({
195
211
  error: z.string(),
@@ -203,6 +219,29 @@ var settleResponseSchema = z.union([
203
219
  // src/client.ts
204
220
  var FACILITATOR_TIMEOUT_MS = 1e4;
205
221
  var SETTLE_TIMEOUT_MS = 6e4;
222
+ var RETRY_AFTER_SHAPE = /^(?:\d{1,10}|[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT)$/;
223
+ async function readErrorBody(response) {
224
+ const json = await response.json().catch(() => null);
225
+ if (typeof json !== "object" || json === null) return {};
226
+ const { error, message } = json;
227
+ return {
228
+ ...typeof error === "string" && { error },
229
+ ...typeof message === "string" && { message }
230
+ };
231
+ }
232
+ function retryAfterOf(response) {
233
+ const value = response.headers.get("retry-after");
234
+ return value !== null && RETRY_AFTER_SHAPE.test(value) ? value : void 0;
235
+ }
236
+ function throwIfRedirect(response) {
237
+ const redirected = response.type === "opaqueredirect" || response.status >= 300 && response.status < 400;
238
+ if (!redirected) return;
239
+ response.body?.cancel().catch(() => {
240
+ });
241
+ throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE, {
242
+ status: response.status
243
+ });
244
+ }
206
245
  function decodePaymentHeader(paymentHeader) {
207
246
  try {
208
247
  return decodeBase64(paymentHeader);
@@ -211,24 +250,43 @@ function decodePaymentHeader(paymentHeader) {
211
250
  }
212
251
  }
213
252
  var FacilitatorClient = class {
253
+ // Checked and kept when the client is built: a config changed afterwards
254
+ // does not move the calls elsewhere.
255
+ url;
256
+ apiKey;
214
257
  constructor(config) {
215
- this.config = config;
258
+ const url = facilitatorUrlSchema.safeParse(config.url);
259
+ if (!url.success) {
260
+ throw new X402ConfigError(
261
+ url.error.issues[0]?.message ?? "Invalid facilitator URL",
262
+ url.error
263
+ );
264
+ }
265
+ this.url = new URL(url.data).href.replace(/\/+$/, "");
266
+ this.apiKey = config.apiKey;
216
267
  }
217
- config;
218
268
  async verify(paymentHeader, paymentRequirements) {
219
269
  const paymentPayload = decodePaymentHeader(paymentHeader);
220
270
  let json;
221
271
  try {
222
- const response = await fetch(`${this.config.url}/x402/verify`, {
272
+ const response = await fetch(`${this.url}/x402/verify`, {
223
273
  method: "POST",
224
274
  headers: this.buildHeaders(),
225
275
  body: JSON.stringify({ paymentPayload, paymentRequirements }),
276
+ redirect: "manual",
226
277
  signal: AbortSignal.timeout(FACILITATOR_TIMEOUT_MS)
227
278
  });
279
+ throwIfRedirect(response);
228
280
  if (!response.ok) {
229
- const errorBody = await response.json().catch(() => null);
230
- const code = errorBody?.error ?? X402_ERROR_CODES.FACILITATOR_UNAVAILABLE;
231
- throw new X402RuntimeError(code);
281
+ const body = await readErrorBody(response);
282
+ throw new X402RuntimeError(
283
+ body.error ?? X402_ERROR_CODES.FACILITATOR_UNAVAILABLE,
284
+ {
285
+ detail: body.message,
286
+ status: response.status,
287
+ retryAfter: retryAfterOf(response)
288
+ }
289
+ );
232
290
  }
233
291
  json = await response.json();
234
292
  } catch (e) {
@@ -236,7 +294,8 @@ var FacilitatorClient = class {
236
294
  throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
237
295
  }
238
296
  try {
239
- verifyResponseSchema.parse(json);
297
+ const { settleToken } = verifyResponseSchema.parse(json);
298
+ return { settleToken };
240
299
  } catch {
241
300
  throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
242
301
  }
@@ -245,28 +304,47 @@ var FacilitatorClient = class {
245
304
  const paymentPayload = decodePaymentHeader(paymentHeader);
246
305
  let json;
247
306
  try {
248
- const response = await fetch(`${this.config.url}/x402/settle`, {
307
+ const response = await fetch(`${this.url}/x402/settle`, {
249
308
  method: "POST",
250
309
  headers: this.buildHeaders(),
251
- // settleAmount only travels for metered routes — exact bodies are unchanged.
310
+ // settleAmount only travels for metered routes; the settle token
311
+ // travels whenever verify issued one.
252
312
  body: JSON.stringify({
253
313
  paymentPayload,
254
314
  paymentRequirements,
255
315
  ...options?.amount !== void 0 && {
256
316
  settleAmount: options.amount
317
+ },
318
+ ...options?.settleToken !== void 0 && {
319
+ settleToken: options.settleToken
257
320
  }
258
321
  }),
322
+ redirect: "manual",
259
323
  signal: AbortSignal.timeout(SETTLE_TIMEOUT_MS)
260
324
  });
325
+ throwIfRedirect(response);
261
326
  if (!response.ok) {
262
- const errorBody = await response.json().catch(() => null);
263
- const code = errorBody?.error ?? "SUBMISSION_FAILED";
264
- const message = errorBody?.message ?? "Settlement failed";
265
- return { success: false, error: { code, message } };
327
+ const body = await readErrorBody(response);
328
+ if (body.error === void 0 && response.status >= 500) {
329
+ throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
330
+ }
331
+ const retryAfter = retryAfterOf(response);
332
+ return {
333
+ success: false,
334
+ error: {
335
+ code: body.error ?? "SUBMISSION_FAILED",
336
+ message: body.message ?? "Settlement failed",
337
+ status: response.status,
338
+ ...retryAfter !== void 0 && { retryAfter }
339
+ }
340
+ };
266
341
  }
267
342
  json = await response.json();
268
343
  } catch (e) {
269
344
  if (e instanceof X402RuntimeError) throw e;
345
+ if (e instanceof Error && e.name === "TimeoutError") {
346
+ throw new X402RuntimeError(X402_ERROR_CODES.SETTLE_TIMEOUT);
347
+ }
270
348
  throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
271
349
  }
272
350
  try {
@@ -281,7 +359,8 @@ var FacilitatorClient = class {
281
359
  networkId: toEip155Network(paymentRequirements.network),
282
360
  ...parsed.amountSettled !== void 0 && {
283
361
  amountSettled: parsed.amountSettled
284
- }
362
+ },
363
+ ...parsed.alreadySettled && { alreadySettled: true }
285
364
  };
286
365
  }
287
366
  return {
@@ -292,16 +371,22 @@ var FacilitatorClient = class {
292
371
  throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
293
372
  }
294
373
  }
374
+ /**
375
+ * @deprecated The Parallel facilitator no longer serves `/x402/pay`, so this
376
+ * call fails with `FACILITATOR_UNAVAILABLE`. Use `verify`, then `settle`.
377
+ */
295
378
  async pay(paymentHeader) {
296
379
  const headers = this.buildHeaders();
297
380
  headers["X-PAYMENT"] = paymentHeader;
298
381
  let json;
299
382
  try {
300
- const response = await fetch(`${this.config.url}/x402/pay`, {
383
+ const response = await fetch(`${this.url}/x402/pay`, {
301
384
  method: "POST",
302
385
  headers,
386
+ redirect: "manual",
303
387
  signal: AbortSignal.timeout(FACILITATOR_TIMEOUT_MS)
304
388
  });
389
+ throwIfRedirect(response);
305
390
  if (!response.ok) {
306
391
  throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
307
392
  }
@@ -320,8 +405,8 @@ var FacilitatorClient = class {
320
405
  const headers = {
321
406
  "Content-Type": "application/json"
322
407
  };
323
- if (this.config.apiKey) {
324
- headers["X-API-Key"] = this.config.apiKey;
408
+ if (this.apiKey) {
409
+ headers["X-API-Key"] = this.apiKey;
325
410
  }
326
411
  return headers;
327
412
  }
@@ -379,10 +464,21 @@ async function resolvePrice(config, ctx) {
379
464
  }
380
465
  var SETTLE_AMOUNT_HEADER = "payment-settle-amount";
381
466
  var DEFAULT_MAX_TIMEOUT_SECONDS = 300;
467
+ var SETTLEMENT_RESERVE_SECONDS = 120;
382
468
  function handlerTimeoutFor(config) {
383
469
  if ((config.scheme ?? "exact") !== "upto") return HANDLER_TIMEOUT_MS;
384
470
  const seconds = config.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
385
- return Math.max(HANDLER_TIMEOUT_MS, (seconds - 60) * 1e3);
471
+ return Math.max(
472
+ HANDLER_TIMEOUT_MS,
473
+ (seconds - SETTLEMENT_RESERVE_SECONDS) * 1e3
474
+ );
475
+ }
476
+ function jsonResult(status, body, headers = {}) {
477
+ return {
478
+ status,
479
+ headers: { "Content-Type": "application/json", ...headers },
480
+ body
481
+ };
386
482
  }
387
483
  function resolveSettleAmount(raw, maxAmount, decimals) {
388
484
  if (raw === void 0)
@@ -410,7 +506,10 @@ var INVALID_METER_RESPONSE = {
410
506
  message: "The route's meter function failed or returned something that is not an amount; the response was discarded and nothing was charged."
411
507
  };
412
508
  function invalidSettleAmountResponse(reason) {
413
- return reason === "meter" ? INVALID_METER_RESPONSE : INVALID_SETTLE_AMOUNT_RESPONSE;
509
+ return jsonResult(
510
+ 402,
511
+ reason === "meter" ? INVALID_METER_RESPONSE : INVALID_SETTLE_AMOUNT_RESPONSE
512
+ );
414
513
  }
415
514
  var AMOUNT_FORMAT = /^\d+(?:\.\d+)?$/;
416
515
  async function resolveCharge(verified, settleHeader, response) {
@@ -558,31 +657,46 @@ function buildFacilitatorRequirements(config, asset, price) {
558
657
  }
559
658
  };
560
659
  }
561
- function paymentRequiredResponse(url, config, resolvedTokens, price, error) {
660
+ var CODE_SHAPE = /^[A-Z][A-Z0-9_]{2,63}$/;
661
+ var MESSAGE_MAX_LENGTH = 300;
662
+ function shapedCode(code) {
663
+ return typeof code === "string" && CODE_SHAPE.test(code) ? code : void 0;
664
+ }
665
+ function boundedMessage(message) {
666
+ if (typeof message !== "string") return void 0;
667
+ const oneLine = message.replace(/[\p{Cc}\p{Cf}]+/gu, " ").replace(/\s+/g, " ").trim();
668
+ if (!oneLine) return void 0;
669
+ const chars = Array.from(oneLine);
670
+ return chars.length > MESSAGE_MAX_LENGTH ? `${chars.slice(0, MESSAGE_MAX_LENGTH).join("")}\u2026` : oneLine;
671
+ }
672
+ function paymentRequiredResponse(url, config, resolvedTokens, price, refusal) {
562
673
  const paymentRequired = buildPaymentRequired(
563
674
  url,
564
675
  config,
565
676
  resolvedTokens,
566
677
  price
567
678
  );
568
- if (error) paymentRequired.error = error;
569
- return {
570
- status: 402,
571
- headers: {
572
- "Content-Type": "application/json",
573
- "payment-required": encodeBase64(paymentRequired),
574
- "access-control-expose-headers": "payment-required"
575
- },
576
- body: paymentRequired
577
- };
679
+ if (refusal) {
680
+ paymentRequired.error = shapedCode(refusal.code) ?? X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE;
681
+ const message = boundedMessage(refusal.detail);
682
+ if (message) paymentRequired.message = message;
683
+ }
684
+ return jsonResult(402, paymentRequired, {
685
+ "payment-required": encodeBase64(paymentRequired),
686
+ "access-control-expose-headers": "payment-required",
687
+ ...refusal?.retryAfter !== void 0 && {
688
+ "Retry-After": refusal.retryAfter
689
+ }
690
+ });
578
691
  }
579
692
  function createPaymentGate(config) {
580
- try {
581
- paymentMiddlewareConfigSchema.parse(config);
582
- } catch (cause) {
693
+ const checked = paymentMiddlewareConfigSchema.safeParse(config);
694
+ if (!checked.success) {
695
+ const issue = checked.error.issues[0];
696
+ const where = issue?.path.length ? ` at ${issue.path.join(".")}` : "";
583
697
  throw new X402ConfigError(
584
- "Invalid paymentMiddleware config \u2014 check your routes, facilitator URL and payTo addresses",
585
- cause
698
+ `Invalid paymentMiddleware config${where}: ${issue?.message ?? "check your routes, facilitator URL and payTo addresses"}`,
699
+ checked.error
586
700
  );
587
701
  }
588
702
  const client = new FacilitatorClient(config.facilitator);
@@ -630,10 +744,11 @@ function createPaymentGate(config) {
630
744
  asset,
631
745
  price
632
746
  );
747
+ let settleToken;
633
748
  try {
634
- await client.verify(paymentHeader, requirements);
749
+ ({ settleToken } = await client.verify(paymentHeader, requirements));
635
750
  } catch (e) {
636
- const code = e instanceof X402RuntimeError ? e.code : X402_ERROR_CODES.FACILITATOR_UNAVAILABLE;
751
+ const refusal = e instanceof X402RuntimeError ? { code: e.code, detail: e.detail, retryAfter: e.retryAfter } : { code: X402_ERROR_CODES.FACILITATOR_UNAVAILABLE };
637
752
  return {
638
753
  type: "error",
639
754
  result: paymentRequiredResponse(
@@ -641,7 +756,7 @@ function createPaymentGate(config) {
641
756
  routeConfig,
642
757
  resolvedTokens,
643
758
  price,
644
- code
759
+ refusal
645
760
  )
646
761
  };
647
762
  }
@@ -652,12 +767,71 @@ function createPaymentGate(config) {
652
767
  maxAmount: BigInt(requirements.maxAmountRequired),
653
768
  decimals: resolveDecimals(routeConfig, asset),
654
769
  handlerTimeoutMs: handlerTimeoutFor(routeConfig),
655
- // Exact routes keep the historical two-argument client call.
656
- settle: (options) => options ? client.settle(paymentHeader, requirements, options) : client.settle(paymentHeader, requirements),
770
+ settle: (options) => client.settle(paymentHeader, requirements, { ...options, settleToken }),
657
771
  ...routeConfig.meter && { meter: routeConfig.meter, request }
658
772
  };
659
773
  };
660
774
  }
775
+ var UNKNOWN_SETTLEMENT_MESSAGE = "The payment could not be settled.";
776
+ var MERCHANT_SETTLEMENT_MESSAGE = "The merchant could not complete the settlement of this payment. The payment was not taken: do not sign another payment for this request before checking with the merchant.";
777
+ var AGENT_MESSAGES = {
778
+ [X402_ERROR_CODES.SETTLE_TIMEOUT]: "The facilitator did not confirm the settlement in time. The payment may still settle: do not sign another payment for this request before checking with the merchant.",
779
+ [X402_ERROR_CODES.FACILITATOR_UNAVAILABLE]: "The facilitator could not be reached to settle the payment. It may still have settled: do not sign another payment for this request before checking with the merchant.",
780
+ [X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE]: "The facilitator answered the settlement with an unexpected response. The payment may have settled: do not sign another payment for this request before checking with the merchant.",
781
+ SETTLE_IN_PROGRESS: "The facilitator is still settling this payment. Do not sign another payment for this request before checking with the merchant.",
782
+ RECEIPT_UNAVAILABLE: "The facilitator sent the transaction but could not read its confirmation. The payment may have settled: do not sign another payment for this request before checking with the merchant.",
783
+ SETTLE_TOKEN_INVALID: MERCHANT_SETTLEMENT_MESSAGE,
784
+ SETTLE_TOKEN_REQUIRED: MERCHANT_SETTLEMENT_MESSAGE,
785
+ AMOUNT_MISMATCH: "The facilitator settled a different amount than this request asked for. The response was not served: do not sign another payment for this request before checking with the merchant.",
786
+ UNKNOWN: UNKNOWN_SETTLEMENT_MESSAGE
787
+ };
788
+ function settlementFailure(code, failure) {
789
+ const reason = shapedCode(code) ?? "UNKNOWN";
790
+ return {
791
+ settled: false,
792
+ reason,
793
+ message: AGENT_MESSAGES[reason] ?? boundedMessage(failure?.message) ?? UNKNOWN_SETTLEMENT_MESSAGE,
794
+ ...failure?.retryAfter !== void 0 && {
795
+ retryAfter: failure.retryAfter
796
+ }
797
+ };
798
+ }
799
+ var RETRY_ONCE_CODES = /* @__PURE__ */ new Set([
800
+ X402_ERROR_CODES.SETTLE_TIMEOUT,
801
+ X402_ERROR_CODES.FACILITATOR_UNAVAILABLE
802
+ ]);
803
+ async function settleVerified(verified, options) {
804
+ let response;
805
+ for (let attempt = 0; response === void 0; attempt++) {
806
+ try {
807
+ response = await verified.settle(options);
808
+ } catch (e) {
809
+ const code = e instanceof X402RuntimeError ? e.code : "UNKNOWN";
810
+ if (attempt > 0 || !RETRY_ONCE_CODES.has(code)) {
811
+ return settlementFailure(code);
812
+ }
813
+ }
814
+ }
815
+ if (!response.success) {
816
+ return settlementFailure(response.error.code, response.error);
817
+ }
818
+ if (options?.amount !== void 0 && response.amountSettled !== options.amount) {
819
+ return settlementFailure("AMOUNT_MISMATCH");
820
+ }
821
+ return { settled: true, confirmation: response };
822
+ }
823
+ function settlementFailureResponse(failure) {
824
+ const body = {
825
+ error: "PAYMENT_SETTLEMENT_FAILED",
826
+ reason: failure.reason,
827
+ message: failure.message
828
+ };
829
+ return jsonResult(402, body, {
830
+ ...failure.retryAfter !== void 0 && {
831
+ "Retry-After": failure.retryAfter
832
+ }
833
+ });
834
+ }
661
835
  function createPaymentMiddleware(config) {
662
836
  const gate = createPaymentGate(config);
663
837
  return async (adapter) => {
@@ -687,11 +861,7 @@ function createPaymentMiddleware(config) {
687
861
  });
688
862
  if (resolved.kind === "invalid") {
689
863
  handlerResult.discardResponse();
690
- return {
691
- status: 402,
692
- headers: { "Content-Type": "application/json" },
693
- body: invalidSettleAmountResponse(resolved.reason)
694
- };
864
+ return invalidSettleAmountResponse(resolved.reason);
695
865
  }
696
866
  if (resolved.kind === "skip") {
697
867
  handlerResult.sendResponse();
@@ -699,37 +869,23 @@ function createPaymentMiddleware(config) {
699
869
  }
700
870
  settleOptions = { amount: resolved.amount };
701
871
  }
702
- let settled = false;
703
- try {
704
- const settleResponse = settleOptions ? await gateResult.settle(settleOptions) : await gateResult.settle();
705
- if (settleResponse.success) {
706
- handlerResult.setResponseHeader(
707
- "payment-response",
708
- encodeBase64(settleResponse)
709
- );
710
- handlerResult.setResponseHeader(
711
- "access-control-expose-headers",
712
- "payment-response"
713
- );
714
- settled = true;
715
- }
716
- } catch {
717
- }
718
- if (!settled) {
872
+ const outcome = await settleVerified(gateResult, settleOptions);
873
+ if (!outcome.settled) {
719
874
  handlerResult.discardResponse();
720
- return {
721
- status: 402,
722
- headers: { "Content-Type": "application/json" },
723
- body: {
724
- error: "PAYMENT_SETTLEMENT_FAILED",
725
- message: "Payment could not be confirmed after multiple attempts. Please retry."
726
- }
727
- };
875
+ return settlementFailureResponse(outcome);
728
876
  }
877
+ handlerResult.setResponseHeader(
878
+ "payment-response",
879
+ encodeBase64(outcome.confirmation)
880
+ );
881
+ handlerResult.setResponseHeader(
882
+ "access-control-expose-headers",
883
+ "payment-response"
884
+ );
729
885
  }
730
886
  handlerResult.sendResponse();
731
887
  return { pass: true, handlerRan: true };
732
888
  };
733
889
  }
734
890
 
735
- export { FacilitatorClient, HANDLER_TIMEOUT, PARALLEL_TOKENS, SETTLE_AMOUNT_HEADER, createPaymentGate, createPaymentMiddleware, encodeBase64, getDefaultAcceptedTokens, invalidSettleAmountResponse, isJsonContentType, jsonFromResponse, matchRoute, parseJsonBody, parsePrice, raceTimeout, resolveCharge, resolveSettleAmount, toEip155Network, validateAddress };
891
+ export { FacilitatorClient, HANDLER_TIMEOUT, PARALLEL_TOKENS, SETTLE_AMOUNT_HEADER, createPaymentGate, createPaymentMiddleware, encodeBase64, getDefaultAcceptedTokens, invalidSettleAmountResponse, isJsonContentType, jsonFromResponse, matchRoute, parseJsonBody, parsePrice, raceTimeout, resolveCharge, resolveSettleAmount, settleVerified, settlementFailureResponse, toEip155Network, validateAddress };
@@ -4,7 +4,9 @@
4
4
  var X402_ERROR_CODES = {
5
5
  FACILITATOR_UNAVAILABLE: "FACILITATOR_UNAVAILABLE",
6
6
  FACILITATOR_INVALID_RESPONSE: "FACILITATOR_INVALID_RESPONSE",
7
- INVALID_PAYMENT: "INVALID_PAYMENT"
7
+ INVALID_PAYMENT: "INVALID_PAYMENT",
8
+ /** The facilitator did not answer a settle within the client's timeout: the payment may still settle. */
9
+ SETTLE_TIMEOUT: "SETTLE_TIMEOUT"
8
10
  };
9
11
  var X402ConfigError = class extends Error {
10
12
  constructor(message, cause) {
@@ -14,12 +16,21 @@ var X402ConfigError = class extends Error {
14
16
  }
15
17
  };
16
18
  var X402RuntimeError = class extends Error {
17
- constructor(code) {
19
+ constructor(code, extra) {
18
20
  super(code);
19
21
  this.code = code;
20
22
  this.name = "X402RuntimeError";
23
+ if (extra?.detail !== void 0) this.detail = extra.detail;
24
+ if (extra?.status !== void 0) this.status = extra.status;
25
+ if (extra?.retryAfter !== void 0) this.retryAfter = extra.retryAfter;
21
26
  }
22
27
  code;
28
+ /** The facilitator's message for this code, when it answered with one. */
29
+ detail;
30
+ /** The facilitator's HTTP status, when the error comes from its answer. */
31
+ status;
32
+ /** The facilitator's `Retry-After` header, when it sent one. */
33
+ retryAfter;
23
34
  };
24
35
  var X402PriceRejectedError = class extends Error {
25
36
  constructor(code, message, status = 400) {
@@ -2,7 +2,9 @@
2
2
  var X402_ERROR_CODES = {
3
3
  FACILITATOR_UNAVAILABLE: "FACILITATOR_UNAVAILABLE",
4
4
  FACILITATOR_INVALID_RESPONSE: "FACILITATOR_INVALID_RESPONSE",
5
- INVALID_PAYMENT: "INVALID_PAYMENT"
5
+ INVALID_PAYMENT: "INVALID_PAYMENT",
6
+ /** The facilitator did not answer a settle within the client's timeout: the payment may still settle. */
7
+ SETTLE_TIMEOUT: "SETTLE_TIMEOUT"
6
8
  };
7
9
  var X402ConfigError = class extends Error {
8
10
  constructor(message, cause) {
@@ -12,12 +14,21 @@ var X402ConfigError = class extends Error {
12
14
  }
13
15
  };
14
16
  var X402RuntimeError = class extends Error {
15
- constructor(code) {
17
+ constructor(code, extra) {
16
18
  super(code);
17
19
  this.code = code;
18
20
  this.name = "X402RuntimeError";
21
+ if (extra?.detail !== void 0) this.detail = extra.detail;
22
+ if (extra?.status !== void 0) this.status = extra.status;
23
+ if (extra?.retryAfter !== void 0) this.retryAfter = extra.retryAfter;
19
24
  }
20
25
  code;
26
+ /** The facilitator's message for this code, when it answered with one. */
27
+ detail;
28
+ /** The facilitator's HTTP status, when the error comes from its answer. */
29
+ status;
30
+ /** The facilitator's `Retry-After` header, when it sent one. */
31
+ retryAfter;
21
32
  };
22
33
  var X402PriceRejectedError = class extends Error {
23
34
  constructor(code, message, status = 400) {