@piprail/sdk 2.13.0 → 2.14.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 (30) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/dist/{algorand-AA3WXKW4.js → algorand-6J3IABVF.js} +12 -11
  3. package/dist/{algorand-FCEECDG6.cjs → algorand-QU6G2DQZ.cjs} +43 -42
  4. package/dist/{aptos-LY67Q6QF.js → aptos-DHOMTBLZ.js} +11 -10
  5. package/dist/{aptos-GHJPO6JJ.cjs → aptos-LFTQGBBK.cjs} +41 -40
  6. package/dist/{chunk-MWBT7MCE.cjs → chunk-GYM46G5L.cjs} +22 -4
  7. package/dist/{chunk-SC2ZYDHD.js → chunk-PAMKCWVW.js} +22 -4
  8. package/dist/index.cjs +505 -234
  9. package/dist/index.d.cts +281 -12
  10. package/dist/index.d.ts +281 -12
  11. package/dist/index.js +302 -31
  12. package/dist/{ledger-mF_SoiDB.d.ts → ledger-uFtXlIHY.d.cts} +31 -1
  13. package/dist/{ledger-mF_SoiDB.d.cts → ledger-uFtXlIHY.d.ts} +31 -1
  14. package/dist/{near-FZBUICCS.js → near-5PXTVQ47.js} +14 -5
  15. package/dist/{near-6KAQVVG2.cjs → near-YNNK7RW7.cjs} +39 -30
  16. package/dist/node.d.cts +2 -2
  17. package/dist/node.d.ts +2 -2
  18. package/dist/{solana-ELUWO6N5.js → solana-HITVI3HF.js} +22 -7
  19. package/dist/{solana-MYF4HBO4.cjs → solana-N3UCNCYE.cjs} +54 -39
  20. package/dist/{stellar-ASP2THL2.js → stellar-2QT6YYKN.js} +4 -4
  21. package/dist/{stellar-CRWBSX4E.cjs → stellar-Y3SQN7S5.cjs} +23 -23
  22. package/dist/{sui-Y4RLKKE2.cjs → sui-4AL4E6XU.cjs} +35 -27
  23. package/dist/{sui-FZIKZNVI.js → sui-FV5L6WF5.js} +20 -12
  24. package/dist/{ton-7GKCTC5H.js → ton-5FWDQ4QR.js} +18 -7
  25. package/dist/{ton-AOR3EURW.cjs → ton-5HDVOTMR.cjs} +33 -22
  26. package/dist/{tron-BMCWN5SS.js → tron-AZDY7BMQ.js} +10 -10
  27. package/dist/{tron-OMXB6EW2.cjs → tron-TX2B4N2A.cjs} +39 -39
  28. package/dist/{xrpl-Y6SQNYLC.cjs → xrpl-5TYDLQFS.cjs} +31 -31
  29. package/dist/{xrpl-DD7TJL5L.js → xrpl-UJL5J7CY.js} +13 -13
  30. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  parseUnits,
32
32
  rejectForeignToken,
33
33
  toInsufficientFundsError
34
- } from "./chunk-SC2ZYDHD.js";
34
+ } from "./chunk-PAMKCWVW.js";
35
35
 
36
36
  // src/drivers/registry.ts
37
37
  var byFamily = /* @__PURE__ */ new Map();
@@ -1780,6 +1780,37 @@ function buildReceiptExtension(bundle) {
1780
1780
  if (bundle.attestation) info.receipt = bundle.attestation;
1781
1781
  return { [EXT_OFFER_RECEIPT]: { info } };
1782
1782
  }
1783
+ var EXT_PAYMENT_IDENTIFIER = "payment-identifier";
1784
+ var PAYMENT_ID_MIN = 16;
1785
+ var PAYMENT_ID_MAX = 128;
1786
+ var PAYMENT_ID_RE = /^[A-Za-z0-9_-]+$/;
1787
+ function buildPaymentIdentifierAdvertisement() {
1788
+ return {
1789
+ [EXT_PAYMENT_IDENTIFIER]: {
1790
+ info: { required: false },
1791
+ schema: { properties: { id: { type: "string", minLength: PAYMENT_ID_MIN, maxLength: PAYMENT_ID_MAX } } }
1792
+ }
1793
+ };
1794
+ }
1795
+ function readPaymentIdentifier(payload) {
1796
+ if (typeof payload !== "object" || payload === null) return null;
1797
+ const ext = payload.extensions;
1798
+ if (typeof ext !== "object" || ext === null) return null;
1799
+ const block = ext[EXT_PAYMENT_IDENTIFIER];
1800
+ if (typeof block !== "object" || block === null) return null;
1801
+ const info = block.info;
1802
+ if (typeof info !== "object" || info === null) return null;
1803
+ const id = info.id;
1804
+ if (id === void 0) return null;
1805
+ if (typeof id !== "string") return { invalid: "payment-identifier id must be a string" };
1806
+ if (id.length < PAYMENT_ID_MIN || id.length > PAYMENT_ID_MAX) {
1807
+ return { invalid: `payment-identifier id must be ${PAYMENT_ID_MIN}\u2013${PAYMENT_ID_MAX} chars (got ${id.length})` };
1808
+ }
1809
+ if (!PAYMENT_ID_RE.test(id)) {
1810
+ return { invalid: "payment-identifier id must match [A-Za-z0-9_-]" };
1811
+ }
1812
+ return id;
1813
+ }
1783
1814
  function buildSignatureHeader(signature) {
1784
1815
  return toBase64Json(signature);
1785
1816
  }
