@piprail/sdk 2.7.0 → 2.9.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 (35) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +5 -3
  3. package/dist/{algorand-WB6PBJU4.js → algorand-AA3WXKW4.js} +1 -1
  4. package/dist/{algorand-TMA62DN2.cjs → algorand-FCEECDG6.cjs} +32 -32
  5. package/dist/{aptos-JQMZNTMD.cjs → aptos-GHJPO6JJ.cjs} +31 -31
  6. package/dist/{aptos-QAAXIUY3.js → aptos-LY67Q6QF.js} +1 -1
  7. package/dist/{chunk-JG6KRAW6.cjs → chunk-MWBT7MCE.cjs} +13 -1
  8. package/dist/chunk-O4UQOZ4Z.cjs +14 -0
  9. package/dist/{chunk-7XK22JSQ.js → chunk-SC2ZYDHD.js} +12 -0
  10. package/dist/chunk-SK3CB7UA.js +14 -0
  11. package/dist/index.cjs +754 -238
  12. package/dist/index.d.cts +2386 -2577
  13. package/dist/index.d.ts +2386 -2577
  14. package/dist/index.js +595 -79
  15. package/dist/ledger-BtzrfO-3.d.cts +658 -0
  16. package/dist/ledger-BtzrfO-3.d.ts +658 -0
  17. package/dist/{near-H5AQ253I.cjs → near-6KAQVVG2.cjs} +26 -26
  18. package/dist/{near-OTPQD6BI.js → near-FZBUICCS.js} +1 -1
  19. package/dist/node.cjs +38 -0
  20. package/dist/node.d.cts +16 -0
  21. package/dist/node.d.ts +16 -0
  22. package/dist/node.js +38 -0
  23. package/dist/{solana-3FMCWSEE.js → solana-ELUWO6N5.js} +33 -2
  24. package/dist/{solana-M3VOHCMO.cjs → solana-MYF4HBO4.cjs} +64 -33
  25. package/dist/{stellar-U5NCRIOJ.js → stellar-BEMT7UYF.js} +1 -1
  26. package/dist/{stellar-FW6C6FBE.cjs → stellar-SUKASK4N.cjs} +20 -20
  27. package/dist/{sui-Y53M4GUM.js → sui-F5JQ2N6I.js} +1 -1
  28. package/dist/{sui-47C2KEZI.cjs → sui-VE5LT7BL.cjs} +16 -16
  29. package/dist/{ton-5ZPT5PSP.js → ton-7GKCTC5H.js} +11 -7
  30. package/dist/{ton-MMPKWT6N.cjs → ton-AOR3EURW.cjs} +25 -21
  31. package/dist/{tron-JOT4STIG.cjs → tron-EMFXDFHW.cjs} +24 -24
  32. package/dist/{tron-WYS4X2I5.js → tron-ZZZS3FNN.js} +1 -1
  33. package/dist/{xrpl-2MZEOIFY.js → xrpl-DD7TJL5L.js} +1 -1
  34. package/dist/{xrpl-PECT4IMX.cjs → xrpl-Y6SQNYLC.cjs} +20 -20
  35. package/package.json +11 -1
package/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
2
2
 
3
+ var _chunkO4UQOZ4Zcjs = require('./chunk-O4UQOZ4Z.cjs');
3
4
 
4
5
 
5
6
 
@@ -24,7 +25,10 @@
24
25
 
25
26
 
26
27
 
27
- var _chunkJG6KRAW6cjs = require('./chunk-JG6KRAW6.cjs');
28
+
29
+
30
+
31
+ var _chunkMWBT7MCEcjs = require('./chunk-MWBT7MCE.cjs');
28
32
 
29
33
  // src/drivers/registry.ts
30
34
  var byFamily = /* @__PURE__ */ new Map();
@@ -53,13 +57,13 @@ function resolveNetwork(opts) {
53
57
  const family = familyForChain(opts.chain);
54
58
  const driver = byFamily.get(family);
55
59
  if (!driver) {
56
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedNetworkError)(
60
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedNetworkError)(
57
61
  `No driver registered for the "${family}" family \u2014 it may not be mounted yet (use the async resolveNetwork()).`
58
62
  );
59
63
  }
60
64
  const net = driver.resolve(opts);
61
65
  if (!net) {
62
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedNetworkError)(
66
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedNetworkError)(
63
67
  `The ${family} driver didn't recognise this chain input.`
64
68
  );
65
69
  }
@@ -320,12 +324,12 @@ function resolveChain(input, rpcUrlOverride) {
320
324
 
321
325
  var _accounts = require('viem/accounts');
322
326
  function createWalletAdapter(config, resolved) {
323
- _chunkJG6KRAW6cjs.assertNoLegacyWalletKey.call(void 0, config, "EVM");
327
+ _chunkMWBT7MCEcjs.assertNoLegacyWalletKey.call(void 0, config, "EVM");
324
328
  if ("key" in config) {
325
329
  const key = config.key;
326
330
  if (typeof key !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(key)) {
327
331
  const hint = typeof key === "string" && !key.startsWith("0x") ? " (got a non-0x string \u2014 a base58/seed key belongs to another family; pass { key } as the EVM chain's 0x\u2026 hex secret)." : " (expected 0x followed by 64 hex characters).";
328
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
332
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
329
333
  `chain is EVM; the wallet { key } is not a valid 0x\u2026 32-byte hex private key${hint}`
330
334
  );
331
335
  }
@@ -333,7 +337,7 @@ function createWalletAdapter(config, resolved) {
333
337
  try {
334
338
  account = _accounts.privateKeyToAccount.call(void 0, key);
335
339
  } catch (err) {
336
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
340
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
337
341
  `chain is EVM; the wallet { key } is not a valid 0x\u2026 32-byte hex private key: ${err instanceof Error ? err.message : String(err)}.`
338
342
  );
339
343
  }
@@ -343,12 +347,12 @@ function createWalletAdapter(config, resolved) {
343
347
  }
344
348
  const wc = config.walletClient;
345
349
  if (!wc.account) {
346
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
350
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
347
351
  "chain is EVM; the provided walletClient has no attached account. Use `createWalletClient({ account, chain, transport })`, or pass { key }."
348
352
  );
349
353
  }
350
354
  if (wc.chain && wc.chain.id !== resolved.chainId) {
351
- throw new (0, _chunkJG6KRAW6cjs.WrongChainError)(
355
+ throw new (0, _chunkMWBT7MCEcjs.WrongChainError)(
352
356
  `PipRailClient: walletClient is on chain ${wc.chain.id} but the SDK was configured with chain ${resolved.chainId}. They must match.`
353
357
  );
354
358
  }
@@ -678,7 +682,7 @@ async function payExactEvm(input) {
678
682
  code = void 0;
679
683
  }
680
684
  if (code && code !== "0x") {
681
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
685
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
682
686
  `exact buyer rail requires an EOA signer; ${account.address} is a contract / EIP-1271 / EIP-7702-delegated account (no recoverable ECDSA signature). Pay via onchain-proof.`
683
687
  );
684
688
  }
@@ -688,13 +692,13 @@ async function payExactEvm(input) {
688
692
  domain = await readExactDomain(publicClient, accept.asset);
689
693
  }
690
694
  if (!domain) {
691
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
695
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
692
696
  `exact: couldn't derive the EIP-712 domain for ${accept.asset} on ${accept.network}. Either it isn't an EIP-3009 token (USDT needs Permit2; native/plain ERC-20 aren't exact-payable) \u2014 pay via onchain-proof \u2014 OR your RPC couldn't read it (transient): if the gate advertised eip3009, pass a reliable rpcUrl and retry.`
693
697
  );
694
698
  }
695
699
  const g = globalThis.crypto;
696
700
  if (!_optionalChain([g, 'optionalAccess', _5 => _5.getRandomValues])) {
697
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
701
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
698
702
  "this runtime lacks Web Crypto (globalThis.crypto.getRandomValues); the exact rail needs a CSPRNG nonce."
699
703
  );
700
704
  }
@@ -951,7 +955,7 @@ async function verifyAndSettleExactEvm(input) {
951
955
  args: writeArgs
952
956
  });
953
957
  } catch (err) {
954
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
958
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
955
959
  `exact settle: the merchant relayer failed to broadcast transferWithAuthorization (${shorten(err instanceof Error ? err.message : String(err))}). The payer's authorization is still valid and unused \u2014 fund/fix the relayer and the payer can retry.`,
956
960
  { cause: err }
957
961
  );
@@ -963,7 +967,7 @@ async function verifyAndSettleExactEvm(input) {
963
967
  return { ok: false, error: "tx_reverted", detail: `Settlement tx ${txHash} reverted on-chain.` };
964
968
  }
965
969
  } catch (err) {
966
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
970
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
967
971
  `exact settle: broadcast ${txHash} but couldn't confirm it (${shorten(err instanceof Error ? err.message : String(err))}).`,
968
972
  { cause: err }
969
973
  );
@@ -1094,7 +1098,7 @@ function shorten2(msg) {
1094
1098
  function randomPermit2Nonce() {
1095
1099
  const g = globalThis.crypto;
1096
1100
  if (!_optionalChain([g, 'optionalAccess', _8 => _8.getRandomValues])) {
1097
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
1101
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
1098
1102
  "this runtime lacks Web Crypto (globalThis.crypto.getRandomValues); the permit2 rail needs a CSPRNG nonce."
1099
1103
  );
1100
1104
  }
@@ -1113,7 +1117,7 @@ async function ensurePermit2Allowance(input) {
1113
1117
  args: [account.address, PERMIT2_ADDRESS]
1114
1118
  });
1115
1119
  } catch (err) {
1116
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
1120
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
1117
1121
  `permit2: couldn't read the Permit2 allowance for ${token} (${shorten2(err instanceof Error ? err.message : String(err))}).`
1118
1122
  );
1119
1123
  }
@@ -1130,7 +1134,7 @@ async function ensurePermit2Allowance(input) {
1130
1134
  await publicClient.waitForTransactionReceipt({ hash, confirmations: 1 });
1131
1135
  return hash;
1132
1136
  } catch (err) {
1133
- throw _nullishCoalesce(_chunkJG6KRAW6cjs.toInsufficientFundsError.call(void 0, err), () => ( new (0, _chunkJG6KRAW6cjs.SettlementError)(
1137
+ throw _nullishCoalesce(_chunkMWBT7MCEcjs.toInsufficientFundsError.call(void 0, err), () => ( new (0, _chunkMWBT7MCEcjs.SettlementError)(
1134
1138
  `permit2: the one-time Permit2 approval for ${token} failed to broadcast (${shorten2(err instanceof Error ? err.message : String(err))}).`,
1135
1139
  { cause: err }
1136
1140
  )));
@@ -1145,7 +1149,7 @@ async function payPermit2Evm(input) {
1145
1149
  code = void 0;
1146
1150
  }
1147
1151
  if (code && code !== "0x") {
1148
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
1152
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
1149
1153
  `permit2 buyer rail requires an EOA signer; ${account.address} is a contract / EIP-1271 / EIP-7702-delegated account. Pay via onchain-proof.`
1150
1154
  );
1151
1155
  }
@@ -1320,7 +1324,7 @@ async function verifyAndSettlePermit2Evm(input) {
1320
1324
  args: settleArgs
1321
1325
  });
1322
1326
  } catch (err) {
1323
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
1327
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
1324
1328
  `permit2 settle: the merchant relayer failed to broadcast the proxy settle (${shorten2(err instanceof Error ? err.message : String(err))}). The payer's signature is still valid and its nonce unused \u2014 fund/fix the relayer and the payer can retry.`,
1325
1329
  { cause: err }
1326
1330
  );
@@ -1332,7 +1336,7 @@ async function verifyAndSettlePermit2Evm(input) {
1332
1336
  return { ok: false, error: "tx_reverted", detail: `Settlement tx ${txHash} reverted on-chain.` };
1333
1337
  }
1334
1338
  } catch (err) {
1335
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
1339
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
1336
1340
  `permit2 settle: broadcast ${txHash} but couldn't confirm it (${shorten2(err instanceof Error ? err.message : String(err))}).`,
1337
1341
  { cause: err }
1338
1342
  );
@@ -1584,15 +1588,15 @@ function makeEvmNetwork(resolved) {
1584
1588
  const info = resolved.tokens[token.toUpperCase()];
1585
1589
  if (!info) {
1586
1590
  const known = Object.keys(resolved.tokens).join(", ") || "(none built in)";
1587
- throw new (0, _chunkJG6KRAW6cjs.UnknownTokenError)(
1591
+ throw new (0, _chunkMWBT7MCEcjs.UnknownTokenError)(
1588
1592
  `token "${token}" isn't built in for ${resolved.chain.name} (known: ${known}). Pass { address, decimals } instead, or use 'native'.`
1589
1593
  );
1590
1594
  }
1591
1595
  return { asset: info.address, decimals: info.decimals, symbol: info.symbol };
1592
1596
  }
1593
- _chunkJG6KRAW6cjs.rejectForeignToken.call(void 0, token, "evm", network);
1597
+ _chunkMWBT7MCEcjs.rejectForeignToken.call(void 0, token, "evm", network);
1594
1598
  if (!("address" in token)) {
1595
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
1599
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
1596
1600
  `chain ${network} is EVM; a custom token must be { address, decimals }.`
1597
1601
  );
1598
1602
  }
@@ -1624,20 +1628,20 @@ function makeEvmNetwork(resolved) {
1624
1628
  },
1625
1629
  assertValidPayTo(payTo) {
1626
1630
  if (!_viem.isAddress.call(void 0, payTo)) {
1627
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
1631
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
1628
1632
  `chain ${network} is EVM, but payTo "${payTo}" is not a valid 0x address.`
1629
1633
  );
1630
1634
  }
1631
1635
  },
1632
1636
  bindWallet(wallet) {
1633
1637
  if (typeof wallet !== "object" || wallet === null) {
1634
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
1638
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
1635
1639
  `chain ${network} is EVM; wallet must be { key } (0x\u2026 hex) or { walletClient }.`
1636
1640
  );
1637
1641
  }
1638
- _chunkJG6KRAW6cjs.assertNoLegacyWalletKey.call(void 0, wallet, "EVM");
1642
+ _chunkMWBT7MCEcjs.assertNoLegacyWalletKey.call(void 0, wallet, "EVM");
1639
1643
  if (!("key" in wallet) && !("walletClient" in wallet)) {
1640
- throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
1644
+ throw new (0, _chunkMWBT7MCEcjs.WrongFamilyError)(
1641
1645
  `chain ${network} is EVM; wallet must be { key } (0x\u2026 hex) or { walletClient }.`
1642
1646
  );
1643
1647
  }
@@ -1654,12 +1658,12 @@ function makeEvmNetwork(resolved) {
1654
1658
  });
