@piprail/sdk 2.13.1 → 2.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/dist/{algorand-AQK5EAUF.cjs → algorand-ICJNXO5V.cjs} +43 -42
  3. package/dist/{algorand-TQCYK2XT.js → algorand-RM7MP4PK.js} +12 -11
  4. package/dist/{aptos-RYQOSFBQ.js → aptos-2FIRTMQX.js} +11 -10
  5. package/dist/{aptos-65UX7GKA.cjs → aptos-MVEG5ZPS.cjs} +41 -40
  6. package/dist/{chunk-DCOUJZPL.cjs → chunk-57V5DNJT.cjs} +45 -19
  7. package/dist/{chunk-O32N6MFN.js → chunk-NUPCFNC5.js} +27 -1
  8. package/dist/index.cjs +503 -239
  9. package/dist/index.d.cts +279 -7
  10. package/dist/index.d.ts +279 -7
  11. package/dist/index.js +299 -35
  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-UDPFA6SV.cjs → near-C2IS4RCH.cjs} +39 -30
  15. package/dist/{near-VDATC5AV.js → near-L2OWD7M6.js} +14 -5
  16. package/dist/node.d.cts +2 -2
  17. package/dist/node.d.ts +2 -2
  18. package/dist/{solana-RQNXFCZO.cjs → solana-B424IQ5I.cjs} +54 -39
  19. package/dist/{solana-VYLWFNAH.js → solana-V2TGLHJ4.js} +22 -7
  20. package/dist/{stellar-OK2HW5PZ.cjs → stellar-4YR4UZQX.cjs} +23 -23
  21. package/dist/{stellar-KBR4V77T.js → stellar-J7VE7QP7.js} +4 -4
  22. package/dist/{sui-SVFBJFW5.cjs → sui-F7UW6JXJ.cjs} +35 -27
  23. package/dist/{sui-BXHB6D3W.js → sui-GMRQAAJH.js} +20 -12
  24. package/dist/{ton-D7YN6BGR.cjs → ton-3SHFVDLP.cjs} +33 -22
  25. package/dist/{ton-NNKQFQ6U.js → ton-PEBYBNWJ.js} +18 -7
  26. package/dist/{tron-WZFU57NX.cjs → tron-BS5EID2U.cjs} +39 -39
  27. package/dist/{tron-W2D5PQXV.js → tron-ZYJHHROT.js} +10 -10
  28. package/dist/{xrpl-37E23W53.js → xrpl-P2D6TS6I.js} +13 -13
  29. package/dist/{xrpl-5NHY3NEL.cjs → xrpl-SUEFOOKW.cjs} +31 -31
  30. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  import {
8
8
  ConfirmationTimeoutError,
9
9
  InsufficientFundsError,
10
+ InvalidConfigError,
10
11
  InvalidEnvelopeError,
11
12
  MAX_DECIMALS,
12
13
  MaxRetriesExceededError,
@@ -31,7 +32,7 @@ import {
31
32
  parseUnits,
32
33
  rejectForeignToken,
33
34
  toInsufficientFundsError
34
- } from "./chunk-O32N6MFN.js";
35
+ } from "./chunk-NUPCFNC5.js";
35
36
 
36
37
  // src/drivers/registry.ts
37
38
  var byFamily = /* @__PURE__ */ new Map();
@@ -1780,6 +1781,37 @@ function buildReceiptExtension(bundle) {
1780
1781
  if (bundle.attestation) info.receipt = bundle.attestation;
1781
1782
  return { [EXT_OFFER_RECEIPT]: { info } };
1782
1783
  }