@@ -1806,7 +1837,10 @@ function parseReceipt(response) {
1806
1837
  const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
1807
1838
  if (!headerValue) return null;
1808
1839
  const parsed = fromBase64Json(headerValue);
1809
- return isValidReceipt(parsed) ? parsed : null;
1840
+ if (!isValidReceipt(parsed)) return null;
1841
+ const r = parsed;
1842
+ if (typeof r.transaction !== "string" && typeof r.txHash === "string") r.transaction = r.txHash;
1843
+ return r;
1810
1844
  }
1811
1845
  function parseReceiptExtension(response) {
1812
1846
  const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
@@ -1836,7 +1870,8 @@ function parseSettleResponse(response) {
1836
1870
  if (!parsed || typeof parsed !== "object" || typeof parsed.success !== "boolean") return null;
1837
1871
  return {
1838
1872
  success: parsed.success,
1839
- ...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : {},
1873
+ // Tolerate the legacy v1 `txHash` alias for `transaction` (mirrors isValidReceipt/parseReceipt).
1874
+ ...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : typeof parsed.txHash === "string" ? { transaction: parsed.txHash } : {},
1840
1875
  ...typeof parsed.network === "string" ? { network: parsed.network } : {},
1841
1876
  ...typeof parsed.payer === "string" ? { payer: parsed.payer } : {},
1842
1877
  ...typeof parsed.errorReason === "string" ? { errorReason: parsed.errorReason } : {},
@@ -1855,6 +1890,14 @@ function parseSignatureObject(parsed) {
1855
1890
  if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
1856
1891
  return null;
1857
1892
  }
1893
+ if (!accepted) {
1894
+ const synthesized = {
1895
+ scheme: "onchain-proof",
1896
+ ...typeof v.network === "string" ? { network: v.network } : {},
1897
+ ...typeof v.asset === "string" ? { asset: v.asset } : {}
1898
+ };
1899
+ return { ...v, accepted: synthesized, payload };
1900
+ }
1858
1901
  return parsed;
1859
1902
  }
1860
1903
  function parseSignatureHeader(value) {
@@ -1994,7 +2037,11 @@ var evmDriver = {
1994
2037
  resolve(opts) {
1995
2038
  if (typeof opts.chain === "string" && /^(solana|ton|stellar)/.test(opts.chain)) return null;
1996
2039
  if (typeof opts.chain === "string") {
1997
- return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
2040
+ try {
2041
+ return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
2042
+ } catch (err) {
2043
+ throw new UnsupportedNetworkError(err instanceof Error ? err.message : String(err), { cause: err });
2044
+ }
1998
2045
  }
1999
2046
  let resolved;
2000
2047
  try {
@@ -2039,8 +2086,13 @@ function makeEvmNetwork(resolved) {
2039
2086
  `chain ${network} is EVM; a custom token must be { address, decimals }.`
2040
2087
  );
2041
2088
  }
2089
+ if (!isAddress(token.address)) {
2090
+ throw new WrongFamilyError(
2091
+ `chain ${network} is EVM, but token address "${token.address}" is not a valid 0x address.`
2092
+ );
2093
+ }
2042
2094
  return {
2043
- asset: token.address,
2095
+ asset: getAddress5(token.address),
2044
2096
  decimals: token.decimals,
2045
2097
  ...token.symbol ? { symbol: token.symbol } : {}
2046
2098
  };
@@ -2121,9 +2173,9 @@ function makeEvmNetwork(resolved) {
2121
2173
  },
2122
2174
  async estimateCost(accept) {
2123
2175
  const { decimals, symbol } = resolved.chain.nativeCurrency;
2124
- if (accept.scheme === "exact") {
2125
- const m = accept.extra.assetTransferMethod;
2126
- const permit2 = m === "permit2" || m === "permit2-exact";
2176
+ if (accept.scheme === "exact" || accept.scheme === "upto") {
2177
+ const m = accept.extra?.assetTransferMethod;
2178
+ const permit2 = m === "permit2" || m === "permit2-exact" || m === "permit2-upto";
2127
2179
  return nativeCost({
2128
2180
  symbol,
2129
2181
  decimals,
@@ -2329,7 +2381,7 @@ var loaders = {
2329
2381
  solana: async () => {
2330
2382
  let mod;
2331
2383
  try {
2332
- mod = await import("./solana-ELUWO6N5.js");
2384
+ mod = await import("./solana-HITVI3HF.js");
2333
2385
  } catch (cause) {
2334
2386
  throw new MissingDriverError(
2335
2387
  `Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
@@ -2341,7 +2393,7 @@ var loaders = {
2341
2393
  ton: async () => {
2342
2394
  let mod;
2343
2395
  try {
2344
- mod = await import("./ton-7GKCTC5H.js");
2396
+ mod = await import("./ton-5FWDQ4QR.js");
2345
2397
  } catch (cause) {
2346
2398
  throw new MissingDriverError(
2347
2399
  `TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
@@ -2353,7 +2405,7 @@ var loaders = {
2353
2405
  stellar: async () => {
2354
2406
  let mod;
2355
2407
  try {
2356
- mod = await import("./stellar-ASP2THL2.js");
2408
+ mod = await import("./stellar-2QT6YYKN.js");
2357
2409
  } catch (cause) {
2358
2410
  throw new MissingDriverError(
2359
2411
  `Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
@@ -2365,7 +2417,7 @@ var loaders = {
2365
2417
  xrpl: async () => {
2366
2418
  let mod;
2367
2419
  try {
2368
- mod = await import("./xrpl-DD7TJL5L.js");
2420
+ mod = await import("./xrpl-UJL5J7CY.js");
2369
2421
  } catch (cause) {
2370
2422
  throw new MissingDriverError(
2371
2423
  `XRPL selected, but its package isn't installed. Run: npm install xrpl`,
@@ -2377,7 +2429,7 @@ var loaders = {
2377
2429
  tron: async () => {
2378
2430
  let mod;
2379
2431
  try {
2380
- mod = await import("./tron-BMCWN5SS.js");
2432
+ mod = await import("./tron-AZDY7BMQ.js");
2381
2433
  } catch (cause) {
2382
2434
  throw new MissingDriverError(
2383
2435
  `Tron selected, but its package isn't installed. Run: npm install tronweb`,
@@ -2389,7 +2441,7 @@ var loaders = {
2389
2441
  sui: async () => {
2390
2442
  let mod;
2391
2443
  try {
2392
- mod = await import("./sui-FZIKZNVI.js");
2444
+ mod = await import("./sui-FV5L6WF5.js");
2393
2445
  } catch (cause) {
2394
2446
  throw new MissingDriverError(
2395
2447
  `Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
@@ -2401,7 +2453,7 @@ var loaders = {
2401
2453
  near: async () => {
2402
2454
  let mod;
2403
2455
  try {
2404
- mod = await import("./near-FZBUICCS.js");
2456
+ mod = await import("./near-5PXTVQ47.js");
2405
2457
  } catch (cause) {
2406
2458
  throw new MissingDriverError(
2407
2459
  `NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
@@ -2413,7 +2465,7 @@ var loaders = {
2413
2465
  aptos: async () => {
2414
2466
  let mod;
2415
2467
  try {
2416
- mod = await import("./aptos-LY67Q6QF.js");
2468
+ mod = await import("./aptos-DHOMTBLZ.js");
2417
2469
  } catch (cause) {
2418
2470
  throw new MissingDriverError(
2419
2471
  `Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
@@ -2425,7 +2477,7 @@ var loaders = {
2425
2477
  algorand: async () => {
2426
2478
  let mod;
2427
2479
  try {
2428
- mod = await import("./algorand-AA3WXKW4.js");
2480
+ mod = await import("./algorand-6J3IABVF.js");
2429
2481
  } catch (cause) {
2430
2482
  throw new MissingDriverError(
2431
2483
  `Algorand selected, but its package isn't installed. Run: npm install algosdk`,
@@ -3449,6 +3501,24 @@ var SpendLedger = class {
3449
3501
  }
3450
3502
  };
3451
3503
 
3504
+ // src/util/exactRecovery.ts
3505
+ function exactSettleCheckHint(family, payerFrom, nonce) {
3506
+ switch (family) {
3507
+ case "evm":
3508
+ return `the EIP-3009 \`authorizationState(${payerFrom}, ${nonce})\` (or, on the Permit2 method, the Permit2 nonce bitmap)`;
3509
+ case "solana":
3510
+ return `the buyer's transaction signature (a duplicate signature is the chain's own replay guard; plus the SPL-Memo nonce when present)`;
3511
+ case "algorand":
3512
+ return `the atomic group / transaction id`;
3513
+ case "aptos":
3514
+ return `the sender's account sequence number`;
3515
+ case "near":
3516
+ return `the access-key nonce (\`${nonce}\`)`;
3517
+ default:
3518
+ return `the single-use marker (\`ref=${nonce}\`)`;
3519
+ }
3520
+ }
3521
+
3452
3522
  // src/client.ts
3453
3523
  var DEFAULT_SCHEMES = ["onchain-proof"];
3454
3524
  var RECIPIENT_FIX = {
@@ -4014,7 +4084,8 @@ var PipRailClient = class {
4014
4084
  * before publishing, so retry with a brief backoff if a fresh listing is missing.
4015
4085
  * - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
4016
4086
  * `onchain-proof` rails by default, and standard `exact` rails too once you opt in
4017
- * with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand).
4087
+ * with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
4088
+ * + Aptos + NEAR).
4018
4089
  */
4019
4090
  async discover(opts = {}) {
4020
4091
  const found = await searchOpenIndexes({
@@ -4222,7 +4293,7 @@ var PipRailClient = class {
4222
4293
  );
4223
4294
  if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
4224
4295
  throw new UnsupportedSchemeError(
4225
- `This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand + NEAR today), and no 'onchain-proof' rail was offered.`
4296
+ `This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand, Aptos + NEAR today), and no 'onchain-proof' rail was offered.`
4226
4297
  );
4227
4298
  }
4228
4299
  if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
@@ -4275,7 +4346,15 @@ var PipRailClient = class {
4275
4346
  if (schemes.includes("exact")) {
4276
4347
  out.push(
4277
4348
  ...challenge.accepts.filter(
4278
- (a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" && net.describeAsset(a.asset) != null && // a foreign rail's maxTimeoutSeconds must be a usable positive integer, or
4349
+ (a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" && // `native` is never `exact`-payable on ANY family (exact = an EIP-3009/Permit2-style
4350
+ // signed-authorization scheme a native coin can't support; every driver's payExact
4351
+ // throws/returns-null for it). describeAsset('native') IS non-null (onchain-proof needs
4352
+ // it), so without this guard a malformed 402 advertising a native `exact` rail would be
4353
+ // gathered, planned `payable`, even chosen by autoRoute — then throw at pay time.
4354
+ a.asset !== "native" && // the exact pay path (payExact → driver) reads `extra.assetTransferMethod`; a malformed
4355
+ // 402 offering an exact rail for a RECOGNISED token but omitting `extra` would otherwise
4356
+ // be planned payable then throw a raw TypeError mid-pay. Require it at gather time.
4357
+ typeof a.extra?.assetTransferMethod === "string" && net.describeAsset(a.asset) != null && // a foreign rail's maxTimeoutSeconds must be a usable positive integer, or
4279
4358
  // signing it would build a NaN/garbage validBefore — drop it silently
4280
4359
  // (symmetric with an unrecognised token) rather than leak a raw SyntaxError.
4281
4360
  Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
@@ -4285,7 +4364,8 @@ var PipRailClient = class {
4285
4364
  if (schemes.includes("upto")) {
4286
4365
  out.push(
4287
4366
  ...challenge.accepts.filter(
4288
- (a) => a.scheme === "upto" && this.supportsNetwork(net, a.network) && typeof net.payUpto === "function" && net.describeAsset(a.asset) != null && typeof a.extra?.facilitatorAddress === "string" && a.extra.facilitatorAddress.length > 0 && Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
4367
+ (a) => a.scheme === "upto" && this.supportsNetwork(net, a.network) && typeof net.payUpto === "function" && a.asset !== "native" && // native is not upto-payable either (same reason as exact)
4368
+ net.describeAsset(a.asset) != null && typeof a.extra?.facilitatorAddress === "string" && a.extra.facilitatorAddress.length > 0 && Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
4289
4369
  )
4290
4370
  );
4291
4371
  }
@@ -4760,7 +4840,7 @@ var PipRailClient = class {
4760
4840
  async payExactRail(net, wallet, accept, url, init, quote) {
4761
4841
  if (!net.payExact) {
4762
4842
  throw new UnsupportedSchemeError(
4763
- `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana, Algorand + NEAR today).`
4843
+ `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana, Algorand, Aptos + NEAR today).`
4764
4844
  );
4765
4845
  }
4766
4846
  throwIfAborted(init?.signal);
@@ -4793,7 +4873,7 @@ var PipRailClient = class {
4793
4873
  response = await fetch(url, { ...init ?? {}, headers, signal });
4794
4874
  } catch (err) {
4795
4875
  throw new PaymentTimeoutError(
4796
- `exact: no response after submitting the authorization (nonce=${nonce}) to ${hostOf2(url)}. The facilitator may have already settled it \u2014 verify on-chain with authorizationState(${payerFrom}, ${nonce}) before re-presenting; do NOT re-pay.`,
4876
+ `exact: no response after submitting the authorization (nonce=${nonce}) to ${hostOf2(url)}. The facilitator may have already settled it \u2014 verify on-chain via ${exactSettleCheckHint(net.family, payerFrom, nonce)} before re-presenting the SAME signed authorization; do NOT re-pay.`,
4797
4877
  { cause: err, ref: nonce }
4798
4878
  );
4799
4879
  } finally {
@@ -4809,7 +4889,7 @@ var PipRailClient = class {
4809
4889
  const receipt = parseReceipt(response);
4810
4890
  this.captureReceipt(response, url);
4811
4891
  this.safeEmit({ kind: "payment-settled", receipt, ...settle ? { settle } : {} });
4812
- const ref = settle?.transaction || receipt?.transaction || `eip3009-nonce:${nonce}`;
4892
+ const ref = settle?.transaction || receipt?.transaction || `${net.family === "evm" ? "eip3009" : net.family}-nonce:${nonce}`;
4813
4893
  this.recordSpend(quote, ref);
4814
4894
  return response;
4815
4895
  }
@@ -4828,7 +4908,7 @@ var PipRailClient = class {
4828
4908
  ...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
4829
4909
  });
4830
4910
  throw new MaxRetriesExceededError(
4831
- `exact: server still returned 402 after submitting the signed authorization (nonce=${nonce}). Last rejection: ${why}. Re-present the SAME authorization \u2014 do NOT re-sign a fresh nonce; verify authorizationState(${payerFrom}, ${nonce}) first. ref=${nonce}.`,
4911
+ `exact: server still returned 402 after submitting the signed authorization (nonce=${nonce}). Last rejection: ${why}. Re-present the SAME authorization \u2014 do NOT re-sign a fresh nonce; verify on-chain via ${exactSettleCheckHint(net.family, payerFrom, nonce)} first. ref=${nonce}.`,
4832
4912
  { ref: nonce }
4833
4913
  );
4834
4914
  }
@@ -5499,8 +5579,8 @@ A 402 may offer up to three rails; you don't choose per payment \u2014 the clien
5499
5579
  (the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
5500
5580
  - exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
5501
5581
  (e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
5502
- works on EVM, Solana + Algorand, and the on-chain method (EIP-3009 / Permit2 / SVM / Algorand
5503
- fee-pooled group) is picked automatically.
5582
+ works on EVM, Solana, Algorand, Aptos + NEAR, and the on-chain method (EIP-3009 / Permit2 / SVM /
5583
+ Algorand fee-pooled group / Aptos fee-payer / NEAR SignedDelegateAction) is picked automatically.
5504
5584
  - upto (the metered/variable x402 rail, opt-in, EVM): the amount you see is a MAXIMUM \u2014 you sign
5505
5585
  a ceiling, the server meters real usage and settles the ACTUAL (<= the max). BUDGET AGAINST THE MAX:
5506
5586
  the plan/policy treat the ceiling as the spend (a server may charge up to it), so a payable plan
@@ -6045,6 +6125,23 @@ function buildWellKnownX402(input) {
6045
6125
  ...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
6046
6126
  };
6047
6127
  }
6128
+ function buildWellKnownX402Manifest(input) {
6129
+ return {
6130
+ x402Version: 2,
6131
+ lastUpdated: input.lastUpdated ?? Math.floor(Date.now() / 1e3),
6132
+ items: input.resources.map((r) => ({
6133
+ resource: {
6134
+ url: r.url,
6135
+ ...r.description ? { description: r.description } : {},
6136
+ ...r.mimeType ? { mimeType: r.mimeType } : {}
6137
+ },
6138
+ type: "http",
6139
+ accepts: r.accepts,
6140
+ input: { method: (r.method ?? "GET").toUpperCase() },
6141
+ ...r.mimeType ? { output: { mimeType: r.mimeType } } : {}
6142
+ }))
6143
+ };
6144
+ }
6048
6145
  function buildX402DnsTxt(input) {
6049
6146
  const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
6050
6147
  return {
@@ -6775,7 +6872,7 @@ function createPaymentGate(options) {
6775
6872
  if (hasCustomStore) {
6776
6873
  return options.isUsed ? Boolean(await options.isUsed(ref)) : false;
6777
6874
  }
6778
- const key = ref.toLowerCase();
6875
+ const key = ref.startsWith("pid:") ? ref : ref.toLowerCase();
6779
6876
  const now = Date.now();
6780
6877
  pruneUsed(now);
6781
6878
  if (localUsed.has(key)) return true;
@@ -6787,7 +6884,7 @@ function createPaymentGate(options) {
6787
6884
  if (ok && options.markUsed) await options.markUsed(ref);
6788
6885
  return;
6789
6886
  }
6790
- if (!ok) localUsed.delete(ref.toLowerCase());
6887
+ if (!ok) localUsed.delete(ref.startsWith("pid:") ? ref : ref.toLowerCase());
6791
6888
  }
6792
6889
  function buildAccept(s, nonce) {
6793
6890
  return {
@@ -6860,6 +6957,7 @@ function createPaymentGate(options) {
6860
6957
  const specs = await ready();
6861
6958
  const nonce = genNonce();
6862
6959
  const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
6960
+ const paymentIdAd = options.paymentIdentifier ? buildPaymentIdentifierAdvertisement() : void 0;
6863
6961
  const accepts = buildAccepts(specs, nonce);
6864
6962
  const endpointInfo = buildEndpointInfo({
6865
6963
  ...options.description ? { description: options.description } : {},
@@ -6877,11 +6975,13 @@ function createPaymentGate(options) {
6877
6975
  const bodyPiprail = { ...selfDescribe ?? {}, ...rejectionPiprail };
6878
6976
  const bodyExtensions = {
6879
6977
  ...bazaar,
6978
+ ...paymentIdAd,
6880
6979
  ...rejectionExt,
6881
6980
  ...Object.keys(bodyPiprail).length > 0 ? { piprail: bodyPiprail } : {}
6882
6981
  };
6883
6982
  const headerExtensions = {
6884
6983
  ...bazaar,
6984
+ ...paymentIdAd,
6885
6985
  ...Object.keys(rejectionPiprail).length > 0 ? { piprail: rejectionPiprail } : {}
6886
6986
  };
6887
6987
  const challenge2 = {
@@ -7091,7 +7191,17 @@ function createPaymentGate(options) {
7091
7191
  await settleTx(ref, false);
7092
7192
  return rejection(result.error, result.detail);
7093
7193
  }
7094
- await settleTx(ref, true);
7194
+ const verified = result.receipt.transaction;
7195
+ if (verified && verified !== ref) {
7196
+ if (await claimTx(verified)) {
7197
+ await settleTx(ref, false);
7198
+ return rejection("tx_already_used", `Payment ${verified} was already redeemed.`);
7199
+ }
7200
+ await settleTx(ref, false);
7201
+ await settleTx(verified, true);
7202
+ } else {
7203
+ await settleTx(ref, true);
7204
+ }
7095
7205
  await deliverOnPaid(spec, result.receipt);
7096
7206
  return await buildPaidResult(spec, result.receipt, sig.payload.nonce);
7097
7207
  }
@@ -7297,7 +7407,7 @@ function createPaymentGate(options) {
7297
7407
  if (result.kind === "invalid") await deliverOnFailed(result);
7298
7408
  return result;
7299
7409
  }
7300
- async function resolveVerdictObject(obj) {
7410
+ async function routeVerdictObject(obj) {
7301
7411
  if (obj === void 0 || obj === null) return asChallenge();
7302
7412
  const sig = parseSignatureObject(obj);
7303
7413
  if (sig && sig.accepted && typeof sig.accepted.network === "string" && typeof sig.accepted.asset === "string") {
@@ -7309,6 +7419,44 @@ function createPaymentGate(options) {
7309
7419
  if (exact) return verifyExact(exact);
7310
7420
  return asChallenge();
7311
7421
  }
7422
+ function echoPaymentIdentifier(result, id) {
7423
+ try {
7424
+ const decoded = decodeBase64Json(result.receiptHeader);
7425
+ if (!decoded) return result;
7426
+ const { extensions: existing, ...receiptOnly } = decoded;
7427
+ const merged = {
7428
+ ...existing ?? {},
7429
+ [EXT_PAYMENT_IDENTIFIER]: { info: { required: false, id } }
7430
+ };
7431
+ return { ...result, receiptHeader: buildReceiptHeader(receiptOnly, merged) };
7432
+ } catch {
7433
+ return result;
7434
+ }
7435
+ }
7436
+ async function resolveVerdictObject(obj) {
7437
+ if (!options.paymentIdentifier) return routeVerdictObject(obj);
7438
+ const id = readPaymentIdentifier(obj);
7439
+ if (id !== null && typeof id === "object") {
7440
+ return rejection("signature_invalid", `payment-identifier: ${id.invalid}.`);
7441
+ }
7442
+ if (id === null) return routeVerdictObject(obj);
7443
+ const idKey = "pid:" + id;
7444
+ if (await claimTx(idKey)) {
7445
+ return rejection(
7446
+ "tx_already_used",
7447
+ `Idempotency id "${id}" is already bound to a settled payment; use a fresh id for a new payment.`
7448
+ );
7449
+ }
7450
+ let result;
7451
+ try {
7452
+ result = await routeVerdictObject(obj);
7453
+ } catch (err) {
7454
+ await settleTx(idKey, false);
7455
+ throw err;
7456
+ }
7457
+ await settleTx(idKey, result.kind === "paid");
7458
+ return result.kind === "paid" ? echoPaymentIdentifier(result, id) : result;
7459
+ }
7312
7460
  return { challenge, verify, verifyObject, describe, landingPage };
7313
7461
  }
7314
7462
  function requirePayment(options) {
@@ -7708,6 +7856,115 @@ function resourceUrlFromMessage(message) {
7708
7856
  }
7709
7857
  return "";
7710
7858
  }
7859
+
7860
+ // src/transports/mcp-types.ts
7861
+ var MCP_PAYMENT_META_KEY = "x402/payment";
7862
+ var MCP_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
7863
+
7864
+ // src/transports/mcp.ts
7865
+ function toMcpPaymentRequired(challenge) {
7866
+ const text = JSON.stringify(challenge);
7867
+ return {
7868
+ isError: true,
7869
+ structuredContent: challenge,
7870
+ content: [{ type: "text", text }]
7871
+ };
7872
+ }
7873
+ function toMcpPaymentResponse(content, receipt) {
7874
+ return {
7875
+ content,
7876
+ _meta: {
7877
+ [MCP_PAYMENT_RESPONSE_META_KEY]: {
7878
+ success: true,
7879
+ transaction: receipt.transaction,
7880
+ network: receipt.network,
7881
+ payer: receipt.payer
7882
+ }
7883
+ }
7884
+ };
7885
+ }
7886
+ function fromMcpPayment(params) {
7887
+ const meta = params?._meta?.[MCP_PAYMENT_META_KEY];
7888
+ return meta == null ? null : meta;
7889
+ }
7890
+ function fromMcpPaymentRequired(result) {
7891
+ if (!result || result.isError !== true) return null;
7892
+ const sc = result.structuredContent;
7893
+ if (sc && typeof sc === "object" && typeof sc.x402Version === "number") {
7894
+ return sc;
7895
+ }
7896
+ const text = result.content?.[0]?.text;
7897
+ if (typeof text === "string") {
7898
+ try {
7899
+ const parsed = JSON.parse(text);
7900
+ if (parsed && typeof parsed === "object" && typeof parsed.x402Version === "number") {
7901
+ return parsed;
7902
+ }
7903
+ } catch {
7904
+ }
7905
+ }
7906
+ return null;
7907
+ }
7908
+ function isMcpPaymentRequired(result) {
7909
+ return fromMcpPaymentRequired(result) != null;
7910
+ }
7911
+ function fromMcpPaymentResponse(result) {
7912
+ const meta = result?._meta?.[MCP_PAYMENT_RESPONSE_META_KEY];
7913
+ if (!meta || typeof meta !== "object") return null;
7914
+ return meta;
7915
+ }
7916
+ function buildMcpPaymentMeta(input) {
7917
+ return {
7918
+ [MCP_PAYMENT_META_KEY]: {
7919
+ x402Version: input.x402Version ?? 2,
7920
+ ...input.resource ? { resource: input.resource } : {},
7921
+ accepted: input.accepted,
7922
+ payload: input.payload
7923
+ }
7924
+ };
7925
+ }
7926
+ function createMcpPaymentTool(options) {
7927
+ const gate = options.gate ?? createPaymentGate(options);
7928
+ function settlementFailed(code, detail) {
7929
+ return {
7930
+ isError: true,
7931
+ content: [
7932
+ {
7933
+ type: "text",
7934
+ text: `x402 settlement failed (${toA2AErrorCode(code)}): ${detail}. The buyer can retry, or pay the onchain-proof rail directly.`
7935
+ }
7936
+ ]
7937
+ };
7938
+ }
7939
+ async function handleToolCall(params) {
7940
+ const raw = fromMcpPayment(params);
7941
+ if (raw == null) {
7942
+ const { challenge } = await gate.challenge(options.resourceUrl ?? "");
7943
+ return toMcpPaymentRequired(challenge);
7944
+ }
7945
+ let result;
7946
+ try {
7947
+ result = await gate.verifyObject(raw);
7948
+ } catch (err) {
7949
+ if (err instanceof SettlementError) return settlementFailed("settlement_failed", err.message);
7950
+ throw err;
7951
+ }
7952
+ if (result.kind === "paid") {
7953
+ try {
7954
+ const content = await options.fulfill({ receipt: result.receipt, params });
7955
+ return toMcpPaymentResponse(content, result.receipt);
7956
+ } catch (err) {
7957
+ const detail = err instanceof Error ? err.message : String(err);
7958
+ return toMcpPaymentResponse(
7959
+ [{ type: "text", text: `Payment settled (tx ${result.receipt.transaction}), but serving the result failed: ${detail}` }],
7960
+ result.receipt
7961
+ );
7962
+ }
7963
+ }
7964
+ return toMcpPaymentRequired(result.challenge);
7965
+ }
7966
+ return { handleToolCall, gate };
7967
+ }
7711
7968
  export {
7712
7969
  A2A_ERROR_KEY,
7713
7970
  A2A_EXTENSIONS_HEADER,
@@ -7726,6 +7983,7 @@ export {
7726
7983
  EIP3009_TYPES,
7727
7984
  EXACT_NETWORK_SLUGS,
7728
7985
  EXT_OFFER_RECEIPT,
7986
+ EXT_PAYMENT_IDENTIFIER,
7729
7987
  GENERATOR,
7730
7988
  HEADER_REQUIRED,
7731
7989
  HEADER_RESPONSE,
@@ -7735,6 +7993,8 @@ export {
7735
7993
  InsufficientFundsError,
7736
7994
  InvalidEnvelopeError,
7737
7995
  KNOWN_FACILITATORS,
7996
+ MCP_PAYMENT_META_KEY,
7997
+ MCP_PAYMENT_RESPONSE_META_KEY,
7738
7998
  MaxRetriesExceededError,
7739
7999
  MissingDriverError,
7740
8000
  MultiChainPayer,
@@ -7772,18 +8032,22 @@ export {
7772
8032
  buildEndpointInfo,
7773
8033
  buildExactAuthorization,
7774
8034
  buildExactSignatureHeader,
8035
+ buildMcpPaymentMeta,
7775
8036
  buildOpenApi,
8037
+ buildPaymentIdentifierAdvertisement,
7776
8038
  buildReceiptExtension,
7777
8039
  buildReceiptHeader,
7778
8040
  buildSelfDescription,
7779
8041
  buildSignatureHeader,
7780
8042
  buildUptoSignatureHeader,
7781
8043
  buildWellKnownX402,
8044
+ buildWellKnownX402Manifest,
7782
8045
  buildX402DnsTxt,
7783
8046
  chainIdForExactNetwork,
7784
8047
  claim402IndexDomain,
7785
8048
  classifyChallenge,
7786
8049
  createA2APaymentHandler,
8050
+ createMcpPaymentTool,
7787
8051
  createPaymentGate,
7788
8052
  decodeBase64Json,
7789
8053
  decorateOutcome,
@@ -7801,7 +8065,11 @@ export {
7801
8065
  formatSpendReport,
7802
8066
  fromA2APaymentPayload,
7803
8067
  fromA2APaymentRequired,
8068
+ fromMcpPayment,
8069
+ fromMcpPaymentRequired,
8070
+ fromMcpPaymentResponse,
7804
8071
  getDirectoryInfo,
8072
+ isMcpPaymentRequired,
7805
8073
  isPermit2ProxyChain,
7806
8074
  isUptoProxyChain,
7807
8075
  knownFacilitatorsFor,
@@ -7824,6 +8092,7 @@ export {
7824
8092
  planAcross,
7825
8093
  rankResources,
7826
8094
  readExactDomain,
8095
+ readPaymentIdentifier,
7827
8096
  register402Index,
7828
8097
  registerDriver,
7829
8098
  registerX402Scan,
@@ -7840,5 +8109,7 @@ export {
7840
8109
  toA2APaymentRequired,
7841
8110
  toInsufficientFundsError,
7842
8111
  toInvalidBody,
8112
+ toMcpPaymentRequired,
8113
+ toMcpPaymentResponse,
7843
8114
  verify402IndexDomain
7844
8115
  };