uvd-x402-sdk 2.95.0 → 2.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +34 -5
  2. package/dist/adapters/index.d.mts +1 -1
  3. package/dist/adapters/index.d.ts +1 -1
  4. package/dist/adapters/index.js +2 -1
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/adapters/index.mjs +2 -1
  7. package/dist/adapters/index.mjs.map +1 -1
  8. package/dist/backend/index.d.mts +3 -2
  9. package/dist/backend/index.d.ts +3 -2
  10. package/dist/backend/index.js +498 -30
  11. package/dist/backend/index.js.map +1 -1
  12. package/dist/backend/index.mjs +475 -31
  13. package/dist/backend/index.mjs.map +1 -1
  14. package/dist/{index-CF2HBEAJ.d.mts → index--bevvYU9.d.ts} +3 -1
  15. package/dist/{index-CkHu2s9r.d.ts → index-B2i1mGpW.d.mts} +3 -1
  16. package/dist/{index-DnxubrYX.d.mts → index-BsKsZzP3.d.mts} +1 -1
  17. package/dist/{index-DnxubrYX.d.ts → index-BsKsZzP3.d.ts} +1 -1
  18. package/dist/{index-CIUGPbu8.d.mts → index-ClOAmprt.d.mts} +232 -18
  19. package/dist/{index-DTbVW7EU.d.ts → index-DNTFp6WT.d.ts} +232 -18
  20. package/dist/index.d.mts +5 -4
  21. package/dist/index.d.ts +5 -4
  22. package/dist/index.js +512 -43
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +489 -44
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/providers/algorand/index.d.mts +1 -1
  27. package/dist/providers/algorand/index.d.ts +1 -1
  28. package/dist/providers/algorand/index.js +2 -1
  29. package/dist/providers/algorand/index.js.map +1 -1
  30. package/dist/providers/algorand/index.mjs +2 -1
  31. package/dist/providers/algorand/index.mjs.map +1 -1
  32. package/dist/providers/evm/index.d.mts +1 -1
  33. package/dist/providers/evm/index.d.ts +1 -1
  34. package/dist/providers/evm/index.js +2 -1
  35. package/dist/providers/evm/index.js.map +1 -1
  36. package/dist/providers/evm/index.mjs +2 -1
  37. package/dist/providers/evm/index.mjs.map +1 -1
  38. package/dist/providers/hedera/index.d.mts +1 -1
  39. package/dist/providers/hedera/index.d.ts +1 -1
  40. package/dist/providers/near/index.d.mts +1 -1
  41. package/dist/providers/near/index.d.ts +1 -1
  42. package/dist/providers/near/index.js +2 -1
  43. package/dist/providers/near/index.js.map +1 -1
  44. package/dist/providers/near/index.mjs +2 -1
  45. package/dist/providers/near/index.mjs.map +1 -1
  46. package/dist/providers/solana/index.d.mts +1 -1
  47. package/dist/providers/solana/index.d.ts +1 -1
  48. package/dist/providers/solana/index.js +2 -1
  49. package/dist/providers/solana/index.js.map +1 -1
  50. package/dist/providers/solana/index.mjs +2 -1
  51. package/dist/providers/solana/index.mjs.map +1 -1
  52. package/dist/providers/stellar/index.d.mts +1 -1
  53. package/dist/providers/stellar/index.d.ts +1 -1
  54. package/dist/providers/stellar/index.js +2 -1
  55. package/dist/providers/stellar/index.js.map +1 -1
  56. package/dist/providers/stellar/index.mjs +2 -1
  57. package/dist/providers/stellar/index.mjs.map +1 -1
  58. package/dist/providers/sui/index.d.mts +1 -1
  59. package/dist/providers/sui/index.d.ts +1 -1
  60. package/dist/providers/sui/index.js +2 -1
  61. package/dist/providers/sui/index.js.map +1 -1
  62. package/dist/providers/sui/index.mjs +2 -1
  63. package/dist/providers/sui/index.mjs.map +1 -1
  64. package/dist/providers/xrpl/index.d.mts +1 -1
  65. package/dist/providers/xrpl/index.d.ts +1 -1
  66. package/dist/providers/xrpl/index.js +2 -1
  67. package/dist/providers/xrpl/index.js.map +1 -1
  68. package/dist/providers/xrpl/index.mjs +2 -1
  69. package/dist/providers/xrpl/index.mjs.map +1 -1
  70. package/dist/react/index.d.mts +4 -3
  71. package/dist/react/index.d.ts +4 -3
  72. package/dist/react/index.js +153 -1
  73. package/dist/react/index.js.map +1 -1
  74. package/dist/react/index.mjs +153 -1
  75. package/dist/react/index.mjs.map +1 -1
  76. package/dist/react/picker/index.d.mts +1 -1
  77. package/dist/react/picker/index.d.ts +1 -1
  78. package/dist/react/picker/index.js +2 -1
  79. package/dist/react/picker/index.js.map +1 -1
  80. package/dist/react/picker/index.mjs +2 -1
  81. package/dist/react/picker/index.mjs.map +1 -1
  82. package/dist/receipts-Co6C9FPO.d.ts +111 -0
  83. package/dist/receipts-D0zg-8uK.d.mts +111 -0
  84. package/dist/utils/index.d.mts +2 -2
  85. package/dist/utils/index.d.ts +2 -2
  86. package/dist/utils/index.js +2 -1
  87. package/dist/utils/index.js.map +1 -1
  88. package/dist/utils/index.mjs +2 -1
  89. package/dist/utils/index.mjs.map +1 -1
  90. package/dist/{validity-SD6nwegA.d.mts → validity-BcPTzuK8.d.mts} +1 -1
  91. package/dist/{validity-BrvXzCEF.d.ts → validity-CoCrj9pZ.d.ts} +1 -1
  92. package/package.json +1 -1
  93. package/src/backend/facilitator-error.ts +87 -2
  94. package/src/backend/index.ts +445 -41
  95. package/src/chains/index.ts +2 -1
  96. package/src/client/X402Client.ts +5 -0
  97. package/src/fixtures/facilitator-receipts-v1.json +299 -0
  98. package/src/index.ts +18 -0
  99. package/src/receipts.ts +237 -0
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var ed25519 = require('@noble/curves/ed25519');
4
+ var sha256 = require('@noble/hashes/sha256');
5
+ var utils = require('@noble/hashes/utils');
3
6
  var ethers = require('ethers');
4
7
 
5
8
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -8,6 +11,205 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
11
  if (typeof require !== "undefined") return require.apply(this, arguments);
9
12
  throw Error('Dynamic require of "' + x + '" is not supported');
10
13
  });