1784
+ var EXT_PAYMENT_IDENTIFIER = "payment-identifier";
1785
+ var PAYMENT_ID_MIN = 16;
1786
+ var PAYMENT_ID_MAX = 128;
1787
+ var PAYMENT_ID_RE = /^[A-Za-z0-9_-]+$/;
1788
+ function buildPaymentIdentifierAdvertisement() {
1789
+ return {
1790
+ [EXT_PAYMENT_IDENTIFIER]: {
1791
+ info: { required: false },
1792
+ schema: { properties: { id: { type: "string", minLength: PAYMENT_ID_MIN, maxLength: PAYMENT_ID_MAX } } }
1793
+ }
1794
+ };
1795
+ }
1796
+ function readPaymentIdentifier(payload) {
1797
+ if (typeof payload !== "object" || payload === null) return null;
1798
+ const ext = payload.extensions;
1799
+ if (typeof ext !== "object" || ext === null) return null;
1800
+ const block = ext[EXT_PAYMENT_IDENTIFIER];
1801
+ if (typeof block !== "object" || block === null) return null;
1802
+ const info = block.info;
1803
+ if (typeof info !== "object" || info === null) return null;
1804
+ const id = info.id;
1805
+ if (id === void 0) return null;
1806
+ if (typeof id !== "string") return { invalid: "payment-identifier id must be a string" };
1807
+ if (id.length < PAYMENT_ID_MIN || id.length > PAYMENT_ID_MAX) {
1808
+ return { invalid: `payment-identifier id must be ${PAYMENT_ID_MIN}\u2013${PAYMENT_ID_MAX} chars (got ${id.length})` };
1809
+ }
1810
+ if (!PAYMENT_ID_RE.test(id)) {
1811
+ return { invalid: "payment-identifier id must match [A-Za-z0-9_-]" };
1812
+ }
1813
+ return id;
1814
+ }
1783
1815
  function buildSignatureHeader(signature) {
1784
1816
  return toBase64Json(signature);
1785
1817
  }
@@ -1806,7 +1838,10 @@ function parseReceipt(response) {
1806
1838
  const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
1807
1839
  if (!headerValue) return null;
1808
1840
  const parsed = fromBase64Json(headerValue);
1809
- return isValidReceipt(parsed) ? parsed : null;
1841
+ if (!isValidReceipt(parsed)) return null;
1842
+ const r = parsed;
1843
+ if (typeof r.transaction !== "string" && typeof r.txHash === "string") r.transaction = r.txHash;
1844
+ return r;
1810
1845
  }
