@piprail/sdk 2.13.1 → 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 +70 -0
  2. package/dist/{algorand-TQCYK2XT.js → algorand-6J3IABVF.js} +12 -11
  3. package/dist/{algorand-AQK5EAUF.cjs → algorand-QU6G2DQZ.cjs} +43 -42
  4. package/dist/{aptos-RYQOSFBQ.js → aptos-DHOMTBLZ.js} +11 -10
  5. package/dist/{aptos-65UX7GKA.cjs → aptos-LFTQGBBK.cjs} +41 -40
  6. package/dist/{chunk-DCOUJZPL.cjs → chunk-GYM46G5L.cjs} +16 -0
  7. package/dist/{chunk-O32N6MFN.js → chunk-PAMKCWVW.js} +16 -0
  8. package/dist/index.cjs +484 -231
  9. package/dist/index.d.cts +270 -7
  10. package/dist/index.d.ts +270 -7
  11. package/dist/index.js +280 -27
  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-VDATC5AV.js → near-5PXTVQ47.js} +14 -5
  15. package/dist/{near-UDPFA6SV.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-VYLWFNAH.js → solana-HITVI3HF.js} +22 -7
  19. package/dist/{solana-RQNXFCZO.cjs → solana-N3UCNCYE.cjs} +54 -39
  20. package/dist/{stellar-KBR4V77T.js → stellar-2QT6YYKN.js} +4 -4
  21. package/dist/{stellar-OK2HW5PZ.cjs → stellar-Y3SQN7S5.cjs} +23 -23
  22. package/dist/{sui-SVFBJFW5.cjs → sui-4AL4E6XU.cjs} +35 -27
  23. package/dist/{sui-BXHB6D3W.js → sui-FV5L6WF5.js} +20 -12
  24. package/dist/{ton-NNKQFQ6U.js → ton-5FWDQ4QR.js} +18 -7
  25. package/dist/{ton-D7YN6BGR.cjs → ton-5HDVOTMR.cjs} +33 -22
  26. package/dist/{tron-W2D5PQXV.js → tron-AZDY7BMQ.js} +10 -10
  27. package/dist/{tron-WZFU57NX.cjs → tron-TX2B4N2A.cjs} +39 -39
  28. package/dist/{xrpl-5NHY3NEL.cjs → xrpl-5TYDLQFS.cjs} +31 -31
  29. package/dist/{xrpl-37E23W53.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-O32N6MFN.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-VYLWFNAH.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-NNKQFQ6U.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-KBR4V77T.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-37E23W53.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-W2D5PQXV.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-BXHB6D3W.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-VDATC5AV.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-RYQOSFBQ.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-TQCYK2XT.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`,
@@ -4032,7 +4084,8 @@ var PipRailClient = class {
4032
4084
  * before publishing, so retry with a brief backoff if a fresh listing is missing.
4033
4085
  * - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
4034
4086
  * `onchain-proof` rails by default, and standard `exact` rails too once you opt in
4035
- * 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).
4036
4089
  */
4037
4090
  async discover(opts = {}) {
4038
4091
  const found = await searchOpenIndexes({
@@ -4240,7 +4293,7 @@ var PipRailClient = class {
4240
4293
  );
4241
4294
  if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
4242
4295
  throw new UnsupportedSchemeError(
4243
- `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.`
4244
4297
  );
4245
4298
  }
4246
4299
  if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
@@ -4293,7 +4346,15 @@ var PipRailClient = class {
4293
4346
  if (schemes.includes("exact")) {
4294
4347
  out.push(
4295
4348
  ...challenge.accepts.filter(
4296
- (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
4297
4358
  // signing it would build a NaN/garbage validBefore — drop it silently
4298
4359
  // (symmetric with an unrecognised token) rather than leak a raw SyntaxError.
4299
4360
  Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
@@ -4303,7 +4364,8 @@ var PipRailClient = class {
4303
4364
  if (schemes.includes("upto")) {
4304
4365
  out.push(
4305
4366
  ...challenge.accepts.filter(
4306
- (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
4307
4369
  )
4308
4370
  );
4309
4371
  }
@@ -5517,8 +5579,8 @@ A 402 may offer up to three rails; you don't choose per payment \u2014 the clien
5517
5579
  (the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
5518
5580
  - exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
5519
5581
  (e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
5520
- works on EVM, Solana + Algorand, and the on-chain method (EIP-3009 / Permit2 / SVM / Algorand
5521
- 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.
5522
5584
  - upto (the metered/variable x402 rail, opt-in, EVM): the amount you see is a MAXIMUM \u2014 you sign
5523
5585
  a ceiling, the server meters real usage and settles the ACTUAL (<= the max). BUDGET AGAINST THE MAX:
5524
5586
  the plan/policy treat the ceiling as the spend (a server may charge up to it), so a payable plan
@@ -6063,6 +6125,23 @@ function buildWellKnownX402(input) {
6063
6125
  ...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
6064
6126
  };
6065
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
+ }
6066
6145
  function buildX402DnsTxt(input) {
6067
6146
  const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
6068
6147
  return {
@@ -6793,7 +6872,7 @@ function createPaymentGate(options) {
6793
6872
  if (hasCustomStore) {
6794
6873
  return options.isUsed ? Boolean(await options.isUsed(ref)) : false;
6795
6874
  }
6796
- const key = ref.toLowerCase();
6875
+ const key = ref.startsWith("pid:") ? ref : ref.toLowerCase();
6797
6876
  const now = Date.now();
6798
6877
  pruneUsed(now);
6799
6878
  if (localUsed.has(key)) return true;
@@ -6805,7 +6884,7 @@ function createPaymentGate(options) {
6805
6884
  if (ok && options.markUsed) await options.markUsed(ref);
6806
6885
  return;
6807
6886
  }
6808
- if (!ok) localUsed.delete(ref.toLowerCase());
6887
+ if (!ok) localUsed.delete(ref.startsWith("pid:") ? ref : ref.toLowerCase());
6809
6888
  }
6810
6889
  function buildAccept(s, nonce) {
6811
6890
  return {
@@ -6878,6 +6957,7 @@ function createPaymentGate(options) {
6878
6957
  const specs = await ready();
6879
6958
  const nonce = genNonce();
6880
6959
  const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
6960
+ const paymentIdAd = options.paymentIdentifier ? buildPaymentIdentifierAdvertisement() : void 0;
6881
6961
  const accepts = buildAccepts(specs, nonce);
6882
6962
  const endpointInfo = buildEndpointInfo({
6883
6963
  ...options.description ? { description: options.description } : {},
@@ -6895,11 +6975,13 @@ function createPaymentGate(options) {
6895
6975
  const bodyPiprail = { ...selfDescribe ?? {}, ...rejectionPiprail };
6896
6976
  const bodyExtensions = {
6897
6977
  ...bazaar,
6978
+ ...paymentIdAd,
6898
6979
  ...rejectionExt,
6899
6980
  ...Object.keys(bodyPiprail).length > 0 ? { piprail: bodyPiprail } : {}
6900
6981
  };
6901
6982
  const headerExtensions = {
6902
6983
  ...bazaar,
6984
+ ...paymentIdAd,
6903
6985
  ...Object.keys(rejectionPiprail).length > 0 ? { piprail: rejectionPiprail } : {}
6904
6986
  };
6905
6987
  const challenge2 = {
@@ -7109,7 +7191,17 @@ function createPaymentGate(options) {
7109
7191
  await settleTx(ref, false);
7110
7192
  return rejection(result.error, result.detail);
7111
7193
  }
7112
- 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
+ }
7113
7205
  await deliverOnPaid(spec, result.receipt);
7114
7206
  return await buildPaidResult(spec, result.receipt, sig.payload.nonce);
7115
7207
  }
@@ -7315,7 +7407,7 @@ function createPaymentGate(options) {
7315
7407
  if (result.kind === "invalid") await deliverOnFailed(result);
7316
7408
  return result;
7317
7409
  }
7318
- async function resolveVerdictObject(obj) {
7410
+ async function routeVerdictObject(obj) {
7319
7411
  if (obj === void 0 || obj === null) return asChallenge();
7320
7412
  const sig = parseSignatureObject(obj);
7321
7413
  if (sig && sig.accepted && typeof sig.accepted.network === "string" && typeof sig.accepted.asset === "string") {
@@ -7327,6 +7419,44 @@ function createPaymentGate(options) {
7327
7419
  if (exact) return verifyExact(exact);
7328
7420
  return asChallenge();
7329
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
+ }
7330
7460
  return { challenge, verify, verifyObject, describe, landingPage };
7331
7461
  }
7332
7462
  function requirePayment(options) {
@@ -7726,6 +7856,115 @@ function resourceUrlFromMessage(message) {
7726
7856
  }
7727
7857
  return "";
7728
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
+ }
7729
7968
  export {
7730
7969
  A2A_ERROR_KEY,
7731
7970
  A2A_EXTENSIONS_HEADER,
@@ -7744,6 +7983,7 @@ export {
7744
7983
  EIP3009_TYPES,
7745
7984
  EXACT_NETWORK_SLUGS,
7746
7985
  EXT_OFFER_RECEIPT,
7986
+ EXT_PAYMENT_IDENTIFIER,
7747
7987
  GENERATOR,
7748
7988
  HEADER_REQUIRED,
7749
7989
  HEADER_RESPONSE,
@@ -7753,6 +7993,8 @@ export {
7753
7993
  InsufficientFundsError,
7754
7994
  InvalidEnvelopeError,
7755
7995
  KNOWN_FACILITATORS,
7996
+ MCP_PAYMENT_META_KEY,
7997
+ MCP_PAYMENT_RESPONSE_META_KEY,
7756
7998
  MaxRetriesExceededError,
7757
7999
  MissingDriverError,
7758
8000
  MultiChainPayer,
@@ -7790,18 +8032,22 @@ export {
7790
8032
  buildEndpointInfo,
7791
8033
  buildExactAuthorization,
7792
8034
  buildExactSignatureHeader,
8035
+ buildMcpPaymentMeta,
7793
8036
  buildOpenApi,
8037
+ buildPaymentIdentifierAdvertisement,
7794
8038
  buildReceiptExtension,
7795
8039
  buildReceiptHeader,
7796
8040
  buildSelfDescription,
7797
8041
  buildSignatureHeader,
7798
8042
  buildUptoSignatureHeader,
7799
8043
  buildWellKnownX402,
8044
+ buildWellKnownX402Manifest,
7800
8045
  buildX402DnsTxt,
7801
8046
  chainIdForExactNetwork,
7802
8047
  claim402IndexDomain,
7803
8048
  classifyChallenge,
7804
8049
  createA2APaymentHandler,
8050
+ createMcpPaymentTool,
7805
8051
  createPaymentGate,
7806
8052
  decodeBase64Json,
7807
8053
  decorateOutcome,
@@ -7819,7 +8065,11 @@ export {
7819
8065
  formatSpendReport,
7820
8066
  fromA2APaymentPayload,
7821
8067
  fromA2APaymentRequired,
8068
+ fromMcpPayment,
8069
+ fromMcpPaymentRequired,
8070
+ fromMcpPaymentResponse,
7822
8071
  getDirectoryInfo,
8072
+ isMcpPaymentRequired,
7823
8073
  isPermit2ProxyChain,
7824
8074
  isUptoProxyChain,
7825
8075
  knownFacilitatorsFor,
@@ -7842,6 +8092,7 @@ export {
7842
8092
  planAcross,
7843
8093
  rankResources,
7844
8094
  readExactDomain,
8095
+ readPaymentIdentifier,
7845
8096
  register402Index,
7846
8097
  registerDriver,
7847
8098
  registerX402Scan,
@@ -7858,5 +8109,7 @@ export {
7858
8109
  toA2APaymentRequired,
7859
8110
  toInsufficientFundsError,
7860
8111
  toInvalidBody,
8112
+ toMcpPaymentRequired,
8113
+ toMcpPaymentResponse,
7861
8114
  verify402IndexDomain
7862
8115
  };
@@ -210,6 +210,13 @@ interface X402PaymentSignature {
210
210
  nonce: string;
211
211
  txHash: string;
212
212
  };
213
+ /**
214
+ * Optional v2 extensions the client attaches to its payload — e.g. the
215
+ * `payment-identifier` idempotency id at `extensions['payment-identifier'].info.id`
216
+ * (read by the gate via {@link readPaymentIdentifier}). A standard reader ignores it,
217
+ * and omitting it keeps the payload byte-identical.
218
+ */
219
+ extensions?: Record<string, unknown>;
213
220
  }
214
221
  /**
215
222
  * The EIP-3009 authorization a payer signs for a standard `exact` rail. All
@@ -590,6 +597,29 @@ declare function buildReceiptExtension(bundle: {
590
597
  decimals?: number;
591
598
  attestation?: SignedReceipt;
592
599
  }): Record<string, unknown>;
600
+ /** The x402 extension key for the optional idempotency identifier (the official
601
+ * `payment-identifier` extension). A client MAY attach a stable `id` so the server dedupes
602
+ * retries and rejects a reused id bound to a DIFFERENT payment. */
603
+ declare const EXT_PAYMENT_IDENTIFIER = "payment-identifier";
604
+ /**
605
+ * Advertise the `payment-identifier` extension on a 402 challenge — PURE JSON, viem-free. The
606
+ * v2 `{ info, schema }` shape: `info.required:false` (PipRail never MANDATES an id) plus a
607
+ * JSON-Schema bound of {@link PAYMENT_ID_MIN}–{@link PAYMENT_ID_MAX} chars. A client reads this
608
+ * from the challenge and MAY echo an `id` back on its payload; the gate dedupes it on its
609
+ * existing used-proof set. The gate merges this into the challenge `extensions` (a sibling key,
610
+ * never inside `extensions.piprail`).
611
+ */
612
+ declare function buildPaymentIdentifierAdvertisement(): Record<string, unknown>;
613
+ /**
614
+ * Read + validate an inbound `payment-identifier` id from a decoded payment-payload object
615
+ * (`payload.extensions['payment-identifier'].info.id`). PURE, NEVER throws. Returns:
616
+ * - the `id` string when present + valid (16–128 chars, `[A-Za-z0-9_-]`),
617
+ * - `null` when ABSENT (the id is OPTIONAL — the gate proceeds exactly as without the feature),
618
+ * - `{ invalid }` when PRESENT but malformed (the gate re-challenges so the buyer can fix it).
619
+ */
620
+ declare function readPaymentIdentifier(payload: unknown): string | null | {
621
+ invalid: string;
622
+ };
593
623
  declare function buildSignatureHeader(signature: X402PaymentSignature): string;
594
624
  /**
595
625
  * Build the v2 PAYMENT-SIGNATURE header value for a standard x402 `exact` payment:
@@ -928,4 +958,4 @@ declare class SpendLedger {
928
958
  summary(): SpendSummary;
929
959
  }
930
960
 
931
- export { parseSignatureObject as $, type AddressId as A, type X402PaymentSignature as B, type Caip2 as C, type X402Receipt as D, EXT_OFFER_RECEIPT as E, type X402ResourceObject as F, type X402UptoAcceptEntry as G, HEADER_REQUIRED as H, buildChallengeHeader as I, buildExactSignatureHeader as J, buildReceiptExtension as K, buildReceiptHeader as L, buildSignatureHeader as M, buildUptoSignatureHeader as N, decodeBase64Json as O, type PaidReceipt as P, memorySpendStore as Q, parseChallenge as R, type SettleOutcome as S, parseExactObject as T, parseExactPaymentHeader as U, type VerifyErrorCode as V, parseReceipt as W, type X402AcceptEntry as X, parseReceiptExtension as Y, parseSettleResponse as Z, parseSignatureHeader as _, type AssetId as a, parseUptoObject as a0, parseUptoPaymentHeader as a1, pickAccept as a2, type ExactAuthorizationWire as b, type ExactPaymentPayload as c, type ExactPaymentPayloadAny as d, HEADER_RESPONSE as e, HEADER_RESPONSE_V1 as f, HEADER_SIGNATURE as g, HEADER_SIGNATURE_V1 as h, type ParsedExactPayment as i, type ParsedUptoPayment as j, type Permit2Authorization as k, type Permit2PaymentPayload as l, type Permit2UptoAuthorization as m, type Permit2UptoPaymentPayload as n, type PipRailReceipt as o, type SignedReceipt as p, type SpendAssetTotal as q, type SpendDenomTotal as r, SpendLedger as s, type SpendRecord as t, type SpendStore as u, type SpendSummary as v, type VerifyResult as w, type X402AnyAccept as x, type X402Challenge as y, type X402ExactAcceptEntry as z };
961
+ export { parseSettleResponse as $, type AddressId as A, type X402ExactAcceptEntry as B, type Caip2 as C, type X402PaymentSignature as D, EXT_OFFER_RECEIPT as E, type X402Receipt as F, type X402ResourceObject as G, HEADER_REQUIRED as H, type X402UptoAcceptEntry as I, buildChallengeHeader as J, buildExactSignatureHeader as K, buildPaymentIdentifierAdvertisement as L, buildReceiptExtension as M, buildReceiptHeader as N, buildSignatureHeader as O, type PaidReceipt as P, buildUptoSignatureHeader as Q, decodeBase64Json as R, type SettleOutcome as S, memorySpendStore as T, parseChallenge as U, type VerifyErrorCode as V, parseExactObject as W, type X402AcceptEntry as X, parseExactPaymentHeader as Y, parseReceipt as Z, parseReceiptExtension as _, type AssetId as a, parseSignatureHeader as a0, parseSignatureObject as a1, parseUptoObject as a2, parseUptoPaymentHeader as a3, pickAccept as a4, readPaymentIdentifier as a5, EXT_PAYMENT_IDENTIFIER as b, type ExactAuthorizationWire as c, type ExactPaymentPayload as d, type ExactPaymentPayloadAny as e, HEADER_RESPONSE as f, HEADER_RESPONSE_V1 as g, HEADER_SIGNATURE as h, HEADER_SIGNATURE_V1 as i, type ParsedExactPayment as j, type ParsedUptoPayment as k, type Permit2Authorization as l, type Permit2PaymentPayload as m, type Permit2UptoAuthorization as n, type Permit2UptoPaymentPayload as o, type PipRailReceipt as p, type SignedReceipt as q, type SpendAssetTotal as r, type SpendDenomTotal as s, SpendLedger as t, type SpendRecord as u, type SpendStore as v, type SpendSummary as w, type VerifyResult as x, type X402AnyAccept as y, type X402Challenge as z };