14
+ var RECEIPT_ISSUER = "https://facilitator.ultravioletadao.xyz";
15
+ var encoder = new TextEncoder();
16
+ var decoder = new TextDecoder("utf-8", { fatal: true });
17
+ var digest = (value) => utils.bytesToHex(sha256.sha256(value));
18
+ function canonicalReceiptJson(value) {
19
+ if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
20
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return String(value);
21
+ if (Array.isArray(value)) return `[${value.map(canonicalReceiptJson).join(",")}]`;
22
+ if (typeof value === "object" && value) {
23
+ const object = value;
24
+ const keys = Object.keys(object).sort();
25
+ if (keys.some((key) => !/^[\x00-\x7f]*$/.test(key))) throw new Error("non-ASCII canonical key");
26
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalReceiptJson(object[key])}`).join(",")}}`;
27
+ }
28
+ throw new Error("unsupported canonical value");
29
+ }
30
+ function receiptCommitment(domain, value) {
31
+ return digest(encoder.encode(`${domain}
32
+ ${canonicalReceiptJson(value)}`));
33
+ }
34
+ function encode64(bytes) {
35
+ if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
36
+ return btoa(Array.from(bytes, (b) => String.fromCharCode(b)).join(""));
37
+ }
38
+ function decode64(value) {
39
+ if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) throw new Error("invalid base64");
40
+ if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(value, "base64"));
41
+ return Uint8Array.from(atob(value), (c) => c.charCodeAt(0));
42
+ }
43
+ function decodeUrl64(value) {
44
+ const padded = value.replace(/-/g, "+").replace(/_/g, "/");
45
+ return decode64(padded + "=".repeat((4 - padded.length % 4) % 4));
46
+ }
47
+ function parseFacilitatorReceipt(value) {
48
+ if (value === null || value === void 0) return null;
49
+ const r = value;
50
+ if (r.schemaVersion !== 1 || !["verified", "pending", "confirmed", "rejected", "unknown"].includes(r.status)) throw new Error("unsupported receipt version or state");
51
+ for (const key of ["receiptId", "issuer", "operation", "network", "scheme", "asset", "amount", "payTo", "paymentRequestHash", "authorizationId"]) {
52
+ if (typeof r[key] !== "string" || !r[key]) throw new Error(`invalid receipt ${key}`);
53
+ }
54
+ if (!Number.isSafeInteger(r.revision) || r.revision < 1 || !r.request || !r.retry) throw new Error("incomplete receipt");
55
+ if (r.requestHashVersion !== "uvd-x402-request-v1" || r.requestHash !== receiptCommitment(r.requestHashVersion, r.request)) throw new Error("receipt request hash mismatch");
56
+ for (const key of ["network", "scheme", "asset", "amount", "payTo", "purchaseId"]) {
57
+ if (r[key] !== r.request[key]) throw new Error("receipt terms mismatch");
58
+ }
59
+ if (!/^[0-9]+$/.test(r.amount)) throw new Error("receipt amount must be an atomic integer string");
60
+ if (r.status === "confirmed" && (r.operation !== "settle" || !r.settlement?.id)) throw new Error("confirmation has no settlement");
61
+ return r;
62
+ }
63
+ function verifyFacilitatorReceipt(receipt, jwks, issuer = RECEIPT_ISSUER) {
64
+ try {
65
+ parseFacilitatorReceipt(receipt);
66
+ if (receipt.issuer !== issuer || receipt.proof?.type !== "jws" || !receipt.proof.jws) return false;
67
+ const parts = receipt.proof.jws.split(".");
68
+ if (parts.length !== 3) return false;
69
+ const [protectedHeader, payload, signature] = parts;
70
+ const header = JSON.parse(decoder.decode(decodeUrl64(protectedHeader)));
71
+ if (header.alg !== "EdDSA" || header.typ !== "uvd-facilitator-receipt+jws") return false;
72
+ const keys = jwks.keys.filter((k) => k.kid === header.kid && k.kty === "OKP" && k.crv === "Ed25519");
73
+ if (keys.length !== 1 || !keys[0].x) return false;
74
+ if (decoder.decode(decodeUrl64(payload)) !== canonicalReceiptJson({ ...receipt, proof: null })) return false;
75
+ return ed25519.ed25519.verify(decodeUrl64(signature), encoder.encode(`${protectedHeader}.${payload}`), decodeUrl64(keys[0].x));
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+ function createPurchaseContext() {
81
+ return { purchaseId: utils.bytesToHex(utils.randomBytes(16)), accessToken: utils.bytesToHex(utils.randomBytes(32)) };
82
+ }
83
+ function purchaseContextHeader(context) {
84
+ return encode64(encoder.encode(canonicalReceiptJson({
85
+ purchaseId: context.purchaseId,
86
+ accessToken: context.accessToken,
87
+ method: context.method,
88
+ url: context.url,
89
+ bodySha256: context.bodySha256
90
+ })));
91
+ }
92
+ function validatePurchaseContext(header, method, url, body) {
93
+ if (!header) return void 0;
94
+ if (header.length > 8192) throw new Error("invalid purchase context");
95
+ const context = JSON.parse(decoder.decode(decode64(header)));
96
+ if (typeof context.purchaseId !== "string" || !context.purchaseId || context.purchaseId.length > 128 || typeof context.accessToken !== "string" || !/^[0-9a-f]{64}$/.test(context.accessToken) || context.method !== method.toUpperCase() || context.url !== new URL(url).toString() || context.bodySha256 !== digest(body)) throw new Error("purchase context does not match the HTTP request");
97
+ return header;
98
+ }
99
+ function paymentResponseHeaders(result) {
100
+ const encoded = encode64(encoder.encode(JSON.stringify(result)));
101
+ if (encoded.length > 32768) throw new Error("payment response too large");
102
+ return {
103
+ "PAYMENT-RESPONSE": encoded,
104
+ "X-PAYMENT-RESPONSE": encoded,
105
+ "Access-Control-Expose-Headers": "PAYMENT-RESPONSE, X-PAYMENT-RESPONSE",
106
+ "Cache-Control": "no-store"
107
+ };
108
+ }
109
+ var LIST_HEADERS = ["Access-Control-Expose-Headers", "Cache-Control"];
110
+ function mergeHeaderList(existing, additions) {
111
+ const name = (entry) => entry.split("=")[0].trim().toLowerCase();
112
+ const kept = (existing || "").split(",").map((entry) => entry.trim()).filter(Boolean);
113
+ const seen = new Set(kept.map(name));
114
+ for (const entry of additions.split(",").map((value) => value.trim()).filter(Boolean)) {
115
+ if (!seen.has(name(entry))) {
116
+ kept.push(entry);
117
+ seen.add(name(entry));
118
+ }
119
+ }
120
+ return kept.join(", ");
121
+ }
122
+ function mergePaymentResponseHeaders(result, current) {
123
+ const headers = paymentResponseHeaders(result);
124
+ for (const name of LIST_HEADERS) headers[name] = mergeHeaderList(current(name), headers[name]);
125
+ return headers;
126
+ }
127
+ function receiptFromResponse(response) {
128
+ const values = [response.headers.get("PAYMENT-RESPONSE"), response.headers.get("X-PAYMENT-RESPONSE")].filter((v) => v !== null);
129
+ if (!values.length) return null;
130
+ if (new Set(values).size !== 1 || values[0].includes(",") || values[0].length > 32768) throw new Error("ambiguous or oversized payment response header");
131
+ return parseFacilitatorReceipt(JSON.parse(decoder.decode(decode64(values[0]))).receipt);
132
+ }
133
+ function receiptFromErrorBody(body) {
134
+ try {
135
+ return parseFacilitatorReceipt(JSON.parse(body).receipt);
136
+ } catch {
137
+ return null;
138
+ }
139
+ }
140
+ async function fetchWithReceipt(fetchClient, url, options) {
141
+ const { context, persist, trustedKeys, issuer = RECEIPT_ISSUER } = options;
142
+ const transport = options.fetchImpl || globalThis.fetch;
143
+ const method = (options.method || "GET").toUpperCase();
144
+ const request = new Request(url, { ...options.init, method });
145
+ const bytes = new Uint8Array(await request.arrayBuffer());
146
+ const bodyHash = digest(bytes);
147
+ if (context.method && (context.method !== method || context.url !== request.url || context.bodySha256 !== bodyHash)) throw new Error("purchase context cannot be reused for another HTTP request");
148
+ context.method = method;
149
+ context.url = request.url;
150
+ context.bodySha256 = bodyHash;
151
+ const init = { ...options.init, method, headers: new Headers(request.headers), body: ["GET", "HEAD"].includes(method) ? void 0 : bytes };
152
+ let receipt = parseFacilitatorReceipt(context.receipt);
153
+ let transportError;
154
+ const persistCopy = async () => {
155
+ await persist(JSON.parse(JSON.stringify(context)));
156
+ };
157
+ const send = async (input, sendOptions) => {
158
+ const headers = new Headers(sendOptions?.headers);
159
+ const paid = headers.get("X-PAYMENT") || headers.get("PAYMENT-SIGNATURE");
160
+ if (paid) {
161
+ const paymentHeaders = {};
162
+ for (const name of ["X-PAYMENT", "PAYMENT-SIGNATURE"]) {
163
+ const value = headers.get(name);
164
+ if (value) paymentHeaders[name] = value;
165
+ }
166
+ if (context.paymentHeaders && JSON.stringify(context.paymentHeaders) !== JSON.stringify(paymentHeaders)) throw new Error("refusing a new authorization for an existing purchase");
167
+ context.paymentHeaders = paymentHeaders;
168
+ headers.set("X-UVD-Purchase", purchaseContextHeader(context));
169
+ await persistCopy();
170
+ }
171
+ try {
172
+ return await transport(input, { ...sendOptions, headers });
173
+ } catch (error) {
174
+ transportError = error;
175
+ throw error;
176
+ }
177
+ };
178
+ try {
179
+ let response;
180
+ if (context.paymentHeaders) {
181
+ const headers = new Headers(init.headers);
182
+ for (const [name, value] of Object.entries(context.paymentHeaders)) headers.set(name, value);
183
+ response = await send(request.url, { ...init, headers });
184
+ } else {
185
+ response = await fetchClient(request.url, { ...options, method, init, fetchImpl: send });
186
+ }
187
+ const incoming = receiptFromResponse(response);
188
+ if (incoming) {
189
+ if (incoming.issuer !== issuer || Object.entries({ purchaseId: context.purchaseId, method, url: context.url, bodySha256: bodyHash }).some(([key, value]) => incoming.request[key] !== value)) throw new Error("receipt does not bind this purchase");
190
+ if (receipt?.operation === "settle" && (incoming.receiptId !== receipt.receiptId || incoming.revision < receipt.revision)) throw new Error("receipt revision conflict");
191
+ if (trustedKeys && !verifyFacilitatorReceipt(incoming, trustedKeys, issuer)) throw new Error("receipt signature verification failed");
192
+ receipt = incoming;
193
+ context.receipt = incoming;
194
+ await persistCopy();
195
+ }
196
+ const proofVerified = !!(receipt && trustedKeys && verifyFacilitatorReceipt(receipt, trustedKeys, issuer));
197
+ if (receipt && trustedKeys && !proofVerified) throw new Error("receipt signature verification failed");
198
+ return { response, receipt, paymentState: receipt ? receipt.status : context.paymentHeaders ? "unknown" : "not_required", context, proofVerified };
199
+ } catch (error) {
200
+ if (!transportError) throw error;
201
+ return { response: null, receipt, paymentState: "unknown", context, proofVerified: false, error };
202
+ }
203
+ }
204
+ async function getFacilitatorReceipt(receiptId, context, options = {}) {
205
+ if (!/^[0-9a-f-]{36}$/.test(receiptId)) throw new Error("invalid receipt ID");
206
+ const issuer = options.issuer || RECEIPT_ISSUER;
207
+ const response = await (options.fetchImpl || globalThis.fetch)(`${issuer}/receipts/${receiptId}`, { headers: { Authorization: `Bearer ${context.accessToken}` } });
208
+ if (!response.ok) throw new Error(`receipt lookup failed: ${response.status}`);
209
+ const receipt = parseFacilitatorReceipt((await response.json()).receipt);
210
+ if (!receipt || receipt.issuer !== issuer || receipt.purchaseId !== context.purchaseId) throw new Error("receipt lookup mismatch");
211
+ return receipt;
212
+ }
11
213
 
12
214
  // src/utils/base64.ts
13
215
  function decodeBase64Utf8(encoded) {
@@ -809,7 +1011,8 @@ var SUPPORTED_CHAINS = {
809
1011
  // Pinned by src/arc-testnet.test.ts.
810
1012
  //
811
1013
  // Mainnet (5042) and testnet (5042002) were verified independently against
812
- // their official RPCs on 2026-09-16. EURC domains checked on 2026-09-17; live payments pending.
1014
+ // their official RPCs on 2026-09-16. EURC domains checked on 2026-09-17; funded EURC payments settled on Arc mainnet on
1015
+ // 2026-09-22 (x402 v1/v2, docs/networks/arc.md); testnet pending.
813
1016
  arc: {
814
1017
  chainId: 5042,
815
1018
  chainIdHex: "0x13b2",
@@ -1524,6 +1727,9 @@ var REPLAYABLE_LEASE_REASONS = [
1524
1727
  ];
1525
1728
  var AMBIGUOUS_LEASE_REASONS = ["forward_failed"];
1526
1729
  var SETTLEMENT_UNCONFIRMED = "settlement_unconfirmed";
1730
+ var AUTHORIZATION_ALREADY_SETTLED = "authorization_already_settled";
1731
+ var AUTHORIZATION_IN_FLIGHT = "authorization_in_flight";
1732
+ var RECEIPT_REQUEST_CONFLICT = "receipt_request_conflict";
1527
1733
  var MAX_RETRY_AFTER_SECONDS = 15;
1528
1734
  var DEFAULT_RETRY_AFTER_SECONDS = 5;
1529
1735
  var DEFAULT_FACILITATOR_RETRIES = 2;
@@ -1584,6 +1790,12 @@ function isDeclaredUnretryable(parsed) {
1584
1790
  function isSettlementUnconfirmed(failure) {
1585
1791
  return failure.errorCode === SETTLEMENT_UNCONFIRMED;
1586
1792
  }
1793
+ function isAuthorizationAlreadyUsed(failure) {
1794
+ return failure.errorCode === AUTHORIZATION_ALREADY_SETTLED || failure.errorCode === RECEIPT_REQUEST_CONFLICT;
1795
+ }
1796
+ function isAuthorizationInFlight(failure) {
1797
+ return failure.errorCode === AUTHORIZATION_IN_FLIGHT;
1798
+ }
1587
1799
  async function readFacilitatorError(response) {
1588
1800
  let body = "";
1589
1801
  try {
@@ -1595,7 +1807,8 @@ async function readFacilitatorError(response) {
1595
1807
  const parsed = parseFacilitatorErrorBody(body);
1596
1808
  const reason = parsed.reason;
1597
1809
  const transportRetryable = status === 429 || status === 502 || status === 503 || status === 504;
1598
- const retryable = transportRetryable && !isDeclaredUnretryable(parsed);
1810
+ const inFlight = status === 409 && parsed.errorCode === AUTHORIZATION_IN_FLIGHT;
1811
+ const retryable = inFlight || transportRetryable && !isDeclaredUnretryable(parsed);
1599
1812
  const retryAfterSeconds = retryable ? parseRetryAfterSeconds(response) ?? DEFAULT_RETRY_AFTER_SECONDS : void 0;
1600
1813
  const safeToReplay = retryable && (status === 429 || status === 503 && isReplayableLeaseReason(reason));
1601
1814
  return {
@@ -1853,7 +2066,7 @@ function buildSettleRequestForVersion(paymentHeader, requirements, version) {
1853
2066
  return buildSettleRequest(paymentHeader, requirements);
1854
2067
  }
1855
2068
  var X402_CORS_HEADERS = {
1856
- "Access-Control-Allow-Headers": "Content-Type, X-PAYMENT, PAYMENT-SIGNATURE, Authorization",
2069
+ "Access-Control-Allow-Headers": "Content-Type, X-PAYMENT, PAYMENT-SIGNATURE, X-UVD-Purchase, Authorization",
1857
2070
  "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE, PAYMENT-RESPONSE, PAYMENT-REQUIRED",
1858
2071
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS"
1859
2072
  };
@@ -1862,7 +2075,8 @@ var X402_HEADER_NAMES = [
1862
2075
  "PAYMENT-SIGNATURE",
1863
2076
  "X-PAYMENT-RESPONSE",
1864
2077
  "PAYMENT-RESPONSE",
1865
- "PAYMENT-REQUIRED"
2078
+ "PAYMENT-REQUIRED",
2079
+ "X-UVD-Purchase"
1866
2080
  ];
1867
2081
  function getCorsHeaders(origin = "*") {
1868
2082
  return {
@@ -1870,6 +2084,78 @@ function getCorsHeaders(origin = "*") {
1870
2084
  ...X402_CORS_HEADERS
1871
2085
  };
1872
2086
  }
2087
+ var IDEMPOTENCY_KEY_HEADER = "Idempotency-Key";
2088
+ var IDEMPOTENT_REPLAYED_HEADER = "Idempotent-Replayed";
2089
+ function createIdempotencyKey() {
2090
+ return `x402-${utils.bytesToHex(utils.randomBytes(32))}`;
2091
+ }
2092
+ function checkIdempotencyKey(key) {
2093
+ if (typeof key !== "string" || !/^[\x21-\x7e]{1,255}$/.test(key) || key.startsWith("receipt:")) {
2094
+ throw new Error('idempotencyKey must be 1-255 visible ASCII characters and must not start with "receipt:"');
2095
+ }
2096
+ return key;
2097
+ }
2098
+ function isReplayed(response) {
2099
+ try {
2100
+ return response?.headers?.get?.(IDEMPOTENT_REPLAYED_HEADER)?.trim().toLowerCase() === "true";
2101
+ } catch {
2102
+ return false;
2103
+ }
2104
+ }
2105
+ function refuseUnboundReplay(result) {
2106
+ if (!result.replayed) return result;
2107
+ const pending = result.receipt?.status === "pending" || result.receipt?.status === "unknown" || result.errorCode === "settlement_in_progress";
2108
+ if (!result.success && !pending) return result;
2109
+ const {
2110
+ transactionHash: _tx,
2111
+ proofOfPayment: _proof,
2112
+ paymentId: _id,
2113
+ transaction: _t,
2114
+ retryAfterSeconds,
2115
+ ...rest
2116
+ } = result;
2117
+ if (result.success) {
2118
+ return {
2119
+ ...rest,
2120
+ success: false,
2121
+ error: AUTHORIZATION_ALREADY_SETTLED,
2122
+ errorCode: AUTHORIZATION_ALREADY_SETTLED,
2123
+ retryable: false,
2124
+ safeToReplay: false
2125
+ };
2126
+ }
2127
+ return {
2128
+ ...rest,
2129
+ success: false,
2130
+ error: AUTHORIZATION_IN_FLIGHT,
2131
+ errorCode: AUTHORIZATION_IN_FLIGHT,
2132
+ retryable: true,
2133
+ safeToReplay: false,
2134
+ retryAfterSeconds: retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS
2135
+ };
2136
+ }
2137
+ function facilitatorHeaders(idempotencyKey, receiptContext) {
2138
+ return {
2139
+ "Content-Type": "application/json",
2140
+ [IDEMPOTENCY_KEY_HEADER]: idempotencyKey,
2141
+ ...receiptContext ? { "X-UVD-Purchase": receiptContext } : {}
2142
+ };
2143
+ }
2144
+ function admittedVerdict(result) {
2145
+ if (result.isValid !== false) return {};
2146
+ if (result.invalidReason === AUTHORIZATION_IN_FLIGHT) {
2147
+ return {
2148
+ errorCode: AUTHORIZATION_IN_FLIGHT,
2149
+ retryable: true,
2150
+ safeToReplay: false,
2151
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
2152
+ };
2153
+ }
2154
+ if (result.invalidReason === AUTHORIZATION_ALREADY_SETTLED) {
2155
+ return { errorCode: AUTHORIZATION_ALREADY_SETTLED, retryable: false, safeToReplay: false };
2156
+ }
2157
+ return {};
2158
+ }
1873
2159
  var FacilitatorClient = class {
1874
2160
  baseUrl;
1875
2161
  timeout;
@@ -1902,11 +2188,19 @@ var FacilitatorClient = class {
1902
2188
  *
1903
2189
  * Call this before providing the paid resource to validate the payment.
1904
2190
  *
2191
+ * An authorization the facilitator already admitted for another request
2192
+ * comes back invalid with `errorCode` {@link AUTHORIZATION_ALREADY_SETTLED}
2193
+ * (do not serve, do not ask for a new signature) or
2194
+ * {@link AUTHORIZATION_IN_FLIGHT} (`retryable`: the same request learns the
2195
+ * verdict later). Neither is a rejected payment: never answer them with 402.
2196
+ *
1905
2197
  * @param paymentHeader - Parsed x402 payment header
1906
2198
  * @param requirements - Payment requirements
2199
+ * @param options - Purchase context and the payment's `idempotencyKey`
1907
2200
  * @returns Verification result
1908
2201
  */
1909
- async verify(paymentHeader, requirements) {
2202
+ async verify(paymentHeader, requirements, options = {}) {
2203
+ const idempotencyKey = checkIdempotencyKey(options.idempotencyKey ?? createIdempotencyKey());
1910
2204
  const body = buildVerifyRequestForVersion(
1911
2205
  paymentHeader,
1912
2206
  requirements,
@@ -1917,7 +2211,7 @@ var FacilitatorClient = class {
1917
2211
  `${this.baseUrl}/verify`,
1918
2212
  {
1919
2213
  method: "POST",
1920
- headers: { "Content-Type": "application/json" },
2214
+ headers: facilitatorHeaders(idempotencyKey, options.receiptContext),
1921
2215
  body: JSON.stringify(body)
1922
2216
  },
1923
2217
  { timeoutMs: this.timeout, retries: this.retries }
@@ -1926,17 +2220,21 @@ var FacilitatorClient = class {
1926
2220
  return {
1927
2221
  isValid: false,
1928
2222
  invalidReason: error.error,
1929
- ...failureFields(error)
2223
+ ...failureFields(error),
2224
+ receipt: receiptFromErrorBody(error.body),
2225
+ idempotencyKey
1930
2226
  };
1931
2227
  }
1932
- return await response.json();
2228
+ const result = await response.json();
2229
+ return { ...result, ...admittedVerdict(result), receipt: parseFacilitatorReceipt(result.receipt), idempotencyKey };
1933
2230
  } catch (error) {
1934
2231
  return {
1935
2232
  isValid: false,
1936
2233
  invalidReason: error instanceof Error ? error.message : "Unknown error",
1937
2234
  retryable: true,
1938
2235
  safeToReplay: false,
1939
- retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
2236
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS,
2237
+ idempotencyKey
1940
2238
  };
1941
2239
  }
1942
2240
  }
@@ -1945,11 +2243,23 @@ var FacilitatorClient = class {
1945
2243
  *
1946
2244
  * Call this after providing the paid resource to execute the on-chain transfer.
1947
2245
  *
2246
+ * Send the `idempotencyKey` the payment was verified with, and the same one
2247
+ * on any retry: it is the binding that earns the original answer back after
2248
+ * a lost response (`replayed: true`). Without it, or with another one, an
2249
+ * authorization already admitted comes back `409`
2250
+ * {@link AUTHORIZATION_ALREADY_SETTLED}, {@link AUTHORIZATION_IN_FLIGHT} or
2251
+ * {@link RECEIPT_REQUEST_CONFLICT} -- the X-PAYMENT was used; do not serve it
2252
+ * again. With no key and no context the call uses a fresh key, so a replay
2253
+ * it receives is refused the same way.
2254
+ *
1948
2255
  * @param paymentHeader - Parsed x402 payment header
1949
2256
  * @param requirements - Payment requirements
2257
+ * @param options - Purchase context and the payment's `idempotencyKey`
1950
2258
  * @returns Settlement result with transaction hash
1951
2259
  */
1952
- async settle(paymentHeader, requirements) {
2260
+ async settle(paymentHeader, requirements, options = {}) {
2261
+ const unbound = options.idempotencyKey === void 0 && !options.receiptContext;
2262
+ const idempotencyKey = checkIdempotencyKey(options.idempotencyKey ?? createIdempotencyKey());
1953
2263
  const body = buildSettleRequestForVersion(
1954
2264
  paymentHeader,
1955
2265
  requirements,
@@ -1961,7 +2271,8 @@ var FacilitatorClient = class {
1961
2271
  `${this.baseUrl}/settle`,
1962
2272
  {
1963
2273
  method: "POST",
1964
- headers: { "Content-Type": "application/json" },
2274
+ // The same init, key included, goes out on every automatic retry.
2275
+ headers: facilitatorHeaders(idempotencyKey, options.receiptContext),
1965
2276
  body: JSON.stringify(body)
1966
2277
  },
1967
2278
  { timeoutMs: settleTimeout, retries: this.retries }
@@ -1970,7 +2281,9 @@ var FacilitatorClient = class {
1970
2281
  return {
1971
2282
  success: false,
1972
2283
  error: error.error,
1973
- ...failureFields(error)
2284
+ ...failureFields(error),
2285
+ receipt: receiptFromErrorBody(error.body),
2286
+ idempotencyKey
1974
2287
  };
1975
2288
  }
1976
2289
  const result = await response.json();
@@ -1980,7 +2293,7 @@ var FacilitatorClient = class {
1980
2293
  "[x402] settle reported success but carried no transaction hash under transaction/transactionHash/transaction_hash \u2014 treat delivery as unconfirmed"
1981
2294
  );
1982
2295
  }
1983
- return {
2296
+ const settled = {
1984
2297
  // Read the facilitator's verdict instead of asserting one.
1985
2298
  //
1986
2299
  // This was the literal `true`, so a settle was reported successful
@@ -2008,15 +2321,24 @@ var FacilitatorClient = class {
2008
2321
  // facilitator returns it, and this method threw it away — so a seller
2009
2322
  // using the SDK end to end could only ever produce provisional anchors.
2010
2323
  proofOfPayment: result.proofOfPayment ?? result.proof_of_payment,
2011
- payer: result.payer
2324
+ payer: result.payer,
2325
+ receipt: parseFacilitatorReceipt(result.receipt),
2326
+ paymentId: result.paymentId,
2327
+ ...result.receipt?.status === "unknown" || result.receipt?.status === "pending" ? { retryable: true, safeToReplay: false } : {},
2328
+ // `202 settlement_in_progress` and friends: a 2xx that names its state.
2329
+ ...!result.success && typeof result.error === "string" && result.error ? { errorCode: result.error } : {},
2330
+ ...isReplayed(response) ? { replayed: true } : {},
2331
+ idempotencyKey
2012
2332
  };
2333
+ return unbound ? refuseUnboundReplay(settled) : settled;
2013
2334
  } catch (error) {
2014
2335
  return {
2015
2336
  success: false,
2016
2337
  error: error instanceof Error ? error.message : "Unknown error",
2017
2338
  retryable: true,
2018
2339
  safeToReplay: false,
2019
- retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS
2340
+ retryAfterSeconds: DEFAULT_RETRY_AFTER_SECONDS,
2341
+ idempotencyKey
2020
2342
  };
2021
2343
  }
2022
2344
  }
@@ -2026,27 +2348,41 @@ var FacilitatorClient = class {
2026
2348
  * Convenience method that verifies first, then settles if valid.
2027
2349
  * Use this for simple payment flows where you don't need custom logic between verify and settle.
2028
2350
  *
2351
+ * Both steps carry ONE `Idempotency-Key` (`options.idempotencyKey`, or a
2352
+ * fresh one reported back as `idempotencyKey`). With a fresh key and no
2353
+ * purchase context, a replay of an earlier settle is not this purchase and
2354
+ * comes back `settled: false` with `errorCode`
2355
+ * {@link AUTHORIZATION_ALREADY_SETTLED}.
2356
+ *
2029
2357
  * @param paymentHeader - Parsed x402 payment header
2030
2358
  * @param requirements - Payment requirements
2359
+ * @param options - Purchase context and the payment's `idempotencyKey`
2031
2360
  * @returns Combined result with verify and settle status
2032
2361
  */
2033
- async verifyAndSettle(paymentHeader, requirements) {
2034
- const verifyResult = await this.verify(paymentHeader, requirements);
2362
+ async verifyAndSettle(paymentHeader, requirements, options = {}) {
2363
+ const unbound = options.idempotencyKey === void 0 && !options.receiptContext;
2364
+ const binding = { ...options, idempotencyKey: checkIdempotencyKey(options.idempotencyKey ?? createIdempotencyKey()) };
2365
+ const { idempotencyKey } = binding;
2366
+ const verifyResult = await this.verify(paymentHeader, requirements, binding);
2035
2367
  if (!verifyResult.isValid) {
2036
2368
  return {
2037
2369
  verified: false,
2038
2370
  settled: false,
2039
2371
  error: verifyResult.invalidReason,
2040
- ...carryFailureFields(verifyResult)
2372
+ ...carryFailureFields(verifyResult),
2373
+ idempotencyKey
2041
2374
  };
2042
2375
  }
2043
- const settleResult = await this.settle(paymentHeader, requirements);
2376
+ const answered = await this.settle(paymentHeader, requirements, binding);
2377
+ const settleResult = unbound ? refuseUnboundReplay(answered) : answered;
2044
2378
  return {
2045
2379
  verified: true,
2046
2380
  settled: settleResult.success,
2047
2381
  transactionHash: settleResult.transactionHash,
2048
2382
  error: settleResult.error,
2049
- ...carryFailureFields(settleResult)
2383
+ ...carryFailureFields(settleResult),
2384
+ ...settleResult.replayed ? { replayed: true } : {},
2385
+ idempotencyKey
2050
2386
  };
2051
2387
  }
2052
2388
  /**
@@ -2434,20 +2770,51 @@ async function resolvePaymentRequirement(payment, requirements, resolver) {
2434
2770
  }
2435
2771
  return { requirement: matches[0] };
2436
2772
  }
2437
- function createVerifiedPaymentState(client, payment, requirements, verifyResult) {
2773
+ function createVerifiedPaymentState(client, payment, requirements, verifyResult, binding, onSettled) {
2438
2774
  let settlePromise = null;
2439
2775
  return {
2440
2776
  payment,
2441
2777
  requirements,
2442
2778
  verifyResult,
2779
+ idempotencyKey: binding.idempotencyKey,
2443
2780
  settle: () => {
2444
2781
  if (!settlePromise) {
2445
- settlePromise = client.settle(payment, requirements);
2782
+ settlePromise = client.settle(payment, requirements, binding).then((answer) => {
2783
+ const result = binding.receiptContext ? answer : refuseUnboundReplay(answer);
2784
+ try {
2785
+ onSettled?.(result);
2786
+ } catch (error) {
2787
+ console.warn("[x402] settled, but the payment response headers could not be attached:", error);
2788
+ }
2789
+ return result;
2790
+ });
2446
2791
  }
2447
2792
  return settlePromise;
2448
2793
  }
2449
2794
  };
2450
2795
  }
2796
+ function propagatedResult(result) {
2797
+ const { idempotencyKey: _key, ...propagated } = result;
2798
+ return propagated;
2799
+ }
2800
+ function buildPaymentConflictResponse(failure) {
2801
+ if (isAuthorizationInFlight(failure)) {
2802
+ const { headers, body } = buildUnavailableResponse("Payment authorization in flight", failure);
2803
+ return { status: 503, headers, body: { ...body, reason: AUTHORIZATION_IN_FLIGHT } };
2804
+ }
2805
+ const used = isAuthorizationAlreadyUsed(failure);
2806
+ if (!used && failure.status !== 409) return null;
2807
+ return {
2808
+ status: 409,
2809
+ headers: {},
2810
+ body: {
2811
+ error: used ? "Payment authorization already used" : "Payment request conflict",
2812
+ reason: failure.errorCode ?? failure.invalidReason ?? failure.error,
2813
+ retryable: false,
2814
+ safeToReplay: false
2815
+ }
2816
+ };
2817
+ }
2451
2818
  function buildUnavailableResponse(message, failure) {
2452
2819
  const seconds = Math.max(1, Math.ceil(failure.retryAfterSeconds ?? DEFAULT_RETRY_AFTER_SECONDS));
2453
2820
  return {
@@ -2464,14 +2831,25 @@ function buildUnavailableResponse(message, failure) {
2464
2831
  };
2465
2832
  }
2466
2833
  function respondUnavailable(res, message, failure) {
2467
- const { status, headers, body } = buildUnavailableResponse(message, failure);
2834
+ respondExpress(res, buildUnavailableResponse(message, failure));
2835
+ }
2836
+ function respondExpress(res, { status, headers, body }) {
2468
2837
  const staged = res.status(status);
2469
- if (typeof staged.set === "function") {
2838
+ if (Object.keys(headers).length > 0 && typeof staged.set === "function") {
2470
2839
  staged.set(headers).json(body);
2471
2840
  return;
2472
2841
  }
2473
2842
  staged.json(body);
2474
2843
  }
2844
+ function setExpressPaymentHeaders(res, result) {
2845
+ if (!result.receipt || !res.set || res.headersSent) return;
2846
+ const current = (name) => {
2847
+ const value = res.getHeader ? res.getHeader(name) : res.get?.(name);
2848
+ if (value === void 0 || value === null) return void 0;
2849
+ return Array.isArray(value) ? value.join(", ") : String(value);
2850
+ };
2851
+ res.set(mergePaymentResponseHeaders(propagatedResult(result), current));
2852
+ }
2475
2853
  function createPaymentMiddleware(getRequirements, options = {}) {
2476
2854
  const client = new FacilitatorClient({
2477
2855
  baseUrl: options.facilitatorUrl || options.baseUrl,
@@ -2489,8 +2867,28 @@ function createPaymentMiddleware(getRequirements, options = {}) {
2489
2867
  }
2490
2868
  const reqOptions = getRequirements(req);
2491
2869
  const requirements = buildPaymentRequirements(reqOptions);
2492
- const verifyResult = await client.verify(payment, requirements);
2870
+ let receiptContext;
2871
+ try {
2872
+ const entry = Object.entries(req.headers).find(([name]) => name.toLowerCase() === "x-uvd-purchase")?.[1];
2873
+ if (entry !== void 0) {
2874
+ if (typeof entry !== "string" || !req.method || !["GET", "HEAD"].includes(req.method.toUpperCase()) && !req.rawBody) throw new Error("receipt context requires method and exact raw body");
2875
+ const actualUrl = new URL(req.originalUrl || req.url || reqOptions.resource, reqOptions.resource).toString();
2876
+ receiptContext = validatePurchaseContext(entry, req.method, actualUrl, req.rawBody || new Uint8Array());
2877
+ requirements.resource = actualUrl;
2878
+ }
2879
+ } catch {
2880
+ res.status(400).json({ error: "receipt_context_mismatch" });
2881
+ return;
2882
+ }
2883
+ const binding = { idempotencyKey: createIdempotencyKey(), receiptContext };
2884
+ const verifyResult = await client.verify(payment, requirements, binding);
2885
+ setExpressPaymentHeaders(res, verifyResult);
2493
2886
  if (!verifyResult.isValid) {
2887
+ const conflict = buildPaymentConflictResponse(verifyResult);
2888
+ if (conflict) {
2889
+ respondExpress(res, conflict);
2890
+ return;
2891
+ }
2494
2892
  if (verifyResult.retryable) {
2495
2893
  respondUnavailable(res, "Payment verification unavailable", verifyResult);
2496
2894
  return;
@@ -2501,10 +2899,22 @@ function createPaymentMiddleware(getRequirements, options = {}) {
2501
2899
  });
2502
2900
  return;
2503
2901
  }
2504
- req.x402 = createVerifiedPaymentState(client, payment, requirements, verifyResult);
2902
+ req.x402 = createVerifiedPaymentState(
2903
+ client,
2904
+ payment,
2905
+ requirements,
2906
+ verifyResult,
2907
+ binding,
2908
+ (result) => setExpressPaymentHeaders(res, result)
2909
+ );
2505
2910
  if (settlementStrategy === "before-handler") {
2506
2911
  const settleResult = await req.x402.settle();
2507
2912
  if (!settleResult.success) {
2913
+ const conflict = buildPaymentConflictResponse(settleResult);
2914
+ if (conflict) {
2915
+ respondExpress(res, conflict);
2916
+ return;
2917
+ }
2508
2918
  if (settleResult.retryable) {
2509
2919
  respondUnavailable(res, "Payment settlement unavailable", settleResult);
2510
2920
  return;
@@ -2527,12 +2937,21 @@ function settlementFailureBody(failure, fallbackReason) {
2527
2937
  };
2528
2938
  }
2529
2939
  function honoUnavailable(c, message, failure) {
2530
- const { status, headers, body } = buildUnavailableResponse(message, failure);
2940
+ return respondHono(c, buildUnavailableResponse(message, failure));
2941
+ }
2942
+ function respondHono(c, { status, headers, body }) {
2531
2943
  for (const [name, value] of Object.entries(headers)) {
2532
2944
  c.header?.(name, value);
2533
2945
  }
2534
2946
  return c.json(body, status);
2535
2947
  }
2948
+ function setHonoPaymentHeaders(c, result) {
2949
+ if (!result.receipt || !c.header || c.finalized) return;
2950
+ const current = (name) => c.res?.headers.get(name) ?? void 0;
2951
+ for (const [name, value] of Object.entries(mergePaymentResponseHeaders(propagatedResult(result), current))) {
2952
+ c.header(name, value);
2953
+ }
2954
+ }
2536
2955
  function createHonoMiddleware(options) {
2537
2956
  const client = new FacilitatorClient({
2538
2957
  baseUrl: options.facilitatorUrl || options.baseUrl,
@@ -2544,7 +2963,7 @@ function createHonoMiddleware(options) {
2544
2963
  throw new Error("At least one accept entry is required");
2545
2964
  }
2546
2965
  return async (c, next) => {
2547
- const paymentHeader = c.req.header("X-PAYMENT") || c.req.header("x-payment");
2966
+ const paymentHeader = c.req.header("PAYMENT-SIGNATURE") || c.req.header("X-PAYMENT") || c.req.header("x-payment");
2548
2967
  const advertisedVersion = resolveAdvertisedVersion(options.accepts, options.x402Version);
2549
2968
  const advertisedRequirements = options.accepts.map(
2550
2969
  (accept) => buildRequirementFromAcceptance(accept, c.req.url, advertisedVersion)
@@ -2575,8 +2994,24 @@ function createHonoMiddleware(options) {
2575
2994
  reason
2576
2995
  }, 402);
2577
2996
  }
2578
- const verifyResult = await client.verify(parsed, requirement);
2997
+ let receiptContext;
2998
+ try {
2999
+ const header = c.req.header("X-UVD-Purchase");
3000
+ if (header) {
3001
+ const method = c.req.method || c.req.raw?.method;
3002
+ if (!method || !["GET", "HEAD"].includes(method) && !c.req.raw) throw new Error("raw request required");
3003
+ const bytes = c.req.raw ? new Uint8Array(await c.req.raw.clone().arrayBuffer()) : new Uint8Array();
3004
+ receiptContext = validatePurchaseContext(header, method, c.req.url, bytes);
3005
+ }
3006
+ } catch {
3007
+ return c.json({ error: "receipt_context_mismatch" }, 400);
3008
+ }
3009
+ const binding = { idempotencyKey: createIdempotencyKey(), receiptContext };
3010
+ const verifyResult = await client.verify(parsed, requirement, binding);
3011
+ setHonoPaymentHeaders(c, verifyResult);
2579
3012
  if (!verifyResult.isValid) {
3013
+ const conflict = buildPaymentConflictResponse(verifyResult);
3014
+ if (conflict) return respondHono(c, conflict);
2580
3015
  if (verifyResult.retryable) {
2581
3016
  return honoUnavailable(c, "Payment verification unavailable", verifyResult);
2582
3017
  }
@@ -2585,11 +3020,20 @@ function createHonoMiddleware(options) {
2585
3020
  reason: verifyResult.invalidReason
2586
3021
  }, 402);
2587
3022
  }
2588
- const verifiedPayment = createVerifiedPaymentState(client, parsed, requirement, verifyResult);
3023
+ const verifiedPayment = createVerifiedPaymentState(
3024
+ client,
3025
+ parsed,
3026
+ requirement,
3027
+ verifyResult,
3028
+ binding,
3029
+ (result) => setHonoPaymentHeaders(c, result)
3030
+ );
2589
3031
  c.set?.("x402", verifiedPayment);
2590
3032
  if (settlementStrategy === "before-handler") {
2591
3033
  const settleResult = await verifiedPayment.settle();
2592
3034
  if (!settleResult.success) {
3035
+ const conflict = buildPaymentConflictResponse(settleResult);
3036
+ if (conflict) return respondHono(c, conflict);
2593
3037
  if (settleResult.retryable) {
2594
3038
  return honoUnavailable(c, "Payment settlement unavailable", settleResult);
2595
3039
  }
@@ -5481,6 +5925,8 @@ var AdvancedEscrowClient = class {
5481
5925
  };
5482
5926
 
5483
5927
  exports.AMBIGUOUS_LEASE_REASONS = AMBIGUOUS_LEASE_REASONS;
5928
+ exports.AUTHORIZATION_ALREADY_SETTLED = AUTHORIZATION_ALREADY_SETTLED;
5929
+ exports.AUTHORIZATION_IN_FLIGHT = AUTHORIZATION_IN_FLIGHT;
5484
5930
  exports.AdvancedEscrowClient = AdvancedEscrowClient;
5485
5931
  exports.BASE_MAINNET_CONTRACTS = BASE_MAINNET_CONTRACTS;
5486
5932
  exports.BazaarClient = BazaarClient;
@@ -5496,11 +5942,15 @@ exports.Erc8004LookupError = Erc8004LookupError;
5496
5942
  exports.EscrowClient = EscrowClient;
5497
5943
  exports.FacilitatorClient = FacilitatorClient;
5498
5944
  exports.HEALTH_FILTERS = HEALTH_FILTERS;
5945
+ exports.IDEMPOTENCY_KEY_HEADER = IDEMPOTENCY_KEY_HEADER;
5946
+ exports.IDEMPOTENT_REPLAYED_HEADER = IDEMPOTENT_REPLAYED_HEADER;
5499
5947
  exports.MAX_RETRY_AFTER_SECONDS = MAX_RETRY_AFTER_SECONDS;
5500
5948
  exports.MAX_SEARCH_LEN = MAX_SEARCH_LEN;
5501
5949
  exports.OPERATOR_ABI = OPERATOR_ABI;
5502
5950
  exports.OPERATOR_ABI_CREATE3 = OPERATOR_ABI_CREATE3;
5503
5951
  exports.PAYMENT_INFO_TYPEHASH = PAYMENT_INFO_TYPEHASH;
5952
+ exports.RECEIPT_ISSUER = RECEIPT_ISSUER;
5953
+ exports.RECEIPT_REQUEST_CONFLICT = RECEIPT_REQUEST_CONFLICT;
5504
5954
  exports.RELAYED_FEEDBACK_NETWORKS = RELAYED_FEEDBACK_NETWORKS;
5505
5955
  exports.REPLAYABLE_LEASE_REASONS = REPLAYABLE_LEASE_REASONS;
5506
5956
  exports.RegistrationPendingError = RegistrationPendingError;
@@ -5514,6 +5964,7 @@ exports.X402_CORS_HEADERS = X402_CORS_HEADERS;
5514
5964
  exports.X402_HEADER_NAMES = X402_HEADER_NAMES;
5515
5965
  exports.ZERO_ADDRESS = ZERO_ADDRESS;
5516
5966
  exports.buildErc8004PaymentRequirements = buildErc8004PaymentRequirements;
5967
+ exports.buildPaymentConflictResponse = buildPaymentConflictResponse;
5517
5968
  exports.buildPaymentRequirements = buildPaymentRequirements;
5518
5969
  exports.buildSettleRequest = buildSettleRequest;
5519
5970
  exports.buildSettleRequestForVersion = buildSettleRequestForVersion;
@@ -5524,33 +5975,50 @@ exports.buildVerifyRequestForVersion = buildVerifyRequestForVersion;
5524
5975
  exports.buildVerifyRequestV2 = buildVerifyRequestV2;
5525
5976
  exports.canRefundEscrow = canRefundEscrow;
5526
5977
  exports.canReleaseEscrow = canReleaseEscrow;
5978
+ exports.canonicalReceiptJson = canonicalReceiptJson;
5527
5979
  exports.carryFailureFields = carryFailureFields;
5528
5980
  exports.create402Response = create402Response;
5529
5981
  exports.createHonoMiddleware = createHonoMiddleware;
5982
+ exports.createIdempotencyKey = createIdempotencyKey;
5530
5983
  exports.createPaymentMiddleware = createPaymentMiddleware;
5984
+ exports.createPurchaseContext = createPurchaseContext;
5531
5985
  exports.epochToDate = epochToDate;
5532
5986
  exports.escrowTimeRemaining = escrowTimeRemaining;
5533
5987
  exports.extractPaymentFromHeaders = extractPaymentFromHeaders;
5534
5988
  exports.facilitatorFetch = facilitatorFetch;
5989
+ exports.fetchWithReceipt = fetchWithReceipt;
5535
5990
  exports.getCorsHeaders = getCorsHeaders;
5536
5991
  exports.getEscrowContractsByChainId = getEscrowContractsByChainId;
5537
5992
  exports.getEscrowSupportedChainIds = getEscrowSupportedChainIds;
5993
+ exports.getFacilitatorReceipt = getFacilitatorReceipt;
5538
5994
  exports.isAlive = isAlive;
5539
5995
  exports.isAmbiguousLeaseReason = isAmbiguousLeaseReason;
5996
+ exports.isAuthorizationAlreadyUsed = isAuthorizationAlreadyUsed;
5997
+ exports.isAuthorizationInFlight = isAuthorizationInFlight;
5540
5998
  exports.isEscrowExpired = isEscrowExpired;
5541
5999
  exports.isEscrowSupportedOnChain = isEscrowSupportedOnChain;
5542
6000
  exports.isRegisterJobTerminal = isRegisterJobTerminal;
5543
6001
  exports.isReplayableLeaseReason = isReplayableLeaseReason;
5544
6002
  exports.isSettlementUnconfirmed = isSettlementUnconfirmed;
6003
+ exports.mergeHeaderList = mergeHeaderList;
6004
+ exports.mergePaymentResponseHeaders = mergePaymentResponseHeaders;
5545
6005
  exports.parseFacilitatorErrorBody = parseFacilitatorErrorBody;
6006
+ exports.parseFacilitatorReceipt = parseFacilitatorReceipt;
5546
6007
  exports.parsePaymentHeader = parsePaymentHeader;
5547
6008
  exports.parseRetryAfterSeconds = parseRetryAfterSeconds;
6009
+ exports.paymentResponseHeaders = paymentResponseHeaders;
6010
+ exports.purchaseContextHeader = purchaseContextHeader;
5548
6011
  exports.readFacilitatorError = readFacilitatorError;
6012
+ exports.receiptCommitment = receiptCommitment;
6013
+ exports.receiptFromErrorBody = receiptFromErrorBody;
6014
+ exports.receiptFromResponse = receiptFromResponse;
5549
6015
  exports.resolveEnvelopeVersion = resolveEnvelopeVersion;
5550
6016
  exports.supportsRelayedFeedback = supportsRelayedFeedback;
5551
6017
  exports.supportsSolanaFeedback = supportsSolanaFeedback;
5552
6018
  exports.toPaymentRequirementsV2 = toPaymentRequirementsV2;
5553
6019
  exports.toResourceInfoV2 = toResourceInfoV2;
6020
+ exports.validatePurchaseContext = validatePurchaseContext;
6021
+ exports.verifyFacilitatorReceipt = verifyFacilitatorReceipt;
5554
6022
  exports.wireNetwork = wireNetwork;
5555
6023
  //# sourceMappingURL=index.js.map
5556
6024
  //# sourceMappingURL=index.js.map