1811
1846
  function parseReceiptExtension(response) {
1812
1847
  const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
@@ -1836,7 +1871,8 @@ function parseSettleResponse(response) {
1836
1871
  if (!parsed || typeof parsed !== "object" || typeof parsed.success !== "boolean") return null;
1837
1872
  return {
1838
1873
  success: parsed.success,
1839
- ...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : {},
1874
+ // Tolerate the legacy v1 `txHash` alias for `transaction` (mirrors isValidReceipt/parseReceipt).
1875
+ ...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : typeof parsed.txHash === "string" ? { transaction: parsed.txHash } : {},
1840
1876
  ...typeof parsed.network === "string" ? { network: parsed.network } : {},
1841
1877
  ...typeof parsed.payer === "string" ? { payer: parsed.payer } : {},
1842
1878
  ...typeof parsed.errorReason === "string" ? { errorReason: parsed.errorReason } : {},
@@ -1855,6 +1891,14 @@ function parseSignatureObject(parsed) {
1855
1891
  if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
1856
1892
  return null;
1857
1893
  }
1894
+ if (!accepted) {
1895
+ const synthesized = {
1896
+ scheme: "onchain-proof",
1897
+ ...typeof v.network === "string" ? { network: v.network } : {},
1898
+ ...typeof v.asset === "string" ? { asset: v.asset } : {}
1899
+ };
1900
+ return { ...v, accepted: synthesized, payload };
1901
+ }
1858
1902
  return parsed;
1859
1903
  }
1860
1904
  function parseSignatureHeader(value) {
@@ -1994,7 +2038,11 @@ var evmDriver = {
1994
2038
  resolve(opts) {
1995
2039
  if (typeof opts.chain === "string" && /^(solana|ton|stellar)/.test(opts.chain)) return null;
1996
2040
  if (typeof opts.chain === "string") {
1997
- return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
2041
+ try {
2042
+ return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
2043
+ } catch (err) {
2044
+ throw new UnsupportedNetworkError(err instanceof Error ? err.message : String(err), { cause: err });
2045
+ }
1998
2046
  }
1999
2047
  let resolved;
2000
2048
  try {
@@ -2039,8 +2087,13 @@ function makeEvmNetwork(resolved) {
2039
2087
  `chain ${network} is EVM; a custom token must be { address, decimals }.`
2040
2088
  );
2041
2089
  }
2090
+ if (!isAddress(token.address)) {
2091
+ throw new WrongFamilyError(
2092
+ `chain ${network} is EVM, but token address "${token.address}" is not a valid 0x address.`
2093
+ );
2094
+ }
2042
2095
  return {
2043
- asset: token.address,
2096
+ asset: getAddress5(token.address),
2044
2097
  decimals: token.decimals,
2045
2098
  ...token.symbol ? { symbol: token.symbol } : {}
2046
2099
  };
@@ -2121,9 +2174,9 @@ function makeEvmNetwork(resolved) {
2121
2174
  },
2122
2175
  async estimateCost(accept) {
2123
2176
  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";
2177
+ if (accept.scheme === "exact" || accept.scheme === "upto") {
2178
+ const m = accept.extra?.assetTransferMethod;
2179
+ const permit2 = m === "permit2" || m === "permit2-exact" || m === "permit2-upto";
2127
2180
  return nativeCost({
2128
2181
  symbol,
2129
2182
  decimals,
@@ -2329,7 +2382,7 @@ var loaders = {
2329
2382
  solana: async () => {
2330
2383
  let mod;
2331
2384
  try {
2332
- mod = await import("./solana-VYLWFNAH.js");
2385
+ mod = await import("./solana-V2TGLHJ4.js");
2333
2386
  } catch (cause) {
2334
2387
  throw new MissingDriverError(
2335
2388
  `Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
@@ -2341,7 +2394,7 @@ var loaders = {
2341
2394
  ton: async () => {
2342
2395
  let mod;
2343
2396
  try {
2344
- mod = await import("./ton-NNKQFQ6U.js");
2397
+ mod = await import("./ton-PEBYBNWJ.js");
2345
2398
  } catch (cause) {
2346
2399
  throw new MissingDriverError(
2347
2400
  `TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
@@ -2353,7 +2406,7 @@ var loaders = {
2353
2406
  stellar: async () => {
2354
2407
  let mod;
2355
2408
  try {
2356
- mod = await import("./stellar-KBR4V77T.js");
2409
+ mod = await import("./stellar-J7VE7QP7.js");
2357
2410
  } catch (cause) {
2358
2411
  throw new MissingDriverError(
2359
2412
  `Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
@@ -2365,7 +2418,7 @@ var loaders = {
2365
2418
  xrpl: async () => {
2366
2419
  let mod;
2367
2420
  try {
2368
- mod = await import("./xrpl-37E23W53.js");
2421
+ mod = await import("./xrpl-P2D6TS6I.js");
2369
2422
  } catch (cause) {
2370
2423
  throw new MissingDriverError(
2371
2424
  `XRPL selected, but its package isn't installed. Run: npm install xrpl`,
@@ -2377,7 +2430,7 @@ var loaders = {
2377
2430
  tron: async () => {
2378
2431
  let mod;
2379
2432
  try {
2380
- mod = await import("./tron-W2D5PQXV.js");
2433
+ mod = await import("./tron-ZYJHHROT.js");
2381
2434
  } catch (cause) {
2382
2435
  throw new MissingDriverError(
2383
2436
  `Tron selected, but its package isn't installed. Run: npm install tronweb`,
@@ -2389,7 +2442,7 @@ var loaders = {
2389
2442
  sui: async () => {
2390
2443
  let mod;
2391
2444
  try {
2392
- mod = await import("./sui-BXHB6D3W.js");
2445
+ mod = await import("./sui-GMRQAAJH.js");
2393
2446
  } catch (cause) {
2394
2447
  throw new MissingDriverError(
2395
2448
  `Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
@@ -2401,7 +2454,7 @@ var loaders = {
2401
2454
  near: async () => {
2402
2455
  let mod;
2403
2456
  try {
2404
- mod = await import("./near-VDATC5AV.js");
2457
+ mod = await import("./near-L2OWD7M6.js");
2405
2458
  } catch (cause) {
2406
2459
  throw new MissingDriverError(
2407
2460
  `NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
@@ -2413,7 +2466,7 @@ var loaders = {
2413
2466
  aptos: async () => {
2414
2467
  let mod;
2415
2468
  try {
2416
- mod = await import("./aptos-RYQOSFBQ.js");
2469
+ mod = await import("./aptos-2FIRTMQX.js");
2417
2470
  } catch (cause) {
2418
2471
  throw new MissingDriverError(
2419
2472
  `Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
@@ -2425,7 +2478,7 @@ var loaders = {
2425
2478
  algorand: async () => {
2426
2479
  let mod;
2427
2480
  try {
2428
- mod = await import("./algorand-TQCYK2XT.js");
2481
+ mod = await import("./algorand-RM7MP4PK.js");
2429
2482
  } catch (cause) {
2430
2483
  throw new MissingDriverError(
2431
2484
  `Algorand selected, but its package isn't installed. Run: npm install algosdk`,
@@ -2458,7 +2511,7 @@ async function resolveNetwork2(opts) {
2458
2511
  }
2459
2512
 
2460
2513
  // src/indexes.ts
2461
- var DIRECTORY_INFO = {
2514
+ var DIRECTORY_INFO = Object.freeze({
2462
2515
  "402index": {
2463
2516
  source: "402index",
2464
2517
  review: "probe-sync",
@@ -2486,7 +2539,7 @@ var DIRECTORY_INFO = {
2486
2539
  readByDiscover: true,
2487
2540
  caveat: "CDP Bazaar has no register endpoint \u2014 it catalogs a resource only when its own facilitator settles a payment. PipRail verifies locally with no facilitator, so a PipRail resource cannot be listed here (you can still READ Bazaar to find others). List on 402 Index or x402scan instead."
2488
2541
  }
2489
- };
2542
+ });
2490
2543
  function getDirectoryInfo(source) {
2491
2544
  return DIRECTORY_INFO[source];
2492
2545
  }
@@ -4032,7 +4085,8 @@ var PipRailClient = class {
4032
4085
  * before publishing, so retry with a brief backoff if a fresh listing is missing.
4033
4086
  * - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
4034
4087
  * `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).
4088
+ * with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
4089
+ * + Aptos + NEAR).
4036
4090
  */
4037
4091
  async discover(opts = {}) {
4038
4092
  const found = await searchOpenIndexes({
@@ -4240,7 +4294,7 @@ var PipRailClient = class {
4240
4294
  );
4241
4295
  if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
4242
4296
  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.`
4297
+ `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
4298
  );
4245
4299
  }
4246
4300
  if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
@@ -4293,7 +4347,15 @@ var PipRailClient = class {
4293
4347
  if (schemes.includes("exact")) {
4294
4348
  out.push(
4295
4349
  ...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
4350
+ (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
4351
+ // signed-authorization scheme a native coin can't support; every driver's payExact
4352
+ // throws/returns-null for it). describeAsset('native') IS non-null (onchain-proof needs
4353
+ // it), so without this guard a malformed 402 advertising a native `exact` rail would be
4354
+ // gathered, planned `payable`, even chosen by autoRoute — then throw at pay time.
4355
+ a.asset !== "native" && // the exact pay path (payExact → driver) reads `extra.assetTransferMethod`; a malformed
4356
+ // 402 offering an exact rail for a RECOGNISED token but omitting `extra` would otherwise
4357
+ // be planned payable then throw a raw TypeError mid-pay. Require it at gather time.
4358
+ typeof a.extra?.assetTransferMethod === "string" && net.describeAsset(a.asset) != null && // a foreign rail's maxTimeoutSeconds must be a usable positive integer, or
4297
4359
  // signing it would build a NaN/garbage validBefore — drop it silently
4298
4360
  // (symmetric with an unrecognised token) rather than leak a raw SyntaxError.
4299
4361
  Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
@@ -4303,7 +4365,8 @@ var PipRailClient = class {
4303
4365
  if (schemes.includes("upto")) {
4304
4366
  out.push(
4305
4367
  ...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
4368
+ (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)
4369
+ net.describeAsset(a.asset) != null && typeof a.extra?.facilitatorAddress === "string" && a.extra.facilitatorAddress.length > 0 && Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
4307
4370
  )
4308
4371
  );
4309
4372
  }
@@ -5474,14 +5537,15 @@ function formatSpendReport(summary) {
5474
5537
  return `${perAsset} \u2014 grand total: ${grand}`;
5475
5538
  }
5476
5539
  function describeChallenge(challenge) {
5477
- const first = challenge.accepts[0];
5540
+ const accepts = Array.isArray(challenge?.accepts) ? challenge.accepts : [];
5541
+ const first = accepts[0];
5478
5542
  if (!first) {
5479
5543
  return `${BRAND.name} x402 payment endpoint. Pay with @piprail/sdk (${BRAND.sdkInstall}). Docs: ${BRAND.home}.`;
5480
5544
  }
5481
5545
  const extra = first.extra ?? {};
5482
5546
  const amount = extra.amountFormatted ?? first.amount;
5483
5547
  const token = extra.symbol ?? first.asset;
5484
- const hasExact = challenge.accepts.some((a) => a.scheme === "exact");
5548
+ const hasExact = accepts.some((a) => a.scheme === "exact");
5485
5549
  const standard = hasExact ? "; or any standard x402 client (an exact rail is offered)" : "";
5486
5550
  return `${BRAND.name} x402 payment endpoint \u2014 pay ${amount} ${token} on ${first.network} to ${first.payTo}. Programmatic: ${BRAND.sdkInstall} then client.fetch(url)${standard}. Docs: ${BRAND.home}.`;
5487
5551
  }
@@ -5517,8 +5581,8 @@ A 402 may offer up to three rails; you don't choose per payment \u2014 the clien
5517
5581
  (the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
5518
5582
  - exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
5519
5583
  (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.
5584
+ works on EVM, Solana, Algorand, Aptos + NEAR, and the on-chain method (EIP-3009 / Permit2 / SVM /
5585
+ Algorand fee-pooled group / Aptos fee-payer / NEAR SignedDelegateAction) is picked automatically.
5522
5586
  - upto (the metered/variable x402 rail, opt-in, EVM): the amount you see is a MAXIMUM \u2014 you sign
5523
5587
  a ceiling, the server meters real usage and settles the ACTUAL (<= the max). BUDGET AGAINST THE MAX:
5524
5588
  the plan/policy treat the ceiling as the spend (a server may charge up to it), so a payable plan
@@ -5973,12 +6037,14 @@ function paymentTools(client) {
5973
6037
 
5974
6038
  // src/classify.ts
5975
6039
  function classifyChallenge(challenge, opts) {
5976
- const accepts = challenge.accepts ?? [];
6040
+ const accepts = Array.isArray(challenge?.accepts) ? challenge.accepts : [];
6041
+ const network = opts?.network;
6042
+ const schemes = opts?.schemes ?? [];
5977
6043
  const offeredSchemes = [...new Set(accepts.map((a) => a.scheme))];
5978
6044
  const offeredNetworks = [...new Set(accepts.map((a) => a.network))];
5979
- const onClientChain = accepts.some((a) => a.network === opts.network);
6045
+ const onClientChain = accepts.some((a) => a.network === network);
5980
6046
  const payableScheme = accepts.some(
5981
- (a) => a.network === opts.network && opts.schemes.includes(a.scheme)
6047
+ (a) => a.network === network && schemes.includes(a.scheme)
5982
6048
  );
5983
6049
  const verdict = accepts.length === 0 ? "NO_RAIL" : payableScheme ? "PAYABLE_RAIL" : onClientChain ? "UNPAYABLE_SCHEME" : "WRONG_CHAIN";
5984
6050
  return { onClientChain, payableScheme, offeredSchemes, offeredNetworks, verdict };
@@ -6063,6 +6129,29 @@ function buildWellKnownX402(input) {
6063
6129
  ...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
6064
6130
  };
6065
6131
  }
6132
+ function buildWellKnownX402Manifest(input) {
6133
+ if (!Array.isArray(input?.resources)) {
6134
+ throw new InvalidConfigError(
6135
+ "buildWellKnownX402Manifest: `resources` must be an array of ResourceDescription."
6136
+ );
6137
+ }
6138
+ const lastUpdated = typeof input.lastUpdated === "number" && Number.isFinite(input.lastUpdated) ? input.lastUpdated : Math.floor(Date.now() / 1e3);
6139
+ return {
6140
+ x402Version: 2,
6141
+ lastUpdated,
6142
+ items: input.resources.map((r) => ({
6143
+ resource: {
6144
+ url: r.url,
6145
+ ...r.description ? { description: r.description } : {},
6146
+ ...r.mimeType ? { mimeType: r.mimeType } : {}
6147
+ },
6148
+ type: "http",
6149
+ accepts: r.accepts,
6150
+ input: { method: (r.method ?? "GET").toUpperCase() },
6151
+ ...r.mimeType ? { output: { mimeType: r.mimeType } } : {}
6152
+ }))
6153
+ };
6154
+ }
6066
6155
  function buildX402DnsTxt(input) {
6067
6156
  const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
6068
6157
  return {
@@ -6655,7 +6744,7 @@ function createPaymentGate(options) {
6655
6744
  const net = await resolveNetwork2({ chain: a.chain, rpcUrl: a.rpcUrl ?? options.rpcUrl });
6656
6745
  const payTo = a.payTo ?? options.payTo;
6657
6746
  if (!payTo) {
6658
- throw new Error(
6747
+ throw new InvalidConfigError(
6659
6748
  `requirePayment: no payTo for chain ${net.network}. Set it on the accept entry or pass a top-level payTo.`
6660
6749
  );
6661
6750
  }
@@ -6793,7 +6882,7 @@ function createPaymentGate(options) {
6793
6882
  if (hasCustomStore) {
6794
6883
  return options.isUsed ? Boolean(await options.isUsed(ref)) : false;
6795
6884
  }
6796
- const key = ref.toLowerCase();
6885
+ const key = ref.startsWith("pid:") ? ref : ref.toLowerCase();
6797
6886
  const now = Date.now();
6798
6887
  pruneUsed(now);
6799
6888
  if (localUsed.has(key)) return true;
@@ -6805,7 +6894,7 @@ function createPaymentGate(options) {
6805
6894
  if (ok && options.markUsed) await options.markUsed(ref);
6806
6895
  return;
6807
6896
  }
6808
- if (!ok) localUsed.delete(ref.toLowerCase());
6897
+ if (!ok) localUsed.delete(ref.startsWith("pid:") ? ref : ref.toLowerCase());
6809
6898
  }
6810
6899
  function buildAccept(s, nonce) {
6811
6900
  return {
@@ -6878,6 +6967,7 @@ function createPaymentGate(options) {
6878
6967
  const specs = await ready();
6879
6968
  const nonce = genNonce();
6880
6969
  const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
6970
+ const paymentIdAd = options.paymentIdentifier ? buildPaymentIdentifierAdvertisement() : void 0;
6881
6971
  const accepts = buildAccepts(specs, nonce);
6882
6972
  const endpointInfo = buildEndpointInfo({
6883
6973
  ...options.description ? { description: options.description } : {},
@@ -6895,11 +6985,13 @@ function createPaymentGate(options) {
6895
6985
  const bodyPiprail = { ...selfDescribe ?? {}, ...rejectionPiprail };
6896
6986
  const bodyExtensions = {
6897
6987
  ...bazaar,
6988
+ ...paymentIdAd,
6898
6989
  ...rejectionExt,
6899
6990
  ...Object.keys(bodyPiprail).length > 0 ? { piprail: bodyPiprail } : {}
6900
6991
  };
6901
6992
  const headerExtensions = {
6902
6993
  ...bazaar,
6994
+ ...paymentIdAd,
6903
6995
  ...Object.keys(rejectionPiprail).length > 0 ? { piprail: rejectionPiprail } : {}
6904
6996
  };
6905
6997
  const challenge2 = {
@@ -7109,7 +7201,17 @@ function createPaymentGate(options) {
7109
7201
  await settleTx(ref, false);
7110
7202
  return rejection(result.error, result.detail);
7111
7203
  }
7112
- await settleTx(ref, true);
7204
+ const verified = result.receipt.transaction;
7205
+ if (verified && verified !== ref) {
7206
+ if (await claimTx(verified)) {
7207
+ await settleTx(ref, false);
7208
+ return rejection("tx_already_used", `Payment ${verified} was already redeemed.`);
7209
+ }
7210
+ await settleTx(ref, false);
7211
+ await settleTx(verified, true);
7212
+ } else {
7213
+ await settleTx(ref, true);
7214
+ }
7113
7215
  await deliverOnPaid(spec, result.receipt);
7114
7216
  return await buildPaidResult(spec, result.receipt, sig.payload.nonce);
7115
7217
  }
@@ -7315,7 +7417,7 @@ function createPaymentGate(options) {
7315
7417
  if (result.kind === "invalid") await deliverOnFailed(result);
7316
7418
  return result;
7317
7419
  }
7318
- async function resolveVerdictObject(obj) {
7420
+ async function routeVerdictObject(obj) {
7319
7421
  if (obj === void 0 || obj === null) return asChallenge();
7320
7422
  const sig = parseSignatureObject(obj);
7321
7423
  if (sig && sig.accepted && typeof sig.accepted.network === "string" && typeof sig.accepted.asset === "string") {
@@ -7327,6 +7429,44 @@ function createPaymentGate(options) {
7327
7429
  if (exact) return verifyExact(exact);
7328
7430
  return asChallenge();
7329
7431
  }
7432
+ function echoPaymentIdentifier(result, id) {
7433
+ try {
7434
+ const decoded = decodeBase64Json(result.receiptHeader);
7435
+ if (!decoded) return result;
7436
+ const { extensions: existing, ...receiptOnly } = decoded;
7437
+ const merged = {
7438
+ ...existing ?? {},
7439
+ [EXT_PAYMENT_IDENTIFIER]: { info: { required: false, id } }
7440
+ };
7441
+ return { ...result, receiptHeader: buildReceiptHeader(receiptOnly, merged) };
7442
+ } catch {
7443
+ return result;
7444
+ }
7445
+ }
7446
+ async function resolveVerdictObject(obj) {
7447
+ if (!options.paymentIdentifier) return routeVerdictObject(obj);
7448
+ const id = readPaymentIdentifier(obj);
7449
+ if (id !== null && typeof id === "object") {
7450
+ return rejection("signature_invalid", `payment-identifier: ${id.invalid}.`);
7451
+ }
7452
+ if (id === null) return routeVerdictObject(obj);
7453
+ const idKey = "pid:" + id;
7454
+ if (await claimTx(idKey)) {
7455
+ return rejection(
7456
+ "tx_already_used",
7457
+ `Idempotency id "${id}" is already bound to a settled payment; use a fresh id for a new payment.`
7458
+ );
7459
+ }
7460
+ let result;
7461
+ try {
7462
+ result = await routeVerdictObject(obj);
7463
+ } catch (err) {
7464
+ await settleTx(idKey, false);
7465
+ throw err;
7466
+ }
7467
+ await settleTx(idKey, result.kind === "paid");
7468
+ return result.kind === "paid" ? echoPaymentIdentifier(result, id) : result;
7469
+ }
7330
7470
  return { challenge, verify, verifyObject, describe, landingPage };
7331
7471
  }
7332
7472
  function requirePayment(options) {
@@ -7726,6 +7866,115 @@ function resourceUrlFromMessage(message) {
7726
7866
  }
7727
7867
  return "";
7728
7868
  }
7869
+
7870
+ // src/transports/mcp-types.ts
7871
+ var MCP_PAYMENT_META_KEY = "x402/payment";
7872
+ var MCP_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
7873
+
7874
+ // src/transports/mcp.ts
7875
+ function toMcpPaymentRequired(challenge) {
7876
+ const text = JSON.stringify(challenge);
7877
+ return {
7878
+ isError: true,
7879
+ structuredContent: challenge,
7880
+ content: [{ type: "text", text }]
7881
+ };
7882
+ }
7883
+ function toMcpPaymentResponse(content, receipt) {
7884
+ return {
7885
+ content,
7886
+ _meta: {
7887
+ [MCP_PAYMENT_RESPONSE_META_KEY]: {
7888
+ success: true,
7889
+ transaction: receipt.transaction,
7890
+ network: receipt.network,
7891
+ payer: receipt.payer
7892
+ }
7893
+ }
7894
+ };
7895
+ }
7896
+ function fromMcpPayment(params) {
7897
+ const meta = params?._meta?.[MCP_PAYMENT_META_KEY];
7898
+ return meta == null ? null : meta;
7899
+ }
7900
+ function fromMcpPaymentRequired(result) {
7901
+ if (!result || result.isError !== true) return null;
7902
+ const sc = result.structuredContent;
7903
+ if (sc && typeof sc === "object" && typeof sc.x402Version === "number") {
7904
+ return sc;
7905
+ }
7906
+ const text = result.content?.[0]?.text;
7907
+ if (typeof text === "string") {
7908
+ try {
7909
+ const parsed = JSON.parse(text);
7910
+ if (parsed && typeof parsed === "object" && typeof parsed.x402Version === "number") {
7911
+ return parsed;
7912
+ }
7913
+ } catch {
7914
+ }
7915
+ }
7916
+ return null;
7917
+ }
7918
+ function isMcpPaymentRequired(result) {
7919
+ return fromMcpPaymentRequired(result) != null;
7920
+ }
7921
+ function fromMcpPaymentResponse(result) {
7922
+ const meta = result?._meta?.[MCP_PAYMENT_RESPONSE_META_KEY];
7923
+ if (!meta || typeof meta !== "object") return null;
7924
+ return meta;
7925
+ }
7926
+ function buildMcpPaymentMeta(input) {
7927
+ return {
7928
+ [MCP_PAYMENT_META_KEY]: {
7929
+ x402Version: input.x402Version ?? 2,
7930
+ ...input.resource ? { resource: input.resource } : {},
7931
+ accepted: input.accepted,
7932
+ payload: input.payload
7933
+ }
7934
+ };
7935
+ }
7936
+ function createMcpPaymentTool(options) {
7937
+ const gate = options.gate ?? createPaymentGate(options);
7938
+ function settlementFailed(code, detail) {
7939
+ return {
7940
+ isError: true,
7941
+ content: [
7942
+ {
7943
+ type: "text",
7944
+ text: `x402 settlement failed (${toA2AErrorCode(code)}): ${detail}. The buyer can retry, or pay the onchain-proof rail directly.`
7945
+ }
7946
+ ]
7947
+ };
7948
+ }
7949
+ async function handleToolCall(params) {
7950
+ const raw = fromMcpPayment(params);
7951
+ if (raw == null) {
7952
+ const { challenge } = await gate.challenge(options.resourceUrl ?? "");
7953
+ return toMcpPaymentRequired(challenge);
7954
+ }
7955
+ let result;
7956
+ try {
7957
+ result = await gate.verifyObject(raw);
7958
+ } catch (err) {
7959
+ if (err instanceof SettlementError) return settlementFailed("settlement_failed", err.message);
7960
+ throw err;
7961
+ }
7962
+ if (result.kind === "paid") {
7963
+ try {
7964
+ const content = await options.fulfill({ receipt: result.receipt, params });
7965
+ return toMcpPaymentResponse(content, result.receipt);
7966
+ } catch (err) {
7967
+ const detail = err instanceof Error ? err.message : String(err);
7968
+ return toMcpPaymentResponse(
7969
+ [{ type: "text", text: `Payment settled (tx ${result.receipt.transaction}), but serving the result failed: ${detail}` }],
7970
+ result.receipt
7971
+ );
7972
+ }
7973
+ }
7974
+ return toMcpPaymentRequired(result.challenge);
7975
+ }
7976
+ return { handleToolCall, gate };
7977
+ }
7729
7978
  export {
7730
7979
  A2A_ERROR_KEY,
7731
7980
  A2A_EXTENSIONS_HEADER,
@@ -7744,6 +7993,7 @@ export {
7744
7993
  EIP3009_TYPES,
7745
7994
  EXACT_NETWORK_SLUGS,
7746
7995
  EXT_OFFER_RECEIPT,
7996
+ EXT_PAYMENT_IDENTIFIER,
7747
7997
  GENERATOR,
7748
7998
  HEADER_REQUIRED,
7749
7999
  HEADER_RESPONSE,
@@ -7751,8 +8001,11 @@ export {
7751
8001
  HEADER_SIGNATURE,
7752
8002
  HEADER_SIGNATURE_V1,
7753
8003
  InsufficientFundsError,
8004
+ InvalidConfigError,
7754
8005
  InvalidEnvelopeError,
7755
8006
  KNOWN_FACILITATORS,
8007
+ MCP_PAYMENT_META_KEY,
8008
+ MCP_PAYMENT_RESPONSE_META_KEY,
7756
8009
  MaxRetriesExceededError,
7757
8010
  MissingDriverError,
7758
8011
  MultiChainPayer,
@@ -7790,18 +8043,22 @@ export {
7790
8043
  buildEndpointInfo,
7791
8044
  buildExactAuthorization,
7792
8045
  buildExactSignatureHeader,
8046
+ buildMcpPaymentMeta,
7793
8047
  buildOpenApi,
8048
+ buildPaymentIdentifierAdvertisement,
7794
8049
  buildReceiptExtension,
7795
8050
  buildReceiptHeader,
7796
8051
  buildSelfDescription,
7797
8052
  buildSignatureHeader,
7798
8053
  buildUptoSignatureHeader,
7799
8054
  buildWellKnownX402,
8055
+ buildWellKnownX402Manifest,
7800
8056
  buildX402DnsTxt,
7801
8057
  chainIdForExactNetwork,
7802
8058
  claim402IndexDomain,
7803
8059
  classifyChallenge,
7804
8060
  createA2APaymentHandler,
8061
+ createMcpPaymentTool,
7805
8062
  createPaymentGate,
7806
8063
  decodeBase64Json,
7807
8064
  decorateOutcome,
@@ -7819,7 +8076,11 @@ export {
7819
8076
  formatSpendReport,
7820
8077
  fromA2APaymentPayload,
7821
8078
  fromA2APaymentRequired,
8079
+ fromMcpPayment,
8080
+ fromMcpPaymentRequired,
8081
+ fromMcpPaymentResponse,
7822
8082
  getDirectoryInfo,
8083
+ isMcpPaymentRequired,
7823
8084
  isPermit2ProxyChain,
7824
8085
  isUptoProxyChain,
7825
8086
  knownFacilitatorsFor,
@@ -7842,6 +8103,7 @@ export {
7842
8103
  planAcross,
7843
8104
  rankResources,
7844
8105
  readExactDomain,
8106
+ readPaymentIdentifier,
7845
8107
  register402Index,
7846
8108
  registerDriver,
7847
8109
  registerX402Scan,
@@ -7858,5 +8120,7 @@ export {
7858
8120
  toA2APaymentRequired,
7859
8121
  toInsufficientFundsError,
7860
8122
  toInvalidBody,
8123
+ toMcpPaymentRequired,
8124
+ toMcpPaymentResponse,
7861
8125
  verify402IndexDomain
7862
8126
  };