1655
1659
  } catch (err) {
1656
1660
  if (isViemInsufficientFunds(err)) {
1657
- throw new (0, _chunkJG6KRAW6cjs.InsufficientFundsError)(
1661
+ throw new (0, _chunkMWBT7MCEcjs.InsufficientFundsError)(
1658
1662
  err instanceof Error ? err.message : "Insufficient funds for payment.",
1659
1663
  { cause: err }
1660
1664
  );
1661
1665
  }
1662
- throw _nullishCoalesce(_chunkJG6KRAW6cjs.toInsufficientFundsError.call(void 0, err), () => ( err));
1666
+ throw _nullishCoalesce(_chunkMWBT7MCEcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
1663
1667
  }
1664
1668
  },
1665
1669
  async confirm(ref, minConfirmations) {
@@ -1670,7 +1674,7 @@ function makeEvmNetwork(resolved) {
1670
1674
  });
1671
1675
  return { height: receipt.blockNumber.toString() };
1672
1676
  } catch (err) {
1673
- throw new (0, _chunkJG6KRAW6cjs.ConfirmationTimeoutError)(
1677
+ throw new (0, _chunkMWBT7MCEcjs.ConfirmationTimeoutError)(
1674
1678
  `EVM tx ${ref} did not reach ${minConfirmations} confirmation(s) in time.`,
1675
1679
  { cause: err }
1676
1680
  );
@@ -1680,7 +1684,7 @@ function makeEvmNetwork(resolved) {
1680
1684
  const { decimals, symbol } = resolved.chain.nativeCurrency;
1681
1685
  if (accept.scheme === "exact") {
1682
1686
  const permit2 = accept.extra.assetTransferMethod === "permit2";
1683
- return _chunkJG6KRAW6cjs.nativeCost.call(void 0, {
1687
+ return _chunkMWBT7MCEcjs.nativeCost.call(void 0, {
1684
1688
  symbol,
1685
1689
  decimals,
1686
1690
  fee: 0n,
@@ -1691,7 +1695,7 @@ function makeEvmNetwork(resolved) {
1691
1695
  const gasLimit = accept.asset === "native" ? 21000n : 65000n;
1692
1696
  try {
1693
1697
  const gasPrice = await publicClient.getGasPrice();
1694
- return _chunkJG6KRAW6cjs.nativeCost.call(void 0, {
1698
+ return _chunkMWBT7MCEcjs.nativeCost.call(void 0, {
1695
1699
  symbol,
1696
1700
  decimals,
1697
1701
  fee: gasPrice * gasLimit,
@@ -1700,7 +1704,7 @@ function makeEvmNetwork(resolved) {
1700
1704
  });
1701
1705
  } catch (e20) {
1702
1706
  const gasPrice = 5000000000n;
1703
- return _chunkJG6KRAW6cjs.nativeCost.call(void 0, {
1707
+ return _chunkMWBT7MCEcjs.nativeCost.call(void 0, {
1704
1708
  symbol,
1705
1709
  decimals,
1706
1710
  fee: gasPrice * gasLimit,
@@ -1840,9 +1844,9 @@ var loaders = {
1840
1844
  solana: async () => {
1841
1845
  let mod;
1842
1846
  try {
1843
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-M3VOHCMO.cjs")));
1847
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./solana-MYF4HBO4.cjs")));
1844
1848
  } catch (cause) {
1845
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1849
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1846
1850
  `Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
1847
1851
  { cause }
1848
1852
  );
@@ -1852,9 +1856,9 @@ var loaders = {
1852
1856
  ton: async () => {
1853
1857
  let mod;
1854
1858
  try {
1855
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-MMPKWT6N.cjs")));
1859
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./ton-AOR3EURW.cjs")));
1856
1860
  } catch (cause) {
1857
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1861
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1858
1862
  `TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
1859
1863
  { cause }
1860
1864
  );
@@ -1864,9 +1868,9 @@ var loaders = {
1864
1868
  stellar: async () => {
1865
1869
  let mod;
1866
1870
  try {
1867
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-FW6C6FBE.cjs")));
1871
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./stellar-SUKASK4N.cjs")));
1868
1872
  } catch (cause) {
1869
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1873
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1870
1874
  `Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
1871
1875
  { cause }
1872
1876
  );
@@ -1876,9 +1880,9 @@ var loaders = {
1876
1880
  xrpl: async () => {
1877
1881
  let mod;
1878
1882
  try {
1879
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-PECT4IMX.cjs")));
1883
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./xrpl-Y6SQNYLC.cjs")));
1880
1884
  } catch (cause) {
1881
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1885
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1882
1886
  `XRPL selected, but its package isn't installed. Run: npm install xrpl`,
1883
1887
  { cause }
1884
1888
  );
@@ -1888,9 +1892,9 @@ var loaders = {
1888
1892
  tron: async () => {
1889
1893
  let mod;
1890
1894
  try {
1891
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-JOT4STIG.cjs")));
1895
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./tron-EMFXDFHW.cjs")));
1892
1896
  } catch (cause) {
1893
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1897
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1894
1898
  `Tron selected, but its package isn't installed. Run: npm install tronweb`,
1895
1899
  { cause }
1896
1900
  );
@@ -1900,9 +1904,9 @@ var loaders = {
1900
1904
  sui: async () => {
1901
1905
  let mod;
1902
1906
  try {
1903
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-47C2KEZI.cjs")));
1907
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./sui-VE5LT7BL.cjs")));
1904
1908
  } catch (cause) {
1905
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1909
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1906
1910
  `Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
1907
1911
  { cause }
1908
1912
  );
@@ -1912,9 +1916,9 @@ var loaders = {
1912
1916
  near: async () => {
1913
1917
  let mod;
1914
1918
  try {
1915
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-H5AQ253I.cjs")));
1919
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./near-6KAQVVG2.cjs")));
1916
1920
  } catch (cause) {
1917
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1921
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1918
1922
  `NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
1919
1923
  { cause }
1920
1924
  );
@@ -1924,9 +1928,9 @@ var loaders = {
1924
1928
  aptos: async () => {
1925
1929
  let mod;
1926
1930
  try {
1927
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-JQMZNTMD.cjs")));
1931
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./aptos-GHJPO6JJ.cjs")));
1928
1932
  } catch (cause) {
1929
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1933
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1930
1934
  `Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
1931
1935
  { cause }
1932
1936
  );
@@ -1936,9 +1940,9 @@ var loaders = {
1936
1940
  algorand: async () => {
1937
1941
  let mod;
1938
1942
  try {
1939
- mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-TMA62DN2.cjs")));
1943
+ mod = await Promise.resolve().then(() => _interopRequireWildcard(require("./algorand-FCEECDG6.cjs")));
1940
1944
  } catch (cause) {
1941
- throw new (0, _chunkJG6KRAW6cjs.MissingDriverError)(
1945
+ throw new (0, _chunkMWBT7MCEcjs.MissingDriverError)(
1942
1946
  `Algorand selected, but its package isn't installed. Run: npm install algosdk`,
1943
1947
  { cause }
1944
1948
  );
@@ -2027,7 +2031,7 @@ var SLUG_TO_CAIP2 = {
2027
2031
  bsc: "eip155:56",
2028
2032
  // non-EVM families — values mirror each driver's bound caip2 exactly
2029
2033
  solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
2030
- ton: "ton:-239",
2034
+ ton: "tvm:-239",
2031
2035
  tron: "tron:mainnet",
2032
2036
  near: "near:mainnet",
2033
2037
  sui: "sui:mainnet",
@@ -2036,7 +2040,12 @@ var SLUG_TO_CAIP2 = {
2036
2040
  stellar: "stellar:pubnet",
2037
2041
  xrpl: "xrpl:0"
2038
2042
  };
2043
+ var LEGACY_CAIP2_ALIAS = {
2044
+ "ton:-239": "tvm:-239"
2045
+ };
2039
2046
  function normalizeNetwork(network) {
2047
+ const legacy = LEGACY_CAIP2_ALIAS[network];
2048
+ if (legacy) return legacy;
2040
2049
  if (network.includes(":")) return network;
2041
2050
  return _nullishCoalesce(SLUG_TO_CAIP2[network.toLowerCase()], () => ( network));
2042
2051
  }
@@ -2577,6 +2586,53 @@ function encodeBase642(str) {
2577
2586
  }
2578
2587
 
2579
2588
  // src/policy.ts
2589
+ var DENOM_PRECISION = _chunkMWBT7MCEcjs.MAX_DECIMALS;
2590
+ var BUILTIN_DENOMS = {
2591
+ USDC: "USD",
2592
+ USDT: "USD",
2593
+ USD1: "USD",
2594
+ FDUSD: "USD",
2595
+ RLUSD: "USD",
2596
+ EURC: "EUR"
2597
+ };
2598
+ function denomOf(symbol, asset, policy) {
2599
+ if (asset === "native") return void 0;
2600
+ const norm = (v) => typeof v === "string" && v.trim() !== "" ? v.trim().toUpperCase() : void 0;
2601
+ const override = _optionalChain([policy, 'optionalAccess', _18 => _18.denomFor]);
2602
+ if (override && typeof override === "object") {
2603
+ if (asset && asset in override) {
2604
+ const d = norm(override[asset]);
2605
+ if (d) return d;
2606
+ }
2607
+ if (symbol) {
2608
+ const hit = Object.entries(override).find(([k]) => k.trim().toUpperCase() === symbol.trim().toUpperCase());
2609
+ if (hit) {
2610
+ const d = norm(hit[1]);
2611
+ if (d) return d;
2612
+ }
2613
+ }
2614
+ }
2615
+ if (symbol) {
2616
+ const builtin = BUILTIN_DENOMS[symbol.trim().toUpperCase()];
2617
+ if (builtin) return builtin;
2618
+ }
2619
+ return void 0;
2620
+ }
2621
+ function scaleToDenom(amountBase, decimals) {
2622
+ if (!Number.isSafeInteger(decimals) || decimals < 0 || decimals > DENOM_PRECISION) return null;
2623
+ return amountBase * 10n ** BigInt(DENOM_PRECISION - decimals);
2624
+ }
2625
+ function capForDenom(caps, denom) {
2626
+ if (!caps || typeof caps !== "object") return void 0;
2627
+ const target = denom.trim().toUpperCase();
2628
+ let best;
2629
+ for (const [k, v] of Object.entries(caps)) {
2630
+ if (typeof k !== "string" || typeof v !== "string") continue;
2631
+ if (k.trim().toUpperCase() !== target) continue;
2632
+ if (best === void 0 || Number(v) < Number(best)) best = v;
2633
+ }
2634
+ return best;
2635
+ }
2580
2636
  var ALLOW = { allowed: true };
2581
2637
  var deny = (code, reason) => ({
2582
2638
  allowed: false,
@@ -2643,7 +2699,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase, ctx) {
2643
2699
  }
2644
2700
  }
2645
2701
  if (policy.maxAmount !== void 0) {
2646
- const cap = _chunkJG6KRAW6cjs.floorUnits.call(void 0, policy.maxAmount, intent.decimals);
2702
+ const cap = _chunkMWBT7MCEcjs.floorUnits.call(void 0, policy.maxAmount, intent.decimals);
2647
2703
  if (intent.amountBase > cap) {
2648
2704
  return deny(
2649
2705
  "MAX_AMOUNT",
@@ -2652,7 +2708,7 @@ function evaluatePolicy(intent, policy, spentForAssetBase, ctx) {
2652
2708
  }
2653
2709
  }
2654
2710
  if (policy.maxTotal !== void 0) {
2655
- const cap = _chunkJG6KRAW6cjs.floorUnits.call(void 0, policy.maxTotal, intent.decimals);
2711
+ const cap = _chunkMWBT7MCEcjs.floorUnits.call(void 0, policy.maxTotal, intent.decimals);
2656
2712
  if (spentForAssetBase + intent.amountBase > cap) {
2657
2713
  return deny(
2658
2714
  "MAX_TOTAL",
@@ -2660,8 +2716,36 @@ function evaluatePolicy(intent, policy, spentForAssetBase, ctx) {
2660
2716
  );
2661
2717
  }
2662
2718
  }
2719
+ if (ctx && policy.maxTotalPerDenom) {
2720
+ const denom = denomOf(intent.symbol, intent.asset, policy);
2721
+ const capStr = denom ? capForDenom(policy.maxTotalPerDenom, denom) : void 0;
2722
+ if (denom && capStr !== void 0) {
2723
+ const thisScaled = scaleToDenom(intent.amountBase, intent.decimals);
2724
+ if (thisScaled === null) {
2725
+ return deny(
2726
+ "MAX_TOTAL_DENOM",
2727
+ `token for ${denom} has more than ${DENOM_PRECISION} decimals \u2014 refusing to count it toward policy.maxTotalPerDenom.${denom} on trust (it can't be summed safely).`
2728
+ );
2729
+ }
2730
+ const capScaled = _chunkMWBT7MCEcjs.floorUnits.call(void 0, capStr, DENOM_PRECISION);
2731
+ if ((_nullishCoalesce(ctx.spentInDenomScaled, () => ( 0n))) + thisScaled > capScaled) {
2732
+ return deny(
2733
+ "MAX_TOTAL_DENOM",
2734
+ `this payment would push total ${denom} spend past policy.maxTotalPerDenom.${denom} (${capStr}) \u2014 summed across every ${denom} token and chain.`
2735
+ );
2736
+ }
2737
+ }
2738
+ }
2739
+ if (ctx && policy.maxPayments !== void 0) {
2740
+ if ((_nullishCoalesce(ctx.paymentCount, () => ( 0))) + 1 > policy.maxPayments) {
2741
+ return deny(
2742
+ "MAX_PAYMENTS",
2743
+ `this payment would exceed policy.maxPayments (${policy.maxPayments}); already settled ${_nullishCoalesce(ctx.paymentCount, () => ( 0))}.`
2744
+ );
2745
+ }
2746
+ }
2663
2747
  if (ctx && policy.windowTotal !== void 0 && policy.windowSeconds !== void 0) {
2664
- const cap = _chunkJG6KRAW6cjs.floorUnits.call(void 0, policy.windowTotal, intent.decimals);
2748
+ const cap = _chunkMWBT7MCEcjs.floorUnits.call(void 0, policy.windowTotal, intent.decimals);
2665
2749
  if (ctx.spentInWindowBase + intent.amountBase > cap) {
2666
2750
  return deny(
2667
2751
  "WINDOW_TOTAL",
@@ -2669,44 +2753,150 @@ function evaluatePolicy(intent, policy, spentForAssetBase, ctx) {
2669
2753
  );
2670
2754
  }
2671
2755
  }
2756
+ if (ctx && policy.maxPaymentsPerWindow !== void 0 && policy.windowSeconds !== void 0) {
2757
+ if ((_nullishCoalesce(ctx.paymentCountInWindow, () => ( 0))) + 1 > policy.maxPaymentsPerWindow) {
2758
+ return deny(
2759
+ "WINDOW_COUNT",
2760
+ `this payment would exceed policy.maxPaymentsPerWindow (${policy.maxPaymentsPerWindow}) within the last ${policy.windowSeconds}s.`
2761
+ );
2762
+ }
2763
+ }
2672
2764
  return ALLOW;
2673
2765
  }
2674
2766
 
2675
2767
  // src/ledger.ts
2676
2768
  var keyFor = (network, asset) => `${network}|${asset}`;
2677
- var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this); }
2769
+ var SpendLedger = (_class = class {
2678
2770
  __init() {this.records = []}
2679
2771
  __init2() {this.buckets = /* @__PURE__ */ new Map()}
2772
+ /** Per-denomination running total, scaled to {@link DENOM_PRECISION}. Keyed by the
2773
+ * UPPERCASE denomination so lookups are case-insensitive. */
2774
+ __init3() {this.denomTotals = /* @__PURE__ */ new Map()}
2775
+ /** Threshold keys already warned (`warnAtFraction` fires once per crossing per cap).
2776
+ * Lives on the LEDGER — not the client — so clients SHARING one (a cross-chain
2777
+ * MultiChainPayer) dedupe together: a denomination/count threshold fires once across the
2778
+ * whole shared budget, not once per chain. */
2779
+ __init4() {this.warned = /* @__PURE__ */ new Set()}
2780
+
2680
2781
  /**
2681
2782
  * Session clock origin (epoch-ms) — process/session start = ledger
2682
2783
  * construction. In-memory; a new process is a new session. The client reads it
2683
2784
  * to compute the `ttlSeconds` deadline and the rolling-window slice.
2684
2785
  */
2685
- __init3() {this.sessionStart = Date.now()}
2686
- /** Record a settled payment. `decimals` is the TRUE token decimals (for the
2687
- * per-asset running total used by maxTotal + the formatted summary). */
2688
- record(r, decimals) {
2689
- this.records.push(r);
2690
- const key = keyFor(r.network, r.asset);
2786
+ __init5() {this.sessionStart = Date.now()}
2787
+ /**
2788
+ * @param store Optional durable {@link SpendStore}. When supplied, the ledger
2789
+ * HYDRATES from `store.load()` here (so prior spend resumes after a restart) and
2790
+ * `append()`s every settled payment. A throwing/absent store fails SAFE to an
2791
+ * empty in-memory ledger — it never blocks construction (ERRORS.md: never throw).
2792
+ */
2793
+ constructor(store) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);
2794
+ this.store = store;
2795
+ if (store) {
2796
+ let seed = [];
2797
+ try {
2798
+ seed = _nullishCoalesce(store.load(), () => ( []));
2799
+ } catch (e27) {
2800
+ seed = [];
2801
+ }
2802
+ for (const r of seed) this.ingest(r, _nullishCoalesce(_optionalChain([r, 'optionalAccess', _19 => _19.decimals]), () => ( 0)), _optionalChain([r, 'optionalAccess', _20 => _20.denom]));
2803
+ }
2804
+ }
2805
+ /**
2806
+ * A record is safe to tally iff its `amountBase` is a non-negative integer STRING and its
2807
+ * `decimals` is an integer in `[0, MAX_DECIMALS]`. The live `record()` path always passes
2808
+ * (the client validated the quote), but a hydrated record comes from an UNTRUSTED store
2809
+ * (a tampered/corrupt/future-version JSONL line), so we gate it here — a bad record is
2810
+ * dropped rather than allowed to throw `BigInt(...)`/`formatUnits(...)` later and brick a
2811
+ * read or the constructor.
2812
+ */
2813
+ isTallyable(r, decimals) {
2814
+ return !!r && typeof r.amountBase === "string" && /^\d+$/.test(r.amountBase) && Number.isInteger(decimals) && decimals >= 0 && decimals <= _chunkMWBT7MCEcjs.MAX_DECIMALS;
2815
+ }
2816
+ /** Apply a record to the in-memory tallies (records + per-asset bucket + denom total).
2817
+ * Shared by {@link record} and constructor hydration; does NOT persist. Returns the
2818
+ * stored record, or `null` when the record is corrupt and was skipped. */
2819
+ ingest(r, decimals, denom) {
2820
+ if (!this.isTallyable(r, decimals)) return null;
2821
+ const denomStr = typeof denom === "string" && denom.trim() !== "" ? denom : void 0;
2822
+ const rec = { ...r, decimals, ...denomStr ? { denom: denomStr } : {} };
2823
+ this.records.push(rec);
2824
+ const key = keyFor(rec.network, rec.asset);
2691
2825
  const bucket = this.buckets.get(key);
2692
2826
  if (bucket) {
2693
- bucket.total += BigInt(r.amountBase);
2827
+ bucket.total += BigInt(rec.amountBase);
2694
2828
  bucket.count += 1;
2695
- if (!bucket.symbol && r.symbol) bucket.symbol = r.symbol;
2829
+ if (!bucket.symbol && rec.symbol) bucket.symbol = rec.symbol;
2696
2830
  } else {
2697
2831
  this.buckets.set(key, {
2698
- network: r.network,
2699
- asset: r.asset,
2700
- symbol: r.symbol,
2832
+ network: rec.network,
2833
+ asset: rec.asset,
2834
+ symbol: rec.symbol,
2701
2835
  decimals,
2702
- total: BigInt(r.amountBase),
2836
+ total: BigInt(rec.amountBase),
2703
2837
  count: 1
2704
2838
  });
2705
2839
  }
2840
+ if (denomStr) {
2841
+ const scaled = scaleToDenom(BigInt(rec.amountBase), decimals);
2842
+ if (scaled !== null) {
2843
+ const k = denomStr.toUpperCase();
2844
+ this.denomTotals.set(k, (_nullishCoalesce(this.denomTotals.get(k), () => ( 0n))) + scaled);
2845
+ }
2846
+ }
2847
+ return rec;
2848
+ }
2849
+ /** Record a settled payment. `decimals` is the TRUE token decimals (for the
2850
+ * per-asset running total + the formatted summary). `denom` is the unit-of-account
2851
+ * the payment counts toward in the grand total (or omit for none). Persists to the
2852
+ * {@link SpendStore} when one is configured (a failed append never throws). */
2853
+ record(r, decimals, denom) {
2854
+ const rec = this.ingest(r, decimals, denom);
2855
+ if (rec && this.store) {
2856
+ try {
2857
+ this.store.append(rec);
2858
+ } catch (e28) {
2859
+ }
2860
+ }
2706
2861
  }
2707
2862
  /** Running total (base units) already spent on this (network, asset). */
2708
2863
  totalFor(network, asset) {
2709
- return _nullishCoalesce(_optionalChain([this, 'access', _18 => _18.buckets, 'access', _19 => _19.get, 'call', _20 => _20(keyFor(network, asset)), 'optionalAccess', _21 => _21.total]), () => ( 0n));
2864
+ return _nullishCoalesce(_optionalChain([this, 'access', _21 => _21.buckets, 'access', _22 => _22.get, 'call', _23 => _23(keyFor(network, asset)), 'optionalAccess', _24 => _24.total]), () => ( 0n));
2865
+ }
2866
+ /**
2867
+ * Running grand total for a DENOMINATION, scaled to {@link DENOM_PRECISION} (so
2868
+ * tokens of different decimals add up exactly). Summed across every token of that
2869
+ * denomination and every chain this ledger has seen. Powers `maxTotalPerDenom`.
2870
+ * `0n` for a denomination never spent on. Case-insensitive.
2871
+ */
2872
+ totalForDenom(denom) {
2873
+ return _nullishCoalesce(this.denomTotals.get(denom.toUpperCase()), () => ( 0n));
2874
+ }
2875
+ /** Total number of settled payments (across every chain + token). Powers `maxPayments`. */
2876
+ count() {
2877
+ return this.records.length;
2878
+ }
2879
+ /** Mark a `warnAtFraction` threshold key as fired; returns `true` the FIRST time (so the
2880
+ * caller emits the `budget-threshold` event once) and `false` thereafter. Shared across
2881
+ * every client on this ledger, so a cross-chain threshold fires once for the whole budget. */
2882
+ markWarned(key) {
2883
+ if (this.warned.has(key)) return false;
2884
+ this.warned.add(key);
2885
+ return true;
2886
+ }
2887
+ /**
2888
+ * Number of settled payments whose `at` (ISO) is at or after `sinceMs` (epoch-ms),
2889
+ * across every chain + token. Backs the rolling payment-count cap
2890
+ * (`maxPaymentsPerWindow`, `sinceMs = now - windowSeconds*1000`). Linear scan —
2891
+ * negligible at agent-session cardinality and only when a window count cap is set.
2892
+ */
2893
+ countSince(sinceMs) {
2894
+ let n = 0;
2895
+ for (const r of this.records) {
2896
+ const t = Date.parse(r.at);
2897
+ if (Number.isNaN(t) || t >= sinceMs) n += 1;
2898
+ }
2899
+ return n;
2710
2900
  }
2711
2901
  /**
2712
2902
  * Sum of base-unit amounts for (network, asset) whose record `at` (ISO
@@ -2718,9 +2908,9 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
2718
2908
  totalSince(network, asset, sinceMs) {
2719
2909
  let sum = 0n;
2720
2910
  for (const r of this.records) {
2721
- if (r.network === network && r.asset === asset && Date.parse(r.at) >= sinceMs) {
2722
- sum += BigInt(r.amountBase);
2723
- }
2911
+ if (r.network !== network || r.asset !== asset) continue;
2912
+ const t = Date.parse(r.at);
2913
+ if (Number.isNaN(t) || t >= sinceMs) sum += BigInt(r.amountBase);
2724
2914
  }
2725
2915
  return sum;
2726
2916
  }
@@ -2740,6 +2930,14 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
2740
2930
  totalBase: b.total
2741
2931
  }));
2742
2932
  }
2933
+ /**
2934
+ * The per-denomination grand totals, as read-only tuples — `denom` and the running
2935
+ * `totalScaled` (at {@link DENOM_PRECISION}). Lets the client compose the grand-total
2936
+ * budget view; the cap math lives in the client. A never-spent denomination is absent.
2937
+ */
2938
+ denomBuckets() {
2939
+ return [...this.denomTotals.entries()].map(([denom, totalScaled]) => ({ denom, totalScaled }));
2940
+ }
2743
2941
  /** An immutable snapshot of all spend so far. */
2744
2942
  summary() {
2745
2943
  return {
@@ -2750,9 +2948,15 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
2750
2948
  symbol: b.symbol,
2751
2949
  decimals: b.decimals,
2752
2950
  totalBase: b.total.toString(),
2753
- totalFormatted: _chunkJG6KRAW6cjs.formatUnits.call(void 0, b.total, b.decimals),
2951
+ totalFormatted: _chunkMWBT7MCEcjs.formatUnits.call(void 0, b.total, b.decimals),
2754
2952
  count: b.count
2755
2953
  })),
2954
+ byDenom: [...this.denomTotals.entries()].map(([denom, scaled]) => ({
2955
+ denom,
2956
+ totalScaled: scaled.toString(),
2957
+ totalFormatted: _chunkMWBT7MCEcjs.formatUnits.call(void 0, scaled, DENOM_PRECISION),
2958
+ count: this.records.filter((r) => _optionalChain([r, 'access', _25 => _25.denom, 'optionalAccess', _26 => _26.toUpperCase, 'call', _27 => _27()]) === denom).length
2959
+ })),
2756
2960
  records: [...this.records]
2757
2961
  };
2758
2962
  }
@@ -2766,24 +2970,36 @@ var RECIPIENT_FIX = {
2766
2970
  NOT_OPTED_IN: "the recipient must opt into this asset once (a 0-amount self-transfer)",
2767
2971
  INACTIVE: "the recipient account doesn't exist yet \u2014 fund it with the chain's base reserve to activate it"
2768
2972
  };
2769
- var PipRailClient = (_class2 = class {
2973
+ var PipRailClient = class {
2974
+
2770
2975
 
2771
2976
 
2772
2977
 
2978
+ // Per-asset (+ per-denomination + count) tally of everything this client has paid —
2979
+ // powers spent()/budget() and the maxTotal/maxTotalPerDenom/maxPayments caps. Either
2980
+ // its own (optionally store-backed) ledger, or a SHARED one injected so the grand
2981
+ // total + count caps span several chains (MultiChainPayer.fromWallets).
2773
2982
 
2774
- // Per-asset tally of everything this client has paid (powers spent() and the
2775
- // policy's maxTotal cap).
2776
- __init4() {this.ledger = new SpendLedger()}
2983
+ // `warnAtFraction` threshold dedup lives on the LEDGER (`ledger.markWarned`), so clients
2984
+ // sharing one ledger (a cross-chain MultiChainPayer) fire each threshold once for the whole
2985
+ // shared budget not once per chain.
2777
2986
  // Resolved lazily on first request — this is what lets Solana (and future
2778
2987
  // families) auto-mount with no setup call.
2779
2988
 
2780
- constructor(opts) {;_class2.prototype.__init4.call(this);
2989
+ constructor(opts) {
2781
2990
  this.opts = opts;
2782
2991
  this.maxRetries = Math.max(1, _nullishCoalesce(opts.maxPaymentRetries, () => ( 3)));
2783
2992
  this.retryTimeoutMs = _nullishCoalesce(opts.retryTimeoutMs, () => ( 3e4));
2784
2993
  this.onEvent = _nullishCoalesce(opts.onEvent, () => ( (() => void 0)));
2994
+ if (opts.ledger && opts.spendStore) {
2995
+ throw new TypeError(
2996
+ "Pass either `ledger` (a shared SpendLedger) or `spendStore`, not both \u2014 a shared ledger already owns its store."
2997
+ );
2998
+ }
2999
+ this.ledger = _nullishCoalesce(opts.ledger, () => ( new SpendLedger(opts.spendStore)));
2785
3000
  this.assertPolicyAmountCaps(opts.policy);
2786
3001
  this.assertPolicyTimeOptions(opts.policy);
3002
+ this.assertPolicySpendControls(opts.policy);
2787
3003
  }
2788
3004
  /**
2789
3005
  * Fail LOUDLY at construction on a malformed amount cap — a security boundary
@@ -2804,6 +3020,65 @@ var PipRailClient = (_class2 = class {
2804
3020
  );
2805
3021
  }
2806
3022
  }
3023
+ if (policy.maxTotalPerDenom !== void 0) {
3024
+ const m = policy.maxTotalPerDenom;
3025
+ const proto = m && typeof m === "object" ? Object.getPrototypeOf(m) : false;
3026
+ if (!m || typeof m !== "object" || Array.isArray(m) || proto !== Object.prototype && proto !== null) {
3027
+ throw new TypeError(
3028
+ `policy.maxTotalPerDenom must be a plain { DENOM: amount } object (e.g. { USD: '20.00' }); got ${JSON.stringify(policy.maxTotalPerDenom)}.`
3029
+ );
3030
+ }
3031
+ for (const [denom, v] of Object.entries(policy.maxTotalPerDenom)) {
3032
+ if (denom.trim() === "") {
3033
+ throw new TypeError("policy.maxTotalPerDenom has a blank denomination key.");
3034
+ }
3035
+ if (typeof v !== "string" || !/^\d+(\.\d+)?$/.test(v)) {
3036
+ throw new TypeError(
3037
+ `policy.maxTotalPerDenom.${denom} must be a non-negative decimal string (e.g. '20.00'); got ${JSON.stringify(v)}.`
3038
+ );
3039
+ }
3040
+ }
3041
+ }
3042
+ if (policy.denomFor !== void 0) {
3043
+ const m = policy.denomFor;
3044
+ if (!m || typeof m !== "object" || Array.isArray(m)) {
3045
+ throw new TypeError(`policy.denomFor must be a { token: DENOM } object; got ${JSON.stringify(m)}.`);
3046
+ }
3047
+ for (const [k, v] of Object.entries(policy.denomFor)) {
3048
+ if (typeof v !== "string" || v.trim() === "") {
3049
+ throw new TypeError(`policy.denomFor.${k} must be a non-empty denomination string; got ${JSON.stringify(v)}.`);
3050
+ }
3051
+ }
3052
+ }
3053
+ }
3054
+ /**
3055
+ * Fail LOUDLY at construction on a misconfigured count / threshold control (a
3056
+ * programmer error → `TypeError`): payment counts must be positive safe integers,
3057
+ * `maxPaymentsPerWindow` needs `windowSeconds` (it shares the window), and
3058
+ * `warnAtFraction` must be in (0, 1].
3059
+ */
3060
+ assertPolicySpendControls(policy) {
3061
+ if (!policy) return;
3062
+ for (const field of ["maxPayments", "maxPaymentsPerWindow"]) {
3063
+ const v = policy[field];
3064
+ if (v === void 0) continue;
3065
+ if (!Number.isSafeInteger(v) || v <= 0) {
3066
+ throw new TypeError(`policy.${field} must be a positive integer; got ${JSON.stringify(v)}.`);
3067
+ }
3068
+ }
3069
+ if (policy.maxPaymentsPerWindow !== void 0 && policy.windowSeconds === void 0) {
3070
+ throw new TypeError(
3071
+ "policy.maxPaymentsPerWindow needs policy.windowSeconds (the rolling window it counts within) \u2014 set both, or neither."
3072
+ );
3073
+ }
3074
+ if (policy.warnAtFraction !== void 0) {
3075
+ const f = policy.warnAtFraction;
3076
+ if (typeof f !== "number" || !(f > 0 && f <= 1)) {
3077
+ throw new TypeError(
3078
+ `policy.warnAtFraction must be a number in (0, 1] (e.g. 0.8); got ${JSON.stringify(f)}.`
3079
+ );
3080
+ }
3081
+ }
2807
3082
  }
2808
3083
  /**
2809
3084
  * Fail LOUDLY at construction on a misconfigured time policy — a security
@@ -2818,11 +3093,17 @@ var PipRailClient = (_class2 = class {
2818
3093
  if (!policy) return;
2819
3094
  const hasWindowTotal = policy.windowTotal !== void 0;
2820
3095
  const hasWindowSeconds = policy.windowSeconds !== void 0;
2821
- if (hasWindowTotal !== hasWindowSeconds) {
3096
+ const hasWindowCount = policy.maxPaymentsPerWindow !== void 0;
3097
+ if (hasWindowTotal && !hasWindowSeconds) {
2822
3098
  throw new TypeError(
2823
3099
  "policy.windowTotal and policy.windowSeconds must be set together \u2014 a rolling-window cap can't be half-armed (set both, or neither)."
2824
3100
  );
2825
3101
  }
3102
+ if (hasWindowSeconds && !hasWindowTotal && !hasWindowCount) {
3103
+ throw new TypeError(
3104
+ "policy.windowSeconds must be set together with policy.windowTotal and/or policy.maxPaymentsPerWindow \u2014 a window width alone bounds nothing."
3105
+ );
3106
+ }
2826
3107
  if (hasWindowSeconds && !(Number.isSafeInteger(policy.windowSeconds) && policy.windowSeconds > 0)) {
2827
3108
  throw new TypeError("policy.windowSeconds must be a positive integer number of seconds.");
2828
3109
  }
@@ -2834,13 +3115,21 @@ var PipRailClient = (_class2 = class {
2834
3115
  );
2835
3116
  }
2836
3117
  }
3118
+ if (policy.expiresAt !== void 0) {
3119
+ const at = policy.expiresAt;
3120
+ if (!Number.isSafeInteger(at) || Math.abs(at) > 864e13) {
3121
+ throw new TypeError(
3122
+ `policy.expiresAt must be an absolute epoch-MILLISECONDS integer (like Date.now()); got ${JSON.stringify(at)}.`
3123
+ );
3124
+ }
3125
+ }
2837
3126
  }
2838
3127
  /** Emit an observability event, never letting a throwing handler break the
2839
3128
  * payment flow (mirrors the server gate's `onPaid` isolation). */
2840
3129
  safeEmit(event) {
2841
3130
  try {
2842
3131
  this.onEvent(event);
2843
- } catch (e27) {
3132
+ } catch (e29) {
2844
3133
  }
2845
3134
  }
2846
3135
  /** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
@@ -2870,7 +3159,7 @@ var PipRailClient = (_class2 = class {
2870
3159
  * as-is) or a plain object (serialised as JSON).
2871
3160
  */
2872
3161
  post(url, body, init) {
2873
- const headers = new Headers(_optionalChain([init, 'optionalAccess', _22 => _22.headers]));
3162
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _28 => _28.headers]));
2874
3163
  let payload;
2875
3164
  if (body === void 0 || body === null) {
2876
3165
  payload = void 0;
@@ -2901,7 +3190,7 @@ var PipRailClient = (_class2 = class {
2901
3190
  * "0.05 USDC on Base, within budget → pay it." No funds move.
2902
3191
  */
2903
3192
  async quote(url, init) {
2904
- const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _23 => _23.method]), () => ( "GET")) });
3193
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _29 => _29.method]), () => ( "GET")) });
2905
3194
  if (res.status !== 402) return null;
2906
3195
  const { quote } = await this.resolveChallenge(url, res, this.resolveSchemes());
2907
3196
  return quote;
@@ -2920,22 +3209,32 @@ var PipRailClient = (_class2 = class {
2920
3209
  * on Tron, where a USD₮ transfer can cost real TRX.
2921
3210
  */
2922
3211
  async estimateCost(url, init) {
2923
- const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _24 => _24.method]), () => ( "GET")) });
3212
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _30 => _30.method]), () => ( "GET")) });
2924
3213
  if (res.status !== 402) return null;
2925
3214
  const { net, accept, quote } = await this.resolveChallenge(url, res, this.resolveSchemes());
2926
3215
  const cost = await net.estimateCost(accept);
2927
3216
  return { quote, cost };
2928
3217
  }
2929
3218
  /** Aggregated snapshot of every payment this client has settled — total
2930
- * count, cumulative spend per token, and the individual records. */
3219
+ * count, cumulative spend per token, cumulative spend per denomination (the
3220
+ * cross-token grand total), and the individual records. */
2931
3221
  spent() {
2932
3222
  return this.ledger.summary();
2933
3223
  }
3224
+ /** The CONFIGURED spend policy, read back unchanged — so an agent can self-check
3225
+ * its WHOLE leash (caps, allowlists, time, denom + count limits) without hitting a
3226
+ * decline. `undefined` when no policy is set. Pure; never throws. */
3227
+ policy() {
3228
+ return this.opts.policy;
3229
+ }
2934
3230
  /**
2935
3231
  * Read-only budget + time leash for a Mode-A (headless) agent — the policy IS
2936
3232
  * the consent, and this is how the agent SEES what's left of it before paying.
2937
- * Composes the in-memory ledger with the configured policy; never throws, moves
2938
- * no funds. PROCESS-SCOPED every figure resets on restart (see {@link SessionBudget}).
3233
+ * Composes the ledger with the configured policy: the per-asset money leash
3234
+ * (`byAsset`), the cross-token GRAND TOTAL per denomination (`byDenom`, present
3235
+ * from the start), and the payment-COUNT leash (`counts`). Never throws, moves no
3236
+ * funds. The money/count figures persist if a `spendStore` is set; the time
3237
+ * envelope is process-scoped (see {@link SessionBudget}).
2939
3238
  */
2940
3239
  budget() {
2941
3240
  const view = this.sessionView();
@@ -2943,12 +3242,57 @@ var PipRailClient = (_class2 = class {
2943
3242
  return {
2944
3243
  session: {
2945
3244
  start,
2946
- expiresAt: _optionalChain([view, 'optionalAccess', _25 => _25.expiresAt]) != null ? new Date(view.expiresAt).toISOString() : null,
2947
- secondsRemaining: _nullishCoalesce(_optionalChain([view, 'optionalAccess', _26 => _26.secondsRemaining]), () => ( null))
3245
+ expiresAt: _optionalChain([view, 'optionalAccess', _31 => _31.expiresAt]) != null ? new Date(view.expiresAt).toISOString() : null,
3246
+ secondsRemaining: _nullishCoalesce(_optionalChain([view, 'optionalAccess', _32 => _32.secondsRemaining]), () => ( null))
2948
3247
  },
2949
- byAsset: this.remaining()
3248
+ byAsset: this.remaining(),
3249
+ byDenom: this.denomRemaining(),
3250
+ counts: this.countStatus()
2950
3251
  };
2951
3252
  }
3253
+ /**
3254
+ * The cross-token GRAND-TOTAL leash — one row per denomination capped by
3255
+ * `policy.maxTotalPerDenom`. Unlike `remaining()`, rows exist from the START
3256
+ * (the cap is a single declared number, so headroom is previewable before any
3257
+ * spend). `[]` when no `maxTotalPerDenom` is set. Pure; never throws; never a
3258
+ * price-converted figure (tokens grouped as one unit, each 1:1).
3259
+ */
3260
+ denomRemaining() {
3261
+ const caps = _optionalChain([this, 'access', _33 => _33.opts, 'access', _34 => _34.policy, 'optionalAccess', _35 => _35.maxTotalPerDenom]);
3262
+ if (!caps) return [];
3263
+ return Object.entries(caps).map(([rawDenom, capStr]) => {
3264
+ const denom = rawDenom.toUpperCase();
3265
+ const spentScaled = this.ledger.totalForDenom(denom);
3266
+ const capScaled = _chunkMWBT7MCEcjs.floorUnits.call(void 0, capStr, DENOM_PRECISION);
3267
+ const remainingScaled = capScaled > spentScaled ? capScaled - spentScaled : 0n;
3268
+ const fraction = capScaled === 0n ? spentScaled > 0n ? 1 : 0 : Number(spentScaled * 1000000n / capScaled) / 1e6;
3269
+ return {
3270
+ denom,
3271
+ spentFormatted: _chunkMWBT7MCEcjs.formatUnits.call(void 0, spentScaled, DENOM_PRECISION),
3272
+ capFormatted: _chunkMWBT7MCEcjs.formatUnits.call(void 0, capScaled, DENOM_PRECISION),
3273
+ remainingFormatted: _chunkMWBT7MCEcjs.formatUnits.call(void 0, remainingScaled, DENOM_PRECISION),
3274
+ fraction
3275
+ };
3276
+ });
3277
+ }
3278
+ /** The payment-COUNT leash — settled count so far + the configured lifetime/window
3279
+ * caps and what's left. Pure; never throws. */
3280
+ countStatus() {
3281
+ const policy = this.opts.policy;
3282
+ const settled = this.ledger.count();
3283
+ const out = { settled };
3284
+ if (_optionalChain([policy, 'optionalAccess', _36 => _36.maxPayments]) !== void 0) {
3285
+ out.lifetimeCap = policy.maxPayments;
3286
+ out.lifetimeRemaining = Math.max(0, policy.maxPayments - settled);
3287
+ }
3288
+ if (_optionalChain([policy, 'optionalAccess', _37 => _37.maxPaymentsPerWindow]) !== void 0 && policy.windowSeconds !== void 0) {
3289
+ const windowSettled = this.ledger.countSince(Date.now() - policy.windowSeconds * 1e3);
3290
+ out.windowCap = policy.maxPaymentsPerWindow;
3291
+ out.windowSettled = windowSettled;
3292
+ out.windowRemaining = Math.max(0, policy.maxPaymentsPerWindow - windowSettled);
3293
+ }
3294
+ return out;
3295
+ }
2952
3296
  /**
2953
3297
  * Per-(network, asset) remaining budget — ONE row per pair the ledger already
2954
3298
  * holds (decimals are known only after the first spend), so a fresh client with
@@ -2957,7 +3301,7 @@ var PipRailClient = (_class2 = class {
2957
3301
  * never throws, never sums across tokens (no price oracle). PROCESS-SCOPED.
2958
3302
  */
2959
3303
  remaining() {
2960
- const maxTotal = _optionalChain([this, 'access', _27 => _27.opts, 'access', _28 => _28.policy, 'optionalAccess', _29 => _29.maxTotal]);
3304
+ const maxTotal = _optionalChain([this, 'access', _38 => _38.opts, 'access', _39 => _39.policy, 'optionalAccess', _40 => _40.maxTotal]);
2961
3305
  return this.ledger.assetBuckets().map((b) => {
2962
3306
  const base2 = {
2963
3307
  network: b.network,
@@ -2967,13 +3311,13 @@ var PipRailClient = (_class2 = class {
2967
3311
  spentBase: b.totalBase.toString()
2968
3312
  };
2969
3313
  if (maxTotal === void 0) return base2;
2970
- const capBase = _chunkJG6KRAW6cjs.floorUnits.call(void 0, maxTotal, b.decimals);
3314
+ const capBase = _chunkMWBT7MCEcjs.floorUnits.call(void 0, maxTotal, b.decimals);
2971
3315
  const remainingBase = capBase > b.totalBase ? capBase - b.totalBase : 0n;
2972
3316
  return {
2973
3317
  ...base2,
2974
3318
  capBase: capBase.toString(),
2975
3319
  remainingBase: remainingBase.toString(),
2976
- remainingFormatted: _chunkJG6KRAW6cjs.formatUnits.call(void 0, remainingBase, b.decimals)
3320
+ remainingFormatted: _chunkMWBT7MCEcjs.formatUnits.call(void 0, remainingBase, b.decimals)
2977
3321
  };
2978
3322
  });
2979
3323
  }
@@ -3009,15 +3353,15 @@ var PipRailClient = (_class2 = class {
3009
3353
  * the plan yourself. No funds move.
3010
3354
  */
3011
3355
  async planPayment(url, init) {
3012
- const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _30 => _30.method]), () => ( "GET")) });
3356
+ const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _41 => _41.method]), () => ( "GET")) });
3013
3357
  if (res.status !== 402) return null;
3014
3358
  const challenge = await parseChallenge(res);
3015
3359
  if (!challenge) {
3016
- throw new (0, _chunkJG6KRAW6cjs.InvalidEnvelopeError)("402 response did not include a parseable x402 challenge.");
3360
+ throw new (0, _chunkMWBT7MCEcjs.InvalidEnvelopeError)("402 response did not include a parseable x402 challenge.");
3017
3361
  }
3018
3362
  const { net, wallet } = await this.ensure();
3019
3363
  if (!wallet) {
3020
- throw new (0, _chunkJG6KRAW6cjs.WalletRequiredError)(
3364
+ throw new (0, _chunkMWBT7MCEcjs.WalletRequiredError)(
3021
3365
  "planPayment needs a wallet (it checks YOUR balance, gas, and recipient-readiness). This client is read-only \u2014 construct it with a `wallet` to plan or pay."
3022
3366
  );
3023
3367
  }
@@ -3190,31 +3534,31 @@ var PipRailClient = (_class2 = class {
3190
3534
  * streams throw `NonReplayableBodyError`.
3191
3535
  */
3192
3536
  async fetch(url, init) {
3193
- const body = _optionalChain([init, 'optionalAccess', _31 => _31.body]);
3537
+ const body = _optionalChain([init, 'optionalAccess', _42 => _42.body]);
3194
3538
  if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
3195
- throw new (0, _chunkJG6KRAW6cjs.NonReplayableBodyError)(
3539
+ throw new (0, _chunkMWBT7MCEcjs.NonReplayableBodyError)(
3196
3540
  "fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
3197
3541
  );
3198
3542
  }
3199
3543
  const firstResponse = await fetch(url, init);
3200
3544
  if (firstResponse.status !== 402) return firstResponse;
3201
- const schemes = this.resolveSchemes(_optionalChain([init, 'optionalAccess', _32 => _32.schemes]));
3545
+ const schemes = this.resolveSchemes(_optionalChain([init, 'optionalAccess', _43 => _43.schemes]));
3202
3546
  const resolved = await this.resolveChallenge(url, firstResponse, schemes);
3203
3547
  const { net, wallet, challenge } = resolved;
3204
3548
  if (!wallet) {
3205
- throw new (0, _chunkJG6KRAW6cjs.WalletRequiredError)(
3549
+ throw new (0, _chunkMWBT7MCEcjs.WalletRequiredError)(
3206
3550
  "Paying a 402 needs a wallet to sign + settle. This client is read-only \u2014 construct it with a `wallet` to pay (quote/discover/register still work without one)."
3207
3551
  );
3208
3552
  }
3209
3553
  let accept = resolved.accept;
3210
3554
  let quote = resolved.quote;
3211
- const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _33 => _33.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
3555
+ const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _44 => _44.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
3212
3556
  if (autoRoute) {
3213
3557
  const plan = await this.planFromChallenge(net, wallet, challenge, url, schemes);
3214
3558
  if (!plan.best) {
3215
3559
  const reason = _nullishCoalesce(plan.fundingHint, () => ( "No rail is settleable for this payment."));
3216
3560
  this.safeEmit({ kind: "payment-failed", reason });
3217
- throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason);
3561
+ throw new (0, _chunkMWBT7MCEcjs.PaymentDeclinedError)(reason);
3218
3562
  }
3219
3563
  accept = plan.best.accept;
3220
3564
  quote = plan.best.quote;
@@ -3238,7 +3582,7 @@ var PipRailClient = (_class2 = class {
3238
3582
  async resolveChallenge(url, response, schemes) {
3239
3583
  const challenge = await parseChallenge(response);
3240
3584
  if (!challenge) {
3241
- throw new (0, _chunkJG6KRAW6cjs.InvalidEnvelopeError)(
3585
+ throw new (0, _chunkMWBT7MCEcjs.InvalidEnvelopeError)(
3242
3586
  "402 response did not include a parseable x402 challenge."
3243
3587
  );
3244
3588
  }
@@ -3249,7 +3593,7 @@ var PipRailClient = (_class2 = class {
3249
3593
  (a) => a.scheme === "exact" && this.supportsNetwork(net, a.network)
3250
3594
  );
3251
3595
  if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
3252
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
3596
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
3253
3597
  `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.`
3254
3598
  );
3255
3599
  }
@@ -3258,13 +3602,13 @@ var PipRailClient = (_class2 = class {
3258
3602
  (a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && net.describeAsset(a.asset) != null
3259
3603
  );
3260
3604
  if (payable) {
3261
- throw new (0, _chunkJG6KRAW6cjs.NoCompatibleAcceptError)(
3605
+ throw new (0, _chunkMWBT7MCEcjs.NoCompatibleAcceptError)(
3262
3606
  `This 402 is payable only via the standard 'exact' rail on ${net.network}, which is OFF by default. Enable it: new PipRailClient({ \u2026, schemes: ['onchain-proof', 'exact'] }) or per call fetch(url, { schemes: ['exact'] }) (MCP: PIPRAIL_SCHEMES=onchain-proof,exact).`
3263
3607
  );
3264
3608
  }
3265
3609
  }
3266
3610
  const networks = [...new Set(challenge.accepts.map((a) => a.network))].join(", ");
3267
- throw new (0, _chunkJG6KRAW6cjs.NoCompatibleAcceptError)(
3611
+ throw new (0, _chunkMWBT7MCEcjs.NoCompatibleAcceptError)(
3268
3612
  `No accepts[] entry payable by this client on ${net.network} (schemes: ${schemes.join(", ")}; challenge offered: ${networks || "none"}).`
3269
3613
  );
3270
3614
  }
@@ -3366,7 +3710,7 @@ var PipRailClient = (_class2 = class {
3366
3710
  const shortfall = {};
3367
3711
  if (!quote.withinPolicy) {
3368
3712
  blockers.push(
3369
- quote.policyCode === "SESSION_EXPIRED" || quote.policyCode === "WINDOW_TOTAL" ? "OUTSIDE_WINDOW" : "OUTSIDE_POLICY"
3713
+ quote.policyCode === "SESSION_EXPIRED" || quote.policyCode === "WINDOW_TOTAL" || quote.policyCode === "WINDOW_COUNT" ? "OUTSIDE_WINDOW" : "OUTSIDE_POLICY"
3370
3714
  );
3371
3715
  }
3372
3716
  if (quote.symbolMismatch) warnings.push("SYMBOL_MISMATCH");
@@ -3377,21 +3721,21 @@ var PipRailClient = (_class2 = class {
3377
3721
  if (isExact) {
3378
3722
  if (tokenKnown && bal.token < amount) {
3379
3723
  blockers.push("INSUFFICIENT_TOKEN");
3380
- shortfall.token = _chunkJG6KRAW6cjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
3724
+ shortfall.token = _chunkMWBT7MCEcjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
3381
3725
  }
3382
3726
  } else if (isNative) {
3383
3727
  if (nativeKnown && bal.native < amount + fee) {
3384
3728
  blockers.push("INSUFFICIENT_TOKEN");
3385
- shortfall.token = _chunkJG6KRAW6cjs.formatUnits.call(void 0, amount + fee - bal.native, quote.decimals);
3729
+ shortfall.token = _chunkMWBT7MCEcjs.formatUnits.call(void 0, amount + fee - bal.native, quote.decimals);
3386
3730
  }
3387
3731
  } else {
3388
3732
  if (tokenKnown && bal.token < amount) {
3389
3733
  blockers.push("INSUFFICIENT_TOKEN");
3390
- shortfall.token = _chunkJG6KRAW6cjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
3734
+ shortfall.token = _chunkMWBT7MCEcjs.formatUnits.call(void 0, amount - bal.token, quote.decimals);
3391
3735
  }
3392
3736
  if (nativeKnown && bal.native < fee) {
3393
3737
  blockers.push("INSUFFICIENT_GAS");
3394
- shortfall.native = _chunkJG6KRAW6cjs.formatUnits.call(void 0, fee - bal.native, cost.feeDecimals);
3738
+ shortfall.native = _chunkMWBT7MCEcjs.formatUnits.call(void 0, fee - bal.native, cost.feeDecimals);
3395
3739
  } else if (nativeKnown && fee > 0n && bal.native < fee * 3n / 2n) {
3396
3740
  warnings.push("THIN_GAS_MARGIN");
3397
3741
  }
@@ -3416,8 +3760,8 @@ var PipRailClient = (_class2 = class {
3416
3760
  blockers,
3417
3761
  warnings,
3418
3762
  balance: {
3419
- token: bal.token != null ? _chunkJG6KRAW6cjs.formatUnits.call(void 0, bal.token, quote.decimals) : null,
3420
- native: bal.native != null ? _chunkJG6KRAW6cjs.formatUnits.call(void 0, bal.native, cost.feeDecimals) : null
3763
+ token: bal.token != null ? _chunkMWBT7MCEcjs.formatUnits.call(void 0, bal.token, quote.decimals) : null,
3764
+ native: bal.native != null ? _chunkMWBT7MCEcjs.formatUnits.call(void 0, bal.native, cost.feeDecimals) : null
3421
3765
  },
3422
3766
  need: { token: quote.amountFormatted, native: cost.feeFormatted },
3423
3767
  ...shortfall.token || shortfall.native ? { shortfall } : {},
@@ -3428,25 +3772,30 @@ var PipRailClient = (_class2 = class {
3428
3772
  * driver's describeAsset) + the policy verdict + a symbol-mismatch flag. */
3429
3773
  buildQuote(net, accept, url, description) {
3430
3774
  if (typeof accept.amount !== "string" || !/^\d+$/.test(accept.amount)) {
3431
- throw new (0, _chunkJG6KRAW6cjs.InvalidEnvelopeError)(
3775
+ throw new (0, _chunkMWBT7MCEcjs.InvalidEnvelopeError)(
3432
3776
  `challenge amount "${String(accept.amount)}" is not a base-unit integer string.`
3433
3777
  );
3434
3778
  }
3435
3779
  if (typeof accept.asset !== "string" || accept.asset.length === 0) {
3436
- throw new (0, _chunkJG6KRAW6cjs.InvalidEnvelopeError)(
3780
+ throw new (0, _chunkMWBT7MCEcjs.InvalidEnvelopeError)(
3437
3781
  `challenge on ${accept.network} states no (string) asset \u2014 refusing to price it.`
3438
3782
  );
3439
3783
  }
3440
3784
  const amountBase = BigInt(accept.amount);
3441
3785
  const described = net.describeAsset(accept.asset);
3442
- const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _34 => _34.decimals]), () => ( _optionalChain([accept, 'access', _35 => _35.extra, 'optionalAccess', _36 => _36.decimals])));
3786
+ const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _45 => _45.decimals]), () => ( _optionalChain([accept, 'access', _46 => _46.extra, 'optionalAccess', _47 => _47.decimals])));
3443
3787
  if (typeof decimals !== "number" || !Number.isInteger(decimals) || decimals < 0) {
3444
- throw new (0, _chunkJG6KRAW6cjs.InvalidEnvelopeError)(
3788
+ throw new (0, _chunkMWBT7MCEcjs.InvalidEnvelopeError)(
3445
3789
  `challenge for ${accept.asset} on ${accept.network} states no valid decimals and the SDK doesn't recognise the token \u2014 refusing to price it.`
3446
3790
  );
3447
3791
  }
3448
- const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _37 => _37.symbol]), () => ( _optionalChain([accept, 'access', _38 => _38.extra, 'optionalAccess', _39 => _39.symbol])));
3449
- const amountFormatted = _chunkJG6KRAW6cjs.formatUnits.call(void 0, amountBase, decimals);
3792
+ if (decimals > _chunkMWBT7MCEcjs.MAX_DECIMALS) {
3793
+ throw new (0, _chunkMWBT7MCEcjs.InvalidEnvelopeError)(
3794
+ `challenge for ${accept.asset} on ${accept.network} states ${decimals} decimals (> ${_chunkMWBT7MCEcjs.MAX_DECIMALS}) \u2014 refusing to price it (no real token is that deep).`
3795
+ );
3796
+ }
3797
+ const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _48 => _48.symbol]), () => ( _optionalChain([accept, 'access', _49 => _49.extra, 'optionalAccess', _50 => _50.symbol])));
3798
+ const amountFormatted = _chunkMWBT7MCEcjs.formatUnits.call(void 0, amountBase, decimals);
3450
3799
  const intent = {
3451
3800
  host: hostOf2(url),
3452
3801
  chain: this.opts.chain,
@@ -3459,9 +3808,14 @@ var PipRailClient = (_class2 = class {
3459
3808
  };
3460
3809
  const policy = this.opts.policy;
3461
3810
  const hasWindow = !!policy && policy.windowTotal != null && policy.windowSeconds != null;
3811
+ const hasWindowCount = !!policy && policy.maxPaymentsPerWindow != null && policy.windowSeconds != null;
3812
+ const hasDenomCap = !!policy && policy.maxTotalPerDenom != null && Object.keys(policy.maxTotalPerDenom).length > 0;
3813
+ const hasCountCap = !!policy && policy.maxPayments != null;
3462
3814
  const hasTimePolicy = !!policy && (policy.ttlSeconds != null || policy.expiresAt != null || hasWindow);
3815
+ const needsCtx = hasTimePolicy || hasWindowCount || hasDenomCap || hasCountCap;
3816
+ const denom = hasDenomCap ? denomOf(intent.symbol, intent.asset, policy) : void 0;
3463
3817
  const now = Date.now();
3464
- const ctx = hasTimePolicy ? {
3818
+ const ctx = needsCtx ? {
3465
3819
  now,
3466
3820
  sessionStart: this.ledger.sessionStart,
3467
3821
  // Window slice ONLY when BOTH fields are set — never a `?? 0` width.
@@ -3469,7 +3823,12 @@ var PipRailClient = (_class2 = class {
3469
3823
  accept.network,
3470
3824
  accept.asset,
3471
3825
  now - policy.windowSeconds * 1e3
3472
- ) : 0n
3826
+ ) : 0n,
3827
+ // Running grand total on this intent's denomination, across the (shared) ledger.
3828
+ spentInDenomScaled: denom ? this.ledger.totalForDenom(denom) : 0n,
3829
+ // Settled-payment counts (lifetime + window) for the count caps.
3830
+ paymentCount: hasCountCap ? this.ledger.count() : 0,
3831
+ paymentCountInWindow: hasWindowCount ? this.ledger.countSince(now - policy.windowSeconds * 1e3) : 0
3473
3832
  } : void 0;
3474
3833
  const decision = evaluatePolicy(
3475
3834
  intent,
@@ -3477,7 +3836,7 @@ var PipRailClient = (_class2 = class {
3477
3836
  this.ledger.totalFor(accept.network, accept.asset),
3478
3837
  ctx
3479
3838
  );
3480
- const serverSymbol = _optionalChain([accept, 'access', _40 => _40.extra, 'optionalAccess', _41 => _41.symbol]);
3839
+ const serverSymbol = _optionalChain([accept, 'access', _51 => _51.extra, 'optionalAccess', _52 => _52.symbol]);
3481
3840
  const symbolMismatch = intent.recognized && !!serverSymbol && !!symbol && serverSymbol.toUpperCase() !== symbol.toUpperCase();
3482
3841
  return {
3483
3842
  url,
@@ -3505,9 +3864,11 @@ var PipRailClient = (_class2 = class {
3505
3864
  async authorize(quote) {
3506
3865
  if (!quote.withinPolicy) {
3507
3866
  const reason = `Payment refused by policy: ${_nullishCoalesce(quote.policyReason, () => ( "not allowed"))}`;
3508
- const reasonCode = reasonCodeForPolicy(quote.policyCode);
3509
- this.safeEmit({ kind: "payment-failed", reason, code: reasonCode });
3510
- throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason, { reasonCode });
3867
+ this.refuse(reason, {
3868
+ reasonCode: reasonCodeForPolicy(quote.policyCode),
3869
+ policyCode: quote.policyCode,
3870
+ quote
3871
+ });
3511
3872
  }
3512
3873
  const hook = this.opts.onBeforePay;
3513
3874
  if (!hook) return;
@@ -3515,43 +3876,136 @@ var PipRailClient = (_class2 = class {
3515
3876
  try {
3516
3877
  approved = await hook(quote);
3517
3878
  } catch (err) {
3518
- const reason = "onBeforePay threw \u2014 refusing to pay.";
3519
- this.safeEmit({ kind: "payment-failed", reason, code: "APPROVAL" });
3520
- throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason, { cause: err, reasonCode: "APPROVAL" });
3879
+ this.refuse("onBeforePay threw \u2014 refusing to pay.", { reasonCode: "APPROVAL", quote, cause: err });
3521
3880
  }
3522
3881
  if (!approved) {
3523
3882
  const reason = `onBeforePay declined ${quote.amountFormatted} ${_nullishCoalesce(quote.symbol, () => ( ""))}`.trimEnd() + ` on ${quote.network}.`;
3524
- this.safeEmit({ kind: "payment-failed", reason, code: "APPROVAL" });
3525
- throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(reason, { reasonCode: "APPROVAL" });
3883
+ this.refuse(reason, { reasonCode: "APPROVAL", quote });
3526
3884
  }
3527
3885
  }
3528
- /** Record a settled payment in the ledger (true decimals for the running total). */
3886
+ /**
3887
+ * Refuse a payment BEFORE any send: emit BOTH the legacy `payment-failed` (so existing
3888
+ * `onEvent` consumers are unaffected) AND the richer, dedicated `payment-declined`
3889
+ * (typed reasonCode + fine PolicyDenyCode + the quote + a budget snapshot), then throw
3890
+ * the typed {@link PaymentDeclinedError}. Returns `never` so callers' control flow is
3891
+ * exhaustive.
3892
+ */
3893
+ refuse(reason, opts) {
3894
+ this.safeEmit({ kind: "payment-failed", reason, ...opts.reasonCode ? { code: opts.reasonCode } : {} });
3895
+ this.safeEmit({
3896
+ kind: "payment-declined",
3897
+ reason,
3898
+ ...opts.reasonCode ? { reasonCode: opts.reasonCode } : {},
3899
+ ...opts.policyCode ? { code: opts.policyCode } : {},
3900
+ ...opts.quote ? { quote: opts.quote } : {},
3901
+ budget: this.budget()
3902
+ });
3903
+ throw new (0, _chunkMWBT7MCEcjs.PaymentDeclinedError)(reason, {
3904
+ ...opts.reasonCode ? { reasonCode: opts.reasonCode } : {},
3905
+ ...opts.cause !== void 0 ? { cause: opts.cause } : {}
3906
+ });
3907
+ }
3908
+ /** Record a settled payment in the ledger (TRUE decimals for the running total + the
3909
+ * denomination it counts toward in the grand total). Then fire the `onSpend` callback
3910
+ * with the record + the post-payment budget, and emit any `warnAtFraction` thresholds
3911
+ * this payment just crossed. All observability is isolated — a throwing hook never
3912
+ * affects the (already-settled) payment. */
3529
3913
  recordSpend(quote, ref) {
3530
- this.ledger.record(
3531
- {
3532
- url: quote.url,
3533
- host: hostOf2(quote.url),
3534
- network: quote.network,
3535
- asset: quote.asset,
3536
- amountBase: quote.amount,
3537
- amountFormatted: quote.amountFormatted,
3538
- ...quote.symbol ? { symbol: quote.symbol } : {},
3539
- ref,
3540
- at: (/* @__PURE__ */ new Date()).toISOString()
3541
- },
3542
- quote.decimals
3543
- );
3914
+ const denom = denomOf(quote.symbol, quote.asset, this.opts.policy);
3915
+ const record = {
3916
+ url: quote.url,
3917
+ host: hostOf2(quote.url),
3918
+ network: quote.network,
3919
+ asset: quote.asset,
3920
+ amountBase: quote.amount,
3921
+ amountFormatted: quote.amountFormatted,
3922
+ ...quote.symbol ? { symbol: quote.symbol } : {},
3923
+ decimals: quote.decimals,
3924
+ ...denom ? { denom } : {},
3925
+ ref,
3926
+ at: (/* @__PURE__ */ new Date()).toISOString()
3927
+ };
3928
+ this.ledger.record(record, quote.decimals, denom);
3929
+ const budget = this.budget();
3930
+ if (this.opts.onSpend) {
3931
+ try {
3932
+ this.opts.onSpend(record, budget);
3933
+ } catch (e30) {
3934
+ }
3935
+ }
3936
+ this.emitThresholds(budget);
3937
+ }
3938
+ /**
3939
+ * Emit a `budget-threshold` event for each cap whose used-fraction just reached
3940
+ * `policy.warnAtFraction` — the early warning before a hard decline. Fires ONCE per
3941
+ * crossing per cap (deduped on the shared ledger via `markWarned`, so a cross-chain
3942
+ * threshold fires once for the whole budget, not once per chain). No-op when no
3943
+ * `warnAtFraction` is set. Reads the just-computed {@link SessionBudget}; isolated (safeEmit).
3944
+ */
3945
+ emitThresholds(budget) {
3946
+ const frac = _optionalChain([this, 'access', _53 => _53.opts, 'access', _54 => _54.policy, 'optionalAccess', _55 => _55.warnAtFraction]);
3947
+ if (frac === void 0) return;
3948
+ const fire = (scope, label, spentFormatted, capFormatted, fraction) => {
3949
+ if (fraction < frac) return;
3950
+ if (!this.ledger.markWarned(`${scope}:${label}`)) return;
3951
+ this.safeEmit({ kind: "budget-threshold", scope, label, spentFormatted, capFormatted, fraction });
3952
+ };
3953
+ for (const r of budget.byAsset) {
3954
+ if (r.capBase === void 0) continue;
3955
+ const cap = BigInt(r.capBase);
3956
+ const spent = BigInt(r.spentBase);
3957
+ const fraction = cap === 0n ? spent > 0n ? 1 : 0 : Number(spent * 1000000n / cap) / 1e6;
3958
+ fire(
3959
+ "asset",
3960
+ `${_nullishCoalesce(r.symbol, () => ( r.asset))} on ${r.network}`,
3961
+ _chunkMWBT7MCEcjs.formatUnits.call(void 0, spent, r.decimals),
3962
+ _chunkMWBT7MCEcjs.formatUnits.call(void 0, cap, r.decimals),
3963
+ fraction
3964
+ );
3965
+ }
3966
+ for (const d of budget.byDenom) {
3967
+ fire("denom", d.denom, d.spentFormatted, d.capFormatted, d.fraction);
3968
+ }
3969
+ const policy = this.opts.policy;
3970
+ if (_optionalChain([policy, 'optionalAccess', _56 => _56.windowTotal]) !== void 0 && policy.windowSeconds !== void 0) {
3971
+ const since = Date.now() - policy.windowSeconds * 1e3;
3972
+ for (const r of budget.byAsset) {
3973
+ const cap = _chunkMWBT7MCEcjs.floorUnits.call(void 0, policy.windowTotal, r.decimals);
3974
+ const spent = this.ledger.totalSince(r.network, r.asset, since);
3975
+ const fraction = cap === 0n ? spent > 0n ? 1 : 0 : Number(spent * 1000000n / cap) / 1e6;
3976
+ fire(
3977
+ "window",
3978
+ `${_nullishCoalesce(r.symbol, () => ( r.asset))} on ${r.network}`,
3979
+ _chunkMWBT7MCEcjs.formatUnits.call(void 0, spent, r.decimals),
3980
+ _chunkMWBT7MCEcjs.formatUnits.call(void 0, cap, r.decimals),
3981
+ fraction
3982
+ );
3983
+ }
3984
+ }
3985
+ const c = budget.counts;
3986
+ if (c.lifetimeCap !== void 0 && c.lifetimeCap > 0) {
3987
+ fire("count", "maxPayments", String(c.settled), String(c.lifetimeCap), c.settled / c.lifetimeCap);
3988
+ }
3989
+ if (c.windowCap !== void 0 && c.windowCap > 0 && c.windowSettled !== void 0) {
3990
+ fire(
3991
+ "window-count",
3992
+ "maxPaymentsPerWindow",
3993
+ String(c.windowSettled),
3994
+ String(c.windowCap),
3995
+ c.windowSettled / c.windowCap
3996
+ );
3997
+ }
3544
3998
  }
3545
3999
  async payAndConfirm(net, wallet, accept) {
3546
4000
  if (!this.supportsNetwork(net, accept.network)) {
3547
- throw new (0, _chunkJG6KRAW6cjs.WrongChainError)(
4001
+ throw new (0, _chunkMWBT7MCEcjs.WrongChainError)(
3548
4002
  `Challenge expects ${accept.network} but client is on ${net.network}.`
3549
4003
  );
3550
4004
  }
3551
4005
  const ref = await net.send(wallet, accept);
3552
4006
  this.safeEmit({ kind: "payment-broadcast", ref });
3553
4007
  try {
3554
- const { height } = await net.confirm(ref, _nullishCoalesce(_optionalChain([accept, 'access', _42 => _42.extra, 'optionalAccess', _43 => _43.minConfirmations]), () => ( 1)));
4008
+ const { height } = await net.confirm(ref, _nullishCoalesce(_optionalChain([accept, 'access', _57 => _57.extra, 'optionalAccess', _58 => _58.minConfirmations]), () => ( 1)));
3555
4009
  this.safeEmit({
3556
4010
  kind: "payment-confirmed",
3557
4011
  ref,
@@ -3571,9 +4025,9 @@ var PipRailClient = (_class2 = class {
3571
4025
  const signature = {
3572
4026
  x402Version: 2,
3573
4027
  accepted: accept,
3574
- payload: { nonce: _optionalChain([accept, 'access', _44 => _44.extra, 'optionalAccess', _45 => _45.nonce]), txHash: ref }
4028
+ payload: { nonce: _optionalChain([accept, 'access', _59 => _59.extra, 'optionalAccess', _60 => _60.nonce]), txHash: ref }
3575
4029
  };
3576
- const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _46 => _46.headers]));
4030
+ const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _61 => _61.headers]));
3577
4031
  headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
3578
4032
  let lastResponse = null;
3579
4033
  let lastReason = null;
@@ -3588,7 +4042,7 @@ var PipRailClient = (_class2 = class {
3588
4042
  () => timeoutController.abort(),
3589
4043
  this.retryTimeoutMs
3590
4044
  );
3591
- const signal = _optionalChain([originalInit, 'optionalAccess', _47 => _47.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
4045
+ const signal = _optionalChain([originalInit, 'optionalAccess', _62 => _62.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
3592
4046
  try {
3593
4047
  lastResponse = await fetch(url, {
3594
4048
  ..._nullishCoalesce(originalInit, () => ( {})),
@@ -3597,7 +4051,7 @@ var PipRailClient = (_class2 = class {
3597
4051
  });
3598
4052
  } catch (err) {
3599
4053
  if (timeoutController.signal.aborted) {
3600
- throw new (0, _chunkJG6KRAW6cjs.PaymentTimeoutError)(
4054
+ throw new (0, _chunkMWBT7MCEcjs.PaymentTimeoutError)(
3601
4055
  `Server did not respond within ${this.retryTimeoutMs}ms after broadcasting payment ${ref}. Re-verify or re-submit ref=${ref} \u2014 do NOT re-pay.`,
3602
4056
  { cause: err, ref }
3603
4057
  );
@@ -3620,7 +4074,7 @@ var PipRailClient = (_class2 = class {
3620
4074
  reason: `server returned 402 after broadcasting payment ${ref}${unconfirmedNote} (${why})`,
3621
4075
  ...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
3622
4076
  });
3623
- throw new (0, _chunkJG6KRAW6cjs.MaxRetriesExceededError)(
4077
+ throw new (0, _chunkMWBT7MCEcjs.MaxRetriesExceededError)(
3624
4078
  `Server still returned 402 after ${attempts} attempt(s) with on-chain proof ref=${ref}${unconfirmedNote}. Last server rejection: ${why}. Re-verify or re-submit ref=${ref} before retrying \u2014 never re-pay (it would double-spend).`,
3625
4079
  { ref }
3626
4080
  );
@@ -3644,17 +4098,17 @@ var PipRailClient = (_class2 = class {
3644
4098
  */
3645
4099
  async payExactRail(net, wallet, accept, url, init, quote) {
3646
4100
  if (!net.payExact) {
3647
- throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
4101
+ throw new (0, _chunkMWBT7MCEcjs.UnsupportedSchemeError)(
3648
4102
  `the ${net.family} family can't pay a standard 'exact' rail (supported on EVM, Solana, Algorand + NEAR today).`
3649
4103
  );
3650
4104
  }
3651
- throwIfAborted(_optionalChain([init, 'optionalAccess', _48 => _48.signal]));
4105
+ throwIfAborted(_optionalChain([init, 'optionalAccess', _63 => _63.signal]));
3652
4106
  const { payload, accepted, payerFrom, nonce } = await net.payExact(wallet, accept);
3653
- const headers = new Headers(_optionalChain([init, 'optionalAccess', _49 => _49.headers]));
4107
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _64 => _64.headers]));
3654
4108
  headers.set(HEADER_SIGNATURE, buildExactSignatureHeader({ accepted, payload }));
3655
4109
  const rejectDefinitive = (why2) => {
3656
4110
  this.safeEmit({ kind: "payment-failed", reason: `exact: facilitator rejected nonce=${nonce} (${why2})`, code: why2 });
3657
- throw new (0, _chunkJG6KRAW6cjs.MaxRetriesExceededError)(
4111
+ throw new (0, _chunkMWBT7MCEcjs.MaxRetriesExceededError)(
3658
4112
  `exact: the facilitator rejected the payment (${why2}). Fix the cause, then re-present the SAME signed authorization (nonce=${nonce}) \u2014 do NOT re-sign a fresh nonce. ref=${nonce}.`,
3659
4113
  { ref: nonce }
3660
4114
  );
@@ -3667,17 +4121,17 @@ var PipRailClient = (_class2 = class {
3667
4121
  if (Date.now() >= deadline) break;
3668
4122
  await new Promise((r) => setTimeout(r, Math.min(2e3, 400 * 2 ** (attempt - 1))));
3669
4123
  }
3670
- throwIfAborted(_optionalChain([init, 'optionalAccess', _50 => _50.signal]));
4124
+ throwIfAborted(_optionalChain([init, 'optionalAccess', _65 => _65.signal]));
3671
4125
  const budget = Math.min(this.retryTimeoutMs, deadline - Date.now());
3672
4126
  if (budget <= 0) break;
3673
4127
  const timeoutController = new AbortController();
3674
4128
  const timeoutId = setTimeout(() => timeoutController.abort(), budget);
3675
- const signal = _optionalChain([init, 'optionalAccess', _51 => _51.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, init.signal]) : timeoutController.signal;
4129
+ const signal = _optionalChain([init, 'optionalAccess', _66 => _66.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, init.signal]) : timeoutController.signal;
3676
4130
  let response;
3677
4131
  try {
3678
4132
  response = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), headers, signal });
3679
4133
  } catch (err) {
3680
- throw new (0, _chunkJG6KRAW6cjs.PaymentTimeoutError)(
4134
+ throw new (0, _chunkMWBT7MCEcjs.PaymentTimeoutError)(
3681
4135
  `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.`,
3682
4136
  { cause: err, ref: nonce }
3683
4137
  );
@@ -3693,7 +4147,7 @@ var PipRailClient = (_class2 = class {
3693
4147
  if (response.ok && !(settle && settle.success === false)) {
3694
4148
  const receipt = parseReceipt(response);
3695
4149
  this.safeEmit({ kind: "payment-settled", receipt, ...settle ? { settle } : {} });
3696
- const ref = _optionalChain([settle, 'optionalAccess', _52 => _52.transaction]) || _optionalChain([receipt, 'optionalAccess', _53 => _53.transaction]) || `eip3009-nonce:${nonce}`;
4150
+ const ref = _optionalChain([settle, 'optionalAccess', _67 => _67.transaction]) || _optionalChain([receipt, 'optionalAccess', _68 => _68.transaction]) || `eip3009-nonce:${nonce}`;
3697
4151
  this.recordSpend(quote, ref);
3698
4152
  return response;
3699
4153
  }
@@ -3711,21 +4165,21 @@ var PipRailClient = (_class2 = class {
3711
4165
  reason: `exact: 402 after submitting authorization nonce=${nonce} (${why})`,
3712
4166
  ...lastReason ? { code: lastReason.error, detail: lastReason.detail } : {}
3713
4167
  });
3714
- throw new (0, _chunkJG6KRAW6cjs.MaxRetriesExceededError)(
4168
+ throw new (0, _chunkMWBT7MCEcjs.MaxRetriesExceededError)(
3715
4169
  `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}.`,
3716
4170
  { ref: nonce }
3717
4171
  );
3718
4172
  }
3719
- }, _class2);
4173
+ };
3720
4174
  function throwIfAborted(signal) {
3721
- if (_optionalChain([signal, 'optionalAccess', _54 => _54.aborted])) {
4175
+ if (_optionalChain([signal, 'optionalAccess', _69 => _69.aborted])) {
3722
4176
  throw _nullishCoalesce(signal.reason, () => ( new DOMException("This operation was aborted.", "AbortError")));
3723
4177
  }
3724
4178
  }
3725
4179
  function safeBig(s) {
3726
4180
  try {
3727
4181
  return BigInt(s);
3728
- } catch (e28) {
4182
+ } catch (e31) {
3729
4183
  return 0n;
3730
4184
  }
3731
4185
  }
@@ -3788,10 +4242,10 @@ function buildFundingHint(options, chainLabel) {
3788
4242
  return `Couldn't fully read your wallet on ${chainLabel} (RPC throttled) \u2014 retry; you may already be able to pay ${target.quote.amountFormatted} ${sym}.`;
3789
4243
  }
3790
4244
  const parts = [];
3791
- if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _55 => _55.shortfall, 'optionalAccess', _56 => _56.token])) {
4245
+ if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _70 => _70.shortfall, 'optionalAccess', _71 => _71.token])) {
3792
4246
  parts.push(`top up ${target.shortfall.token} ${sym}`);
3793
4247
  }
3794
- if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _57 => _57.shortfall, 'optionalAccess', _58 => _58.native])) {
4248
+ if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _72 => _72.shortfall, 'optionalAccess', _73 => _73.native])) {
3795
4249
  parts.push(`add ~${target.shortfall.native} ${target.cost.feeSymbol} for gas`);
3796
4250
  }
3797
4251
  return parts.length ? `Can't settle on ${chainLabel}: ${parts.join(" and ")} (to pay ${target.quote.amountFormatted} ${sym}).` : `Can't settle on ${chainLabel} for ${target.quote.amountFormatted} ${sym}.`;
@@ -3805,7 +4259,7 @@ async function planAcross(clients, url, init) {
3805
4259
  const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
3806
4260
  return {
3807
4261
  url,
3808
- network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _59 => _59.accept, 'access', _60 => _60.network]), () => ( live[0].network)),
4262
+ network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _74 => _74.accept, 'access', _75 => _75.network]), () => ( live[0].network)),
3809
4263
  status,
3810
4264
  payable: best !== null,
3811
4265
  best,
@@ -3824,7 +4278,7 @@ async function fetchAcross(clients, url, init) {
3824
4278
  const best = rankAcross(live.map((p) => p.plan)).find((o) => o.state === "payable");
3825
4279
  if (!best) {
3826
4280
  const hint = mergeDeclineHint(live.map((p) => p.plan));
3827
- throw new (0, _chunkJG6KRAW6cjs.PaymentDeclinedError)(hint || "No funded chain can settle this payment right now.");
4281
+ throw new (0, _chunkMWBT7MCEcjs.PaymentDeclinedError)(hint || "No funded chain can settle this payment right now.");
3828
4282
  }
3829
4283
  const owner = live.find((p) => p.plan.options.includes(best)).client;
3830
4284
  return owner.fetch(url, { ..._nullishCoalesce(init, () => ( {})), autoRoute: true });
@@ -3838,8 +4292,11 @@ function reasonCodeForPolicy(code) {
3838
4292
  case "SESSION_EXPIRED":
3839
4293
  return "SESSION_EXPIRED";
3840
4294
  case "WINDOW_TOTAL":
4295
+ case "WINDOW_COUNT":
3841
4296
  return "OUTSIDE_WINDOW";
3842
4297
  case "MAX_TOTAL":
4298
+ case "MAX_TOTAL_DENOM":
4299
+ case "MAX_PAYMENTS":
3843
4300
  return "BUDGET";
3844
4301
  case void 0:
3845
4302
  return void 0;
@@ -3850,7 +4307,7 @@ function reasonCodeForPolicy(code) {
3850
4307
  function hostOf2(url) {
3851
4308
  try {
3852
4309
  return new URL(url).hostname;
3853
- } catch (e29) {
4310
+ } catch (e32) {
3854
4311
  return url;
3855
4312
  }
3856
4313
  }
@@ -3867,8 +4324,8 @@ function isReplayableBodyInit(value) {
3867
4324
  async function readInvalidReason(response) {
3868
4325
  try {
3869
4326
  const body = await response.clone().json();
3870
- const ext = _optionalChain([body, 'optionalAccess', _61 => _61.extensions]);
3871
- const piprail = _optionalChain([ext, 'optionalAccess', _62 => _62.piprail]);
4327
+ const ext = _optionalChain([body, 'optionalAccess', _76 => _76.extensions]);
4328
+ const piprail = _optionalChain([ext, 'optionalAccess', _77 => _77.piprail]);
3872
4329
  if (piprail && typeof piprail.code === "string") {
3873
4330
  return {
3874
4331
  error: piprail.code,
@@ -3887,16 +4344,20 @@ async function readInvalidReason(response) {
3887
4344
  detail: typeof body.invalidMessage === "string" ? body.invalidMessage : ""
3888
4345
  };
3889
4346
  }
3890
- } catch (e30) {
4347
+ } catch (e33) {
3891
4348
  }
3892
4349
  const settle = parseSettleResponse(response);
3893
- if (_optionalChain([settle, 'optionalAccess', _63 => _63.errorReason])) return { error: settle.errorReason, detail: "" };
4350
+ if (_optionalChain([settle, 'optionalAccess', _78 => _78.errorReason])) return { error: settle.errorReason, detail: "" };
3894
4351
  return null;
3895
4352
  }
3896
4353
 
3897
4354
  // src/payer.ts
3898
4355
  var MultiChainPayer = class _MultiChainPayer {
3899
4356
 
4357
+ /** True when every client shares ONE ledger (the `fromWallets` path) — so spend +
4358
+ * budget are read from that single source, never concatenated (which would
4359
+ * double-count a shared ledger). */
4360
+
3900
4361
  /**
3901
4362
  * Wrap an explicit, ordered set of single-chain clients — use this when a client
3902
4363
  * needs full control (e.g. a custom EVM chain configured by a viem `Chain`). The
@@ -3904,12 +4365,18 @@ var MultiChainPayer = class _MultiChainPayer {
3904
4365
  * at MOST one client per chain — two clients on the SAME network would double-count in
3905
4366
  * `spent()`/`budget()` and waste a plan round-trip (`fromWallets` can't produce this).
3906
4367
  * For the common case, prefer {@link MultiChainPayer.fromWallets}.
4368
+ *
4369
+ * For a cross-chain grand total / count cap via this path, build the clients with a
4370
+ * SHARED `ledger` (`new SpendLedger(store?)` passed to each client's `ledger` option)
4371
+ * and set `opts.shared = true` so reads come from that one ledger. `fromWallets` does
4372
+ * this for you.
3907
4373
  */
3908
- constructor(clients) {
4374
+ constructor(clients, opts = {}) {
3909
4375
  if (clients.length === 0) {
3910
4376
  throw new TypeError("MultiChainPayer needs at least one PipRailClient.");
3911
4377
  }
3912
4378
  this._clients = [...clients];
4379
+ this._shared = _nullishCoalesce(opts.shared, () => ( false));
3913
4380
  }
3914
4381
  /**
3915
4382
  * Build one client per funded chain from a `{ chain → wallet }` map — the
@@ -3924,30 +4391,36 @@ var MultiChainPayer = class _MultiChainPayer {
3924
4391
  * solana: { key: process.env.SOLANA_SECRET! },
3925
4392
  * xrpl: { key: process.env.XRPL_SEED! },
3926
4393
  * },
3927
- * policy: { maxAmount: '1.00', maxTotal: '20.00', tokens: ['USDC', 'USDT'] },
4394
+ * // ONE budget across all three chains: $20 total + at most 100 payments.
4395
+ * policy: { maxAmount: '1.00', maxTotalPerDenom: { USD: '20.00' }, maxPayments: 100 },
3928
4396
  * })
3929
4397
  * const res = await payer.get('https://api.example.com/paid') // pays on the first funded chain that can settle
3930
4398
  * ```
4399
+ *
4400
+ * Every client shares ONE {@link SpendLedger} (optionally backed by `spendStore`), so
4401
+ * the cross-token grand total + the count caps span all chains as a single budget.
3931
4402
  */
3932
4403
  static fromWallets(opts) {
3933
4404
  const entries = Object.entries(opts.wallets);
3934
4405
  if (entries.length === 0) {
3935
4406
  throw new TypeError("MultiChainPayer.fromWallets needs at least one wallet.");
3936
4407
  }
4408
+ const ledger = new SpendLedger(opts.spendStore);
3937
4409
  const clients = entries.map(
3938
4410
  ([chain, wallet]) => new PipRailClient({
3939
4411
  chain,
3940
4412
  wallet,
4413
+ ledger,
3941
4414
  ...opts.policy ? { policy: opts.policy } : {},
3942
4415
  ...opts.schemes ? { schemes: opts.schemes } : {},
3943
- ..._optionalChain([opts, 'access', _64 => _64.rpcUrls, 'optionalAccess', _65 => _65[chain]]) ? { rpcUrl: opts.rpcUrls[chain] } : {},
4416
+ ..._optionalChain([opts, 'access', _79 => _79.rpcUrls, 'optionalAccess', _80 => _80[chain]]) ? { rpcUrl: opts.rpcUrls[chain] } : {},
3944
4417
  ...opts.onBeforePay ? { onBeforePay: opts.onBeforePay } : {},
3945
4418
  ...opts.onEvent ? { onEvent: opts.onEvent } : {},
3946
4419
  ...opts.maxPaymentRetries != null ? { maxPaymentRetries: opts.maxPaymentRetries } : {},
3947
4420
  ...opts.retryTimeoutMs != null ? { retryTimeoutMs: opts.retryTimeoutMs } : {}
3948
4421
  })
3949
4422
  );
3950
- return new _MultiChainPayer(clients);
4423
+ return new _MultiChainPayer(clients, { shared: true });
3951
4424
  }
3952
4425
  /** The underlying single-chain clients, in preference order. Reach for one of
3953
4426
  * these for chain-specific reads (`estimateCost`, `discoverySigner`, per-chain
@@ -3998,7 +4471,7 @@ var MultiChainPayer = class _MultiChainPayer {
3998
4471
  * {@link PipRailClient.post}.
3999
4472
  */
4000
4473
  post(url, body, init) {
4001
- const headers = new Headers(_optionalChain([init, 'optionalAccess', _66 => _66.headers]));
4474
+ const headers = new Headers(_optionalChain([init, 'optionalAccess', _81 => _81.headers]));
4002
4475
  let payload;
4003
4476
  if (body === void 0 || body === null) {
4004
4477
  payload = void 0;
@@ -4041,28 +4514,50 @@ var MultiChainPayer = class _MultiChainPayer {
4041
4514
  register(url, opts = {}) {
4042
4515
  return this._clients[0].register(url, opts);
4043
4516
  }
4044
- /** Aggregate spend across every chain — counts summed; per-(network,asset) rows
4045
- * and records concatenated (no cross-chain collisions, never a cross-token sum). */
4517
+ /**
4518
+ * Aggregate spend across every chain. With a SHARED ledger (`fromWallets`), this reads
4519
+ * that single ledger ONCE (its records already span every chain) — so the count and the
4520
+ * cross-token `byDenom` grand total are correct and never double-counted. With
4521
+ * independent clients (the explicit constructor), it concatenates: counts summed,
4522
+ * per-(network,asset) `byAsset` + `byDenom` + records concatenated.
4523
+ */
4046
4524
  spent() {
4525
+ if (this._shared) return this._clients[0].spent();
4047
4526
  const summaries = this._clients.map((c) => c.spent());
4048
4527
  return {
4049
4528
  count: summaries.reduce((n, s) => n + s.count, 0),
4050
4529
  byAsset: summaries.flatMap((s) => s.byAsset),
4530
+ byDenom: summaries.flatMap((s) => s.byDenom),
4051
4531
  records: summaries.flatMap((s) => s.records)
4052
4532
  };
4053
4533
  }
4054
- /** A merged budget view: every chain's per-(network,asset) remaining rows, plus the
4055
- * MOST-RESTRICTIVE session time envelope across chains (the soonest deadline wins).
4056
- * Mirrors {@link PipRailClient.budget}'s shape so the agent toolkit reads it
4057
- * unchanged; per-chain session detail is on each `clients[i].budget()`. */
4534
+ /**
4535
+ * A merged budget view. With a SHARED ledger (`fromWallets`) it's the single source of
4536
+ * truth `byAsset`/`byDenom`/`counts` already span every chain, so the grand-total and
4537
+ * count leashes read as ONE budget. With independent clients it merges: per-(network,
4538
+ * asset) rows + per-denom rows concatenated, counts summed, and the MOST-RESTRICTIVE
4539
+ * session time envelope (the soonest deadline wins). Per-chain detail is on each
4540
+ * `clients[i].budget()`.
4541
+ */
4058
4542
  budget() {
4543
+ if (this._shared) return this._clients[0].budget();
4059
4544
  const budgets = this._clients.map((c) => c.budget());
4060
4545
  const session = budgets.map((b) => b.session).reduce((soonest, s) => {
4061
4546
  if (soonest.secondsRemaining == null) return s;
4062
4547
  if (s.secondsRemaining == null) return soonest;
4063
4548
  return s.secondsRemaining < soonest.secondsRemaining ? s : soonest;
4064
4549
  });
4065
- return { session, byAsset: budgets.flatMap((b) => b.byAsset) };
4550
+ return {
4551
+ session,
4552
+ byAsset: budgets.flatMap((b) => b.byAsset),
4553
+ byDenom: budgets.flatMap((b) => b.byDenom),
4554
+ counts: { settled: budgets.reduce((n, b) => n + b.counts.settled, 0) }
4555
+ };
4556
+ }
4557
+ /** The CONFIGURED spend policy (the shared policy `fromWallets` applies to every chain;
4558
+ * the first client's for the explicit constructor). `undefined` when none is set. */
4559
+ policy() {
4560
+ return this._clients[0].policy();
4066
4561
  }
4067
4562
  };
4068
4563
  function isBodyInit(value) {
@@ -4119,14 +4614,14 @@ function buildSelfDescription(input) {
4119
4614
  }
4120
4615
  function buildEndpointInfo(input) {
4121
4616
  const d = input.descriptor;
4122
- const summary = _nullishCoalesce(_optionalChain([d, 'optionalAccess', _67 => _67.summary]), () => ( input.description));
4123
- const hasInput = _optionalChain([d, 'optionalAccess', _68 => _68.queryParams]) && Object.keys(d.queryParams).length > 0;
4617
+ const summary = _nullishCoalesce(_optionalChain([d, 'optionalAccess', _82 => _82.summary]), () => ( input.description));
4618
+ const hasInput = _optionalChain([d, 'optionalAccess', _83 => _83.queryParams]) && Object.keys(d.queryParams).length > 0;
4124
4619
  const endpoint = {
4125
4620
  ...summary ? { summary } : {},
4126
- ..._optionalChain([d, 'optionalAccess', _69 => _69.method]) ? { method: d.method.toUpperCase() } : {},
4621
+ ..._optionalChain([d, 'optionalAccess', _84 => _84.method]) ? { method: d.method.toUpperCase() } : {},
4127
4622
  ...input.mimeType ? { mimeType: input.mimeType } : {},
4128
4623
  ...hasInput ? { input: d.queryParams } : {},
4129
- ..._optionalChain([d, 'optionalAccess', _70 => _70.output]) ? { output: d.output } : {}
4624
+ ..._optionalChain([d, 'optionalAccess', _85 => _85.output]) ? { output: d.output } : {}
4130
4625
  };
4131
4626
  return Object.keys(endpoint).length > 0 ? endpoint : void 0;
4132
4627
  }
@@ -4144,7 +4639,7 @@ function summarizePlan(plan) {
4144
4639
  return `NOT payable: ${_nullishCoalesce(plan.fundingHint, () => ( `no settleable rail on ${plan.network}`))}`;
4145
4640
  }
4146
4641
  function explainDecline(err) {
4147
- if (!(err instanceof _chunkJG6KRAW6cjs.PipRailError)) {
4642
+ if (!(err instanceof _chunkMWBT7MCEcjs.PipRailError)) {
4148
4643
  return `Payment failed: ${err instanceof Error ? err.message : String(err)}`;
4149
4644
  }
4150
4645
  switch (err.code) {
@@ -4167,9 +4662,12 @@ function explainDecline(err) {
4167
4662
  }
4168
4663
  function formatSpendReport(summary) {
4169
4664
  if (summary.count === 0) return "No payments yet.";
4170
- return summary.byAsset.map(
4665
+ const perAsset = summary.byAsset.map(
4171
4666
  (a) => `${a.totalFormatted} ${_nullishCoalesce(a.symbol, () => ( a.asset))} on ${a.network} (${a.count} payment${a.count === 1 ? "" : "s"})`
4172
4667
  ).join("; ");
4668
+ if (summary.byDenom.length === 0) return perAsset;
4669
+ const grand = summary.byDenom.map((d) => `${d.totalFormatted} ${d.denom} total`).join("; ");
4670
+ return `${perAsset} \u2014 grand total: ${grand}`;
4173
4671
  }
4174
4672
  function describeChallenge(challenge) {
4175
4673
  const first = challenge.accepts[0];
@@ -4248,9 +4746,11 @@ Branch on \`code\` (always reliable). Key cases:
4248
4746
  once (enable the exact scheme); report it, don't retry the same call blindly.
4249
4747
 
4250
4748
  ## Knowing your leash \u2014 call piprail_budget
4251
- piprail_budget tells you how much budget and time you have left, per
4252
- (network, asset), plus your spend so far. Read-only; moves no funds. Use it in
4253
- Mode A to self-check before paying.
4749
+ piprail_budget tells you how much budget and time you have left: per (network,
4750
+ asset) remaining, the cross-token GRAND TOTAL per denomination (e.g. how much
4751
+ USD you can still spend across every stablecoin and chain), the payment-count
4752
+ leash, the session time envelope, your spend so far, and the configured policy
4753
+ read back. Read-only; moves no funds. Use it in Mode A to self-check before paying.
4254
4754
 
4255
4755
  ## Two modes
4256
4756
  - Mode A (headless, default): you run FREE inside a pre-set budget + time
@@ -4261,10 +4761,15 @@ Mode A to self-check before paying.
4261
4761
  do NOT retry it as if it were a transient error.
4262
4762
 
4263
4763
  ## Hard facts
4264
- - Spend caps are PER (network, asset). There is no single cross-token dollar cap \u2014
4265
- budgets aren't summed across tokens (no price oracle).
4266
- - Spend totals and the time envelope live IN-MEMORY for THIS process; they reset on restart
4267
- (a convenience, not a durable ledger).
4764
+ - Per-payment + per-(network, asset) caps always apply. A cross-token GRAND TOTAL per
4765
+ denomination (maxTotalPerDenom, e.g. "$20 across every USD stablecoin + chain") is
4766
+ OPTIONAL \u2014 it sums tokens declared as one unit, each 1:1; it is NOT a price oracle and
4767
+ never prices a volatile native coin. Payment-COUNT caps (maxPayments / per-window) also
4768
+ span every chain + token.
4769
+ - The time envelope lives IN-MEMORY for THIS process (resets on restart). The money + count
4770
+ totals also reset on restart UNLESS a durable spend store is configured \u2014 then they resume.
4771
+ - A refusal arrives as declined:true with a reasonCode; 'BUDGET' covers the lifetime, denom,
4772
+ and count caps; 'OUTSIDE_WINDOW' covers both the rolling money and rolling count windows.
4268
4773
  `;
4269
4774
  function agentGuide() {
4270
4775
  return PIPRAIL_AGENT_GUIDE;
@@ -4277,19 +4782,19 @@ async function readBody(res) {
4277
4782
  if (!text) return null;
4278
4783
  try {
4279
4784
  return JSON.parse(text);
4280
- } catch (e31) {
4785
+ } catch (e34) {
4281
4786
  return text;
4282
4787
  }
4283
4788
  }
4284
4789
  function toToolError(err) {
4285
- if (!(err instanceof _chunkJG6KRAW6cjs.PipRailError)) throw err;
4790
+ if (!(err instanceof _chunkMWBT7MCEcjs.PipRailError)) throw err;
4286
4791
  const out = {
4287
4792
  ok: false,
4288
4793
  code: err.code,
4289
4794
  reason: err.message,
4290
4795
  explain: explainDecline(err)
4291
4796
  };
4292
- if (err instanceof _chunkJG6KRAW6cjs.PaymentDeclinedError) {
4797
+ if (err instanceof _chunkMWBT7MCEcjs.PaymentDeclinedError) {
4293
4798
  out.declined = true;
4294
4799
  if (err.reasonCode) out.reasonCode = err.reasonCode;
4295
4800
  }
@@ -4503,14 +5008,14 @@ function paymentTools(client) {
4503
5008
  receipt: parseReceipt(res)
4504
5009
  };
4505
5010
  } catch (err) {
4506
- if (err instanceof _chunkJG6KRAW6cjs.PipRailError) {
5011
+ if (err instanceof _chunkMWBT7MCEcjs.PipRailError) {
4507
5012
  const out = {
4508
5013
  ok: false,
4509
5014
  code: err.code,
4510
5015
  reason: err.message,
4511
5016
  explain: explainDecline(err)
4512
5017
  };
4513
- if (err instanceof _chunkJG6KRAW6cjs.PaymentDeclinedError) {
5018
+ if (err instanceof _chunkMWBT7MCEcjs.PaymentDeclinedError) {
4514
5019
  out.declined = true;
4515
5020
  if (err.reasonCode) out.reasonCode = err.reasonCode;
4516
5021
  }
@@ -4579,11 +5084,11 @@ function paymentTools(client) {
4579
5084
  },
4580
5085
  {
4581
5086
  name: "piprail_budget",
4582
- description: "Read how much of your spend budget and time leash is left \u2014 per (network, asset) remaining, the session time envelope, and your spend so far. Use it in Mode A (headless) to self-check BEFORE paying, so you never discover the leash by hitting a decline. Read-only; moves no funds. NOTE: totals and the time envelope are in-memory for THIS process and reset on restart.",
5087
+ description: "Read how much of your spend budget and time leash is left \u2014 per (network, asset) remaining, the cross-token GRAND TOTAL per denomination (e.g. how much USD you can still spend across every stablecoin and chain), the payment-count leash, the session time envelope, and your spend so far. Use it in Mode A (headless) to self-check BEFORE paying, so you never discover the leash by hitting a decline. Read-only; moves no funds. NOTE: the time envelope is in-memory for THIS process; the money/count totals persist only if a spend store is configured.",
4583
5088
  annotations: {
4584
5089
  title: "Check remaining budget",
4585
5090
  readOnlyHint: true,
4586
- // reads the in-memory ledger + policy; never pays
5091
+ // reads the ledger + policy; never pays
4587
5092
  idempotentHint: true
4588
5093
  // a pure read
4589
5094
  },
@@ -4596,7 +5101,13 @@ function paymentTools(client) {
4596
5101
  return {
4597
5102
  spent,
4598
5103
  remaining: budget.byAsset,
5104
+ grandTotal: budget.byDenom,
5105
+ // cross-token spend cap per denomination (USD/EUR/…)
5106
+ counts: budget.counts,
5107
+ // payment-count leash (settled + lifetime/window caps)
4599
5108
  session: budget.session,
5109
+ policy: _nullishCoalesce(client.policy(), () => ( null)),
5110
+ // the configured leash, read back
4600
5111
  report: formatSpendReport(spent)
4601
5112
  };
4602
5113
  } catch (err) {
@@ -4670,7 +5181,7 @@ function buildBazaarExtension(descriptor = {}) {
4670
5181
  function pathOf(url) {
4671
5182
  try {
4672
5183
  return new URL(url).pathname || "/";
4673
- } catch (e32) {
5184
+ } catch (e35) {
4674
5185
  return url.startsWith("/") ? url : `/${url}`;
4675
5186
  }
4676
5187
  }
@@ -4779,28 +5290,28 @@ async function fetchFacilitatorFeePayer(url, network, timeoutMs = 8e3) {
4779
5290
  const res = await fetch(`${base2}/supported`, { signal: ctrl.signal });
4780
5291
  if (!res.ok) return void 0;
4781
5292
  const body = await res.json();
4782
- const kinds = Array.isArray(_optionalChain([body, 'optionalAccess', _71 => _71.kinds])) ? body.kinds : [];
5293
+ const kinds = Array.isArray(_optionalChain([body, 'optionalAccess', _86 => _86.kinds])) ? body.kinds : [];
4783
5294
  const want = normalizeNetwork(network);
4784
- const kind = kinds.find((k) => _optionalChain([k, 'optionalAccess', _72 => _72.scheme]) === "exact" && normalizeNetwork(String(_nullishCoalesce(_optionalChain([k, 'optionalAccess', _73 => _73.network]), () => ( "")))) === want);
4785
- const fp = _optionalChain([kind, 'optionalAccess', _74 => _74.extra, 'optionalAccess', _75 => _75.feePayer]);
5295
+ const kind = kinds.find((k) => _optionalChain([k, 'optionalAccess', _87 => _87.scheme]) === "exact" && normalizeNetwork(String(_nullishCoalesce(_optionalChain([k, 'optionalAccess', _88 => _88.network]), () => ( "")))) === want);
5296
+ const fp = _optionalChain([kind, 'optionalAccess', _89 => _89.extra, 'optionalAccess', _90 => _90.feePayer]);
4786
5297
  return typeof fp === "string" ? fp : void 0;
4787
- } catch (e33) {
5298
+ } catch (e36) {
4788
5299
  return void 0;
4789
5300
  } finally {
4790
5301
  clearTimeout(timer);
4791
5302
  }
4792
5303
  }
4793
5304
  function parseFacilitatorSupported(body) {
4794
- const kinds = _optionalChain([body, 'optionalAccess', _76 => _76.kinds]);
5305
+ const kinds = _optionalChain([body, 'optionalAccess', _91 => _91.kinds]);
4795
5306
  if (!Array.isArray(kinds)) return [];
4796
5307
  const out = [];
4797
5308
  for (const k of kinds) {
4798
5309
  if (!k || typeof k !== "object") continue;
4799
5310
  const o = k;
4800
5311
  if (typeof o.scheme !== "string" || typeof o.network !== "string") continue;
4801
- const fp = _optionalChain([o, 'access', _77 => _77.extra, 'optionalAccess', _78 => _78.feePayer]);
5312
+ const fp = _optionalChain([o, 'access', _92 => _92.extra, 'optionalAccess', _93 => _93.feePayer]);
4802
5313
  const ver = o.x402Version;
4803
- const method = _optionalChain([o, 'access', _79 => _79.extra, 'optionalAccess', _80 => _80.assetTransferMethod]);
5314
+ const method = _optionalChain([o, 'access', _94 => _94.extra, 'optionalAccess', _95 => _95.assetTransferMethod]);
4804
5315
  out.push({
4805
5316
  scheme: o.scheme,
4806
5317
  network: o.network,
@@ -4819,7 +5330,7 @@ async function facilitatorCoverage(url, timeoutMs = 8e3) {
4819
5330
  const res = await fetch(`${base2}/supported`, { signal: ctrl.signal });
4820
5331
  if (!res.ok) return [];
4821
5332
  return parseFacilitatorSupported(await res.json());
4822
- } catch (e34) {
5333
+ } catch (e37) {
4823
5334
  return [];
4824
5335
  } finally {
4825
5336
  clearTimeout(timer);
@@ -4848,7 +5359,7 @@ async function post(url, body, headers) {
4848
5359
  let json = null;
4849
5360
  try {
4850
5361
  json = await res.json();
4851
- } catch (e35) {
5362
+ } catch (e38) {
4852
5363
  }
4853
5364
  return { status: res.status, json };
4854
5365
  }
@@ -4864,13 +5375,13 @@ async function settleViaFacilitator(input) {
4864
5375
  try {
4865
5376
  verify = await post(`${base2}/verify`, body, auth);
4866
5377
  } catch (err) {
4867
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
5378
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
4868
5379
  `exact settle (facilitator ${base2}): /verify request failed (${err instanceof Error ? err.message : String(err)}).`,
4869
5380
  { cause: err }
4870
5381
  );
4871
5382
  }
4872
5383
  if (verify.status !== 200) {
4873
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
5384
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
4874
5385
  `exact settle (facilitator ${base2}): /verify returned HTTP ${verify.status} (transport/auth error).`
4875
5386
  );
4876
5387
  }
@@ -4886,13 +5397,13 @@ async function settleViaFacilitator(input) {
4886
5397
  try {
4887
5398
  settle = await post(`${base2}/settle`, body, auth);
4888
5399
  } catch (err) {
4889
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
5400
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
4890
5401
  `exact settle (facilitator ${base2}): /settle request failed (${err instanceof Error ? err.message : String(err)}).`,
4891
5402
  { cause: err }
4892
5403
  );
4893
5404
  }
4894
5405
  if (settle.status !== 200) {
4895
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
5406
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
4896
5407
  `exact settle (facilitator ${base2}): /settle returned HTTP ${settle.status} (transport/auth error).`
4897
5408
  );
4898
5409
  }
@@ -5285,7 +5796,7 @@ function createPaymentGate(options) {
5285
5796
  }
5286
5797
  net.assertValidPayTo(payTo);
5287
5798
  const { asset, decimals, symbol } = net.resolveToken(a.token);
5288
- const amountBase = _chunkJG6KRAW6cjs.parseUnits.call(void 0, a.amount, decimals);
5799
+ const amountBase = _chunkMWBT7MCEcjs.parseUnits.call(void 0, a.amount, decimals);
5289
5800
  const spec = { net, asset, decimals, symbol, amountBase, amountFormatted: a.amount, payTo };
5290
5801
  if (exactOption) {
5291
5802
  const outcome = await resolveExactRail(net, asset);
@@ -5298,7 +5809,7 @@ function createPaymentGate(options) {
5298
5809
  if (exactOption && !specs.some((s) => s.exact)) {
5299
5810
  const why = exactSkips.length > 0 ? exactSkips.join(" ") : "The standard `exact` rail is EVM ERC-20 (EIP-3009 \u2014 USDC / EURC \u2014 or Permit2, e.g. Binance-Peg USDC on BNB) or a Solana SPL token (SVM) \u2014 NOT native coins, NOT families without a standard `exact` scheme.";
5300
5811
  if (exactOption.settle === "keyless") {
5301
- if (typeof process === "undefined" || !_optionalChain([process, 'optionalAccess', _81 => _81.env, 'optionalAccess', _82 => _82.PIPRAIL_NO_HINTS])) {
5812
+ if (typeof process === "undefined" || !_optionalChain([process, 'optionalAccess', _96 => _96.env, 'optionalAccess', _97 => _97.PIPRAIL_NO_HINTS])) {
5302
5813
  console.warn(
5303
5814
  `[piprail] exact: true \u2014 no offered chain has a gasless \`exact\` rail available, so this gate serves ONCHAIN-PROOF ONLY (buyers PAY GAS \u2014 the fallback when no facilitator can sponsor). ${why} To be gasless: pin \`exact: { settle: { facilitator } }\` or self-settle \`exact: { settle: 'self', relayer }\`. (Suppress with PIPRAIL_NO_HINTS=1.)`
5304
5815
  );
@@ -5326,7 +5837,7 @@ function createPaymentGate(options) {
5326
5837
  skipReason: `${net.network}: \`exact: true\` found no known keyless facilitator for this network. Pass \`exact: { settle: { facilitator } }\`, \`exact: { settle: 'self', relayer }\`, or see the coverage map (KNOWN_FACILITATORS / docs.piprail.com).`
5327
5838
  };
5328
5839
  }
5329
- if (typeof process === "undefined" || _optionalChain([process, 'optionalAccess', _83 => _83.env, 'optionalAccess', _84 => _84.NODE_ENV]) !== "production" && !_optionalChain([process, 'optionalAccess', _85 => _85.env, 'optionalAccess', _86 => _86.PIPRAIL_NO_HINTS])) {
5840
+ if (typeof process === "undefined" || _optionalChain([process, 'optionalAccess', _98 => _98.env, 'optionalAccess', _99 => _99.NODE_ENV]) !== "production" && !_optionalChain([process, 'optionalAccess', _100 => _100.env, 'optionalAccess', _101 => _101.PIPRAIL_NO_HINTS])) {
5330
5841
  console.warn(
5331
5842
  `[piprail] exact: keyless rail on ${net.network} auto-settles via ${picked.url} (zero-config; pin \`exact.settle.facilitator\` in production).`
5332
5843
  );
@@ -5460,7 +5971,7 @@ function createPaymentGate(options) {
5460
5971
  instruction: describeChallenge({ x402Version: 2, resource: { url: resourceUrl }, accepts }),
5461
5972
  ...endpointInfo ? { endpoint: endpointInfo } : {}
5462
5973
  });
5463
- const rejectionExt = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _87 => _87.extensions]), () => ( {}));
5974
+ const rejectionExt = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _102 => _102.extensions]), () => ( {}));
5464
5975
  const rejectionPiprail = _nullishCoalesce(rejectionExt.piprail, () => ( {}));
5465
5976
  const bodyPiprail = { ..._nullishCoalesce(selfDescribe, () => ( {})), ...rejectionPiprail };
5466
5977
  const bodyExtensions = {
@@ -5480,7 +5991,7 @@ function createPaymentGate(options) {
5480
5991
  ...options.mimeType ? { mimeType: options.mimeType } : {}
5481
5992
  },
5482
5993
  accepts,
5483
- ..._optionalChain([opts, 'optionalAccess', _88 => _88.error]) ? { error: opts.error } : {},
5994
+ ..._optionalChain([opts, 'optionalAccess', _103 => _103.error]) ? { error: opts.error } : {},
5484
5995
  ...Object.keys(bodyExtensions).length > 0 ? { extensions: bodyExtensions } : {}
5485
5996
  };
5486
5997
  const headerChallenge = {
@@ -5511,8 +6022,8 @@ function createPaymentGate(options) {
5511
6022
  function enrichReceipt(spec, receipt) {
5512
6023
  let amountFormatted = receipt.amount;
5513
6024
  try {
5514
- amountFormatted = _chunkJG6KRAW6cjs.formatUnits.call(void 0, BigInt(receipt.amount), spec.decimals);
5515
- } catch (e36) {
6025
+ amountFormatted = _chunkMWBT7MCEcjs.formatUnits.call(void 0, BigInt(receipt.amount), spec.decimals);
6026
+ } catch (e39) {
5516
6027
  }
5517
6028
  return {
5518
6029
  ...receipt,
@@ -5526,7 +6037,7 @@ function createPaymentGate(options) {
5526
6037
  if (!options.onPaidError) return;
5527
6038
  try {
5528
6039
  options.onPaidError(error, receipt);
5529
- } catch (e37) {
6040
+ } catch (e40) {
5530
6041
  }
5531
6042
  }
5532
6043
  function fireOnPaid(receipt) {
@@ -5551,7 +6062,7 @@ function createPaymentGate(options) {
5551
6062
  if (!options.onFailedError) return;
5552
6063
  try {
5553
6064
  options.onFailedError(error, failure);
5554
- } catch (e38) {
6065
+ } catch (e41) {
5555
6066
  }
5556
6067
  }
5557
6068
  function fireOnFailed(failure) {
@@ -5651,28 +6162,28 @@ function createPaymentGate(options) {
5651
6162
  nonce = [exact.payload.transaction, exact.payload.senderAuth].map((t) => {
5652
6163
  try {
5653
6164
  return Buffer.from(t, "base64").toString("base64");
5654
- } catch (e39) {
6165
+ } catch (e42) {
5655
6166
  return t;
5656
6167
  }
5657
6168
  }).join("|");
5658
6169
  } else if ("transaction" in exact.payload) {
5659
6170
  try {
5660
6171
  nonce = Buffer.from(exact.payload.transaction, "base64").toString("base64");
5661
- } catch (e40) {
6172
+ } catch (e43) {
5662
6173
  nonce = exact.payload.transaction;
5663
6174
  }
5664
6175
  } else if ("paymentGroup" in exact.payload) {
5665
6176
  nonce = exact.payload.paymentGroup.map((t) => {
5666
6177
  try {
5667
6178
  return Buffer.from(t, "base64").toString("base64");
5668
- } catch (e41) {
6179
+ } catch (e44) {
5669
6180
  return t;
5670
6181
  }
5671
6182
  }).join("|");
5672
6183
  } else if ("signedDelegateAction" in exact.payload) {
5673
6184
  try {
5674
6185
  nonce = Buffer.from(exact.payload.signedDelegateAction, "base64").toString("base64");
5675
- } catch (e42) {
6186
+ } catch (e45) {
5676
6187
  nonce = exact.payload.signedDelegateAction;
5677
6188
  }
5678
6189
  } else if ("permit2Authorization" in exact.payload) {
@@ -5695,7 +6206,7 @@ function createPaymentGate(options) {
5695
6206
  const ftMethod = accept.extra.assetTransferMethod;
5696
6207
  const needsFeePayer = ftMethod === "svm" || ftMethod === "algorand" || ftMethod === "aptos" || ftMethod === "near";
5697
6208
  if (needsFeePayer && !accept.extra.feePayer) {
5698
- throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
6209
+ throw new (0, _chunkMWBT7MCEcjs.SettlementError)(
5699
6210
  `exact settle: the ${ftMethod} facilitator rail is missing extra.feePayer (the gas sponsor) \u2014 cannot settle.`
5700
6211
  );
5701
6212
  }
@@ -5760,7 +6271,7 @@ function requirePayment(options) {
5760
6271
  try {
5761
6272
  result = await gate.verify(_nullishCoalesce(req.headers[HEADER_SIGNATURE], () => ( req.headers[HEADER_SIGNATURE_V1])));
5762
6273
  } catch (err) {
5763
- if (err instanceof _chunkJG6KRAW6cjs.SettlementError) {
6274
+ if (err instanceof _chunkMWBT7MCEcjs.SettlementError) {
5764
6275
  res.status(502);
5765
6276
  res.json({
5766
6277
  x402Version: 2,
@@ -5808,7 +6319,7 @@ function isRetryableStatus(status) {
5808
6319
  }
5809
6320
  var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
5810
6321
  async function signBody(secret, body) {
5811
- const subtle = _optionalChain([globalThis, 'access', _89 => _89.crypto, 'optionalAccess', _90 => _90.subtle]);
6322
+ const subtle = _optionalChain([globalThis, 'access', _104 => _104.crypto, 'optionalAccess', _105 => _105.subtle]);
5812
6323
  if (!subtle) return null;
5813
6324
  try {
5814
6325
  const enc = new TextEncoder();
@@ -5818,7 +6329,7 @@ async function signBody(secret, body) {
5818
6329
  const sig = await subtle.sign("HMAC", key, enc.encode(body));
5819
6330
  const hex = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
5820
6331
  return `sha256=${hex}`;
5821
- } catch (e43) {
6332
+ } catch (e46) {
5822
6333
  return null;
5823
6334
  }
5824
6335
  }
@@ -5878,8 +6389,8 @@ async function deliverReceipt(receipt, options) {
5878
6389
  const retryable = status === void 0 ? true : isRetryableStatus(status);
5879
6390
  const willRetry = !ok && retryable && attempt < maxAttempts;
5880
6391
  try {
5881
- _optionalChain([onAttempt, 'optionalCall', _91 => _91({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
5882
- } catch (e44) {
6392
+ _optionalChain([onAttempt, 'optionalCall', _106 => _106({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
6393
+ } catch (e47) {
5883
6394
  }
5884
6395
  if (ok) return { delivered: true, attempts: attempt, status };
5885
6396
  if (!willRetry) {
@@ -5998,4 +6509,9 @@ async function deliverReceipt(receipt, options) {
5998
6509
 
5999
6510
 
6000
6511
 
6001
- exports.BRAND = BRAND; exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkJG6KRAW6cjs.ConfirmationTimeoutError; exports.DIRECTORY_INFO = DIRECTORY_INFO; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkJG6KRAW6cjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkJG6KRAW6cjs.InvalidEnvelopeError; exports.KNOWN_FACILITATORS = KNOWN_FACILITATORS; exports.MaxRetriesExceededError = _chunkJG6KRAW6cjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkJG6KRAW6cjs.MissingDriverError; exports.MultiChainPayer = MultiChainPayer; exports.NoCompatibleAcceptError = _chunkJG6KRAW6cjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkJG6KRAW6cjs.NonReplayableBodyError; exports.PERMIT2_ADDRESS = PERMIT2_ADDRESS; exports.PERMIT2_PROXY_CHAIN_IDS = PERMIT2_PROXY_CHAIN_IDS; exports.PERMIT2_WITNESS_TYPES = PERMIT2_WITNESS_TYPES; exports.PIPRAIL_AGENT_GUIDE = PIPRAIL_AGENT_GUIDE; exports.POWERED_BY = POWERED_BY; exports.PaymentDeclinedError = _chunkJG6KRAW6cjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkJG6KRAW6cjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkJG6KRAW6cjs.PipRailError; exports.REGISTER_ATTRIBUTION = REGISTER_ATTRIBUTION; exports.RecipientNotReadyError = _chunkJG6KRAW6cjs.RecipientNotReadyError; exports.SettlementError = _chunkJG6KRAW6cjs.SettlementError; exports.UnknownTokenError = _chunkJG6KRAW6cjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkJG6KRAW6cjs.UnsupportedNetworkError; exports.UnsupportedSchemeError = _chunkJG6KRAW6cjs.UnsupportedSchemeError; exports.WalletRequiredError = _chunkJG6KRAW6cjs.WalletRequiredError; exports.WrongChainError = _chunkJG6KRAW6cjs.WrongChainError; exports.WrongFamilyError = _chunkJG6KRAW6cjs.WrongFamilyError; exports.X402_EXACT_PERMIT2_PROXY = X402_EXACT_PERMIT2_PROXY; exports.agentGuide = agentGuide; exports.appendAttribution = appendAttribution; exports.appendKeywords = appendKeywords; exports.buildBazaarExtension = buildBazaarExtension; exports.buildChallengeHeader = buildChallengeHeader; exports.buildEndpointInfo = buildEndpointInfo; exports.buildExactAuthorization = buildExactAuthorization; exports.buildExactSignatureHeader = buildExactSignatureHeader; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSelfDescription = buildSelfDescription; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.classifyChallenge = classifyChallenge; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.deliverReceipt = deliverReceipt; exports.describeChallenge = describeChallenge; exports.discoveryHeaders = discoveryHeaders; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.explainDecline = explainDecline; exports.facilitatorCoverage = facilitatorCoverage; exports.fetchAcross = fetchAcross; exports.firstKeylessFacilitator = firstKeylessFacilitator; exports.formatSpendReport = formatSpendReport; exports.getDirectoryInfo = getDirectoryInfo; exports.isPermit2ProxyChain = isPermit2ProxyChain; exports.knownFacilitatorsFor = knownFacilitatorsFor; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseFacilitatorSupported = parseFacilitatorSupported; exports.parseReceipt = parseReceipt; exports.parseSettleResponse = parseSettleResponse; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.rankResources = rankResources; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.renderLandingPage = renderLandingPage; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.scoreResource = scoreResource; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.summarizePlan = summarizePlan; exports.toInsufficientFundsError = _chunkJG6KRAW6cjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;
6512
+
6513
+
6514
+
6515
+
6516
+
6517
+ exports.BRAND = BRAND; exports.BUILTIN_DENOMS = BUILTIN_DENOMS; exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkMWBT7MCEcjs.ConfirmationTimeoutError; exports.DENOM_PRECISION = DENOM_PRECISION; exports.DIRECTORY_INFO = DIRECTORY_INFO; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkMWBT7MCEcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkMWBT7MCEcjs.InvalidEnvelopeError; exports.KNOWN_FACILITATORS = KNOWN_FACILITATORS; exports.MaxRetriesExceededError = _chunkMWBT7MCEcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkMWBT7MCEcjs.MissingDriverError; exports.MultiChainPayer = MultiChainPayer; exports.NoCompatibleAcceptError = _chunkMWBT7MCEcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkMWBT7MCEcjs.NonReplayableBodyError; exports.PERMIT2_ADDRESS = PERMIT2_ADDRESS; exports.PERMIT2_PROXY_CHAIN_IDS = PERMIT2_PROXY_CHAIN_IDS; exports.PERMIT2_WITNESS_TYPES = PERMIT2_WITNESS_TYPES; exports.PIPRAIL_AGENT_GUIDE = PIPRAIL_AGENT_GUIDE; exports.POWERED_BY = POWERED_BY; exports.PaymentDeclinedError = _chunkMWBT7MCEcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkMWBT7MCEcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkMWBT7MCEcjs.PipRailError; exports.REGISTER_ATTRIBUTION = REGISTER_ATTRIBUTION; exports.RecipientNotReadyError = _chunkMWBT7MCEcjs.RecipientNotReadyError; exports.SettlementError = _chunkMWBT7MCEcjs.SettlementError; exports.SpendLedger = SpendLedger; exports.UnknownTokenError = _chunkMWBT7MCEcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkMWBT7MCEcjs.UnsupportedNetworkError; exports.UnsupportedSchemeError = _chunkMWBT7MCEcjs.UnsupportedSchemeError; exports.WalletRequiredError = _chunkMWBT7MCEcjs.WalletRequiredError; exports.WrongChainError = _chunkMWBT7MCEcjs.WrongChainError; exports.WrongFamilyError = _chunkMWBT7MCEcjs.WrongFamilyError; exports.X402_EXACT_PERMIT2_PROXY = X402_EXACT_PERMIT2_PROXY; exports.agentGuide = agentGuide; exports.appendAttribution = appendAttribution; exports.appendKeywords = appendKeywords; exports.buildBazaarExtension = buildBazaarExtension; exports.buildChallengeHeader = buildChallengeHeader; exports.buildEndpointInfo = buildEndpointInfo; exports.buildExactAuthorization = buildExactAuthorization; exports.buildExactSignatureHeader = buildExactSignatureHeader; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSelfDescription = buildSelfDescription; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.classifyChallenge = classifyChallenge; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.deliverReceipt = deliverReceipt; exports.denomOf = denomOf; exports.describeChallenge = describeChallenge; exports.discoveryHeaders = discoveryHeaders; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.explainDecline = explainDecline; exports.facilitatorCoverage = facilitatorCoverage; exports.fetchAcross = fetchAcross; exports.firstKeylessFacilitator = firstKeylessFacilitator; exports.formatSpendReport = formatSpendReport; exports.getDirectoryInfo = getDirectoryInfo; exports.isPermit2ProxyChain = isPermit2ProxyChain; exports.knownFacilitatorsFor = knownFacilitatorsFor; exports.memorySpendStore = _chunkO4UQOZ4Zcjs.memorySpendStore; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseFacilitatorSupported = parseFacilitatorSupported; exports.parseReceipt = parseReceipt; exports.parseSettleResponse = parseSettleResponse; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.rankResources = rankResources; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.renderLandingPage = renderLandingPage; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.scoreResource = scoreResource; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.summarizePlan = summarizePlan; exports.toInsufficientFundsError = _chunkMWBT7MCEcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;