@agent-score/commerce 2.0.2 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +26 -11
  2. package/dist/_core-kI7FRAiZ.d.mts +10 -0
  3. package/dist/_core-kI7FRAiZ.d.ts +10 -0
  4. package/dist/challenge/index.d.mts +3 -3
  5. package/dist/challenge/index.d.ts +3 -3
  6. package/dist/challenge/index.js +21 -14
  7. package/dist/challenge/index.js.map +1 -1
  8. package/dist/challenge/index.mjs +21 -14
  9. package/dist/challenge/index.mjs.map +1 -1
  10. package/dist/{checkout-jNUIql6D.d.mts → checkout-BRw_caGr.d.mts} +13 -33
  11. package/dist/{checkout-DhSj_h94.d.ts → checkout-CuSNUJFX.d.ts} +13 -33
  12. package/dist/core.js +1 -1
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +1 -1
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/default_rails-C5gKZJMI.d.ts +198 -0
  17. package/dist/default_rails-XFCuRddA.d.mts +198 -0
  18. package/dist/discovery/index.d.mts +5 -5
  19. package/dist/discovery/index.d.ts +5 -5
  20. package/dist/discovery/index.js +14 -1
  21. package/dist/discovery/index.js.map +1 -1
  22. package/dist/discovery/index.mjs +14 -1
  23. package/dist/discovery/index.mjs.map +1 -1
  24. package/dist/identity/express.d.mts +7 -3
  25. package/dist/identity/express.d.ts +7 -3
  26. package/dist/identity/express.js +39 -96
  27. package/dist/identity/express.js.map +1 -1
  28. package/dist/identity/express.mjs +37 -87
  29. package/dist/identity/express.mjs.map +1 -1
  30. package/dist/identity/fastify.d.mts +4 -4
  31. package/dist/identity/fastify.d.ts +4 -4
  32. package/dist/identity/fastify.js +60 -96
  33. package/dist/identity/fastify.js.map +1 -1
  34. package/dist/identity/fastify.mjs +58 -87
  35. package/dist/identity/fastify.mjs.map +1 -1
  36. package/dist/identity/hono.d.mts +11 -3
  37. package/dist/identity/hono.d.ts +11 -3
  38. package/dist/identity/hono.js +39 -93
  39. package/dist/identity/hono.js.map +1 -1
  40. package/dist/identity/hono.mjs +37 -84
  41. package/dist/identity/hono.mjs.map +1 -1
  42. package/dist/identity/nextjs.d.mts +10 -3
  43. package/dist/identity/nextjs.d.ts +10 -3
  44. package/dist/identity/nextjs.js +49 -93
  45. package/dist/identity/nextjs.js.map +1 -1
  46. package/dist/identity/nextjs.mjs +46 -84
  47. package/dist/identity/nextjs.mjs.map +1 -1
  48. package/dist/identity/policy.js +22 -23317
  49. package/dist/identity/policy.js.map +1 -1
  50. package/dist/identity/policy.mjs +1 -23320
  51. package/dist/identity/policy.mjs.map +1 -1
  52. package/dist/identity/web.d.mts +9 -3
  53. package/dist/identity/web.d.ts +9 -3
  54. package/dist/identity/web.js +45 -93
  55. package/dist/identity/web.js.map +1 -1
  56. package/dist/identity/web.mjs +42 -84
  57. package/dist/identity/web.mjs.map +1 -1
  58. package/dist/index.d.mts +621 -90
  59. package/dist/index.d.ts +621 -90
  60. package/dist/index.js +1202 -328
  61. package/dist/index.js.map +1 -1
  62. package/dist/index.mjs +1188 -327
  63. package/dist/index.mjs.map +1 -1
  64. package/dist/middleware/express.d.mts +10 -0
  65. package/dist/middleware/express.d.ts +10 -0
  66. package/dist/middleware/express.js +128 -0
  67. package/dist/middleware/express.js.map +1 -0
  68. package/dist/middleware/express.mjs +91 -0
  69. package/dist/middleware/express.mjs.map +1 -0
  70. package/dist/middleware/fastify.d.mts +10 -0
  71. package/dist/middleware/fastify.d.ts +10 -0
  72. package/dist/middleware/fastify.js +127 -0
  73. package/dist/middleware/fastify.js.map +1 -0
  74. package/dist/middleware/fastify.mjs +90 -0
  75. package/dist/middleware/fastify.mjs.map +1 -0
  76. package/dist/middleware/hono.d.mts +10 -0
  77. package/dist/middleware/hono.d.ts +10 -0
  78. package/dist/middleware/hono.js +122 -0
  79. package/dist/middleware/hono.js.map +1 -0
  80. package/dist/middleware/hono.mjs +85 -0
  81. package/dist/middleware/hono.mjs.map +1 -0
  82. package/dist/middleware/nextjs.d.mts +22 -0
  83. package/dist/middleware/nextjs.d.ts +22 -0
  84. package/dist/middleware/nextjs.js +143 -0
  85. package/dist/middleware/nextjs.js.map +1 -0
  86. package/dist/middleware/nextjs.mjs +105 -0
  87. package/dist/middleware/nextjs.mjs.map +1 -0
  88. package/dist/middleware/web.d.mts +25 -0
  89. package/dist/middleware/web.d.ts +25 -0
  90. package/dist/middleware/web.js +128 -0
  91. package/dist/middleware/web.js.map +1 -0
  92. package/dist/middleware/web.mjs +91 -0
  93. package/dist/middleware/web.mjs.map +1 -0
  94. package/dist/payment/index.d.mts +32 -21
  95. package/dist/payment/index.d.ts +32 -21
  96. package/dist/payment/index.js +215 -12
  97. package/dist/payment/index.js.map +1 -1
  98. package/dist/payment/index.mjs +205 -12
  99. package/dist/payment/index.mjs.map +1 -1
  100. package/dist/{pricing-CxzwyiO6.d.mts → pricing-4n5Ota0D.d.mts} +14 -4
  101. package/dist/{pricing-CQ9DIFaw.d.ts → pricing-DHfH3ogG.d.ts} +14 -4
  102. package/dist/{rail_spec-XP0wKgJV.d.mts → rail_spec-D6qzh3J0.d.mts} +1 -1
  103. package/dist/{rail_spec-XP0wKgJV.d.ts → rail_spec-D6qzh3J0.d.ts} +1 -1
  104. package/dist/stripe-multichain/index.d.mts +150 -47
  105. package/dist/stripe-multichain/index.d.ts +150 -47
  106. package/dist/stripe-multichain/index.js +19799 -43
  107. package/dist/stripe-multichain/index.js.map +1 -1
  108. package/dist/stripe-multichain/index.mjs +19808 -28
  109. package/dist/stripe-multichain/index.mjs.map +1 -1
  110. package/dist/{x402_server-hgQzWQwB.d.mts → x402_server-Ciz2mls2.d.mts} +1 -1
  111. package/dist/{x402_server-hgQzWQwB.d.ts → x402_server-Ciz2mls2.d.ts} +1 -1
  112. package/package.json +43 -5
  113. package/dist/_response-BFYN3b6i.d.mts +0 -142
  114. package/dist/_response-_iPD5AIj.d.ts +0 -142
  115. package/dist/solana-Cds87OTu.d.mts +0 -67
  116. package/dist/solana-Cds87OTu.d.ts +0 -67
package/dist/index.mjs CHANGED
@@ -31,6 +31,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  mod
32
32
  ));
33
33
 
34
+ // src/payment/network_kind.ts
35
+ function readNetwork(input) {
36
+ if (typeof input === "string") return input;
37
+ if (input && typeof input === "object") {
38
+ const network = input.network;
39
+ return typeof network === "string" ? network : "";
40
+ }
41
+ return "";
42
+ }
43
+ function isEvmNetwork(input) {
44
+ return readNetwork(input).startsWith("eip155:");
45
+ }
46
+ function isSolanaNetwork(input) {
47
+ return readNetwork(input).startsWith("solana:");
48
+ }
49
+ var init_network_kind = __esm({
50
+ "src/payment/network_kind.ts"() {
51
+ "use strict";
52
+ }
53
+ });
54
+
34
55
  // src/identity/ucp.ts
35
56
  function ucpSigningKeyFromJWKImpl(jwk) {
36
57
  if (!jwk || typeof jwk !== "object") {
@@ -160,7 +181,7 @@ function isTempoSessionRailSpec(s) {
160
181
  }
161
182
  function mppRailToNetworkEntry(spec) {
162
183
  if (isTempoSessionRailSpec(spec)) return tempoSessionToNetworkEntry(spec);
163
- if ("rpcUrl" in spec || "tokenProgram" in spec || (spec.network?.startsWith("solana:") ?? false)) {
184
+ if ("rpcUrl" in spec || "tokenProgram" in spec || isSolanaNetwork(spec)) {
164
185
  return solanaMppToNetworkEntry(spec);
165
186
  }
166
187
  if (isTempoRailSpec(spec)) return tempoToNetworkEntry(spec);
@@ -217,6 +238,7 @@ var UCPSigningKey, DEFAULT_VERSION, AGENTSCORE_CAPABILITY_NAME, AGENTSCORE_CAPAB
217
238
  var init_ucp = __esm({
218
239
  "src/identity/ucp.ts"() {
219
240
  "use strict";
241
+ init_network_kind();
220
242
  UCPSigningKey = {
221
243
  fromJWK: ucpSigningKeyFromJWKImpl
222
244
  };
@@ -636,64 +658,6 @@ var init_ucp_jwks = __esm({
636
658
  }
637
659
  });
638
660
 
639
- // src/payment/usdc.ts
640
- var USDC;
641
- var init_usdc = __esm({
642
- "src/payment/usdc.ts"() {
643
- "use strict";
644
- USDC = {
645
- base: {
646
- mainnet: { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", decimals: 6 },
647
- sepolia: { address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", decimals: 6 }
648
- },
649
- solana: {
650
- mainnet: { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", decimals: 6 },
651
- devnet: { mint: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", decimals: 6 }
652
- },
653
- tempo: {
654
- mainnet: { address: "0x20C000000000000000000000b9537d11c60E8b50", decimals: 6 },
655
- testnet: { address: "0x20c0000000000000000000000000000000000000", decimals: 6 }
656
- }
657
- };
658
- }
659
- });
660
-
661
- // src/payment/wwwauthenticate.ts
662
- function paymentRequiredHeader({
663
- x402Version,
664
- accepts,
665
- resource
666
- }) {
667
- return Buffer.from(JSON.stringify({ x402Version, accepts, ...resource ? { resource } : {} })).toString("base64");
668
- }
669
- var init_wwwauthenticate = __esm({
670
- "src/payment/wwwauthenticate.ts"() {
671
- "use strict";
672
- }
673
- });
674
-
675
- // src/payment/networks.ts
676
- var networks;
677
- var init_networks = __esm({
678
- "src/payment/networks.ts"() {
679
- "use strict";
680
- networks = {
681
- base: {
682
- mainnet: { caip2: "eip155:8453", chainId: 8453 },
683
- sepolia: { caip2: "eip155:84532", chainId: 84532 }
684
- },
685
- solana: {
686
- mainnet: { caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" },
687
- devnet: { caip2: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" }
688
- },
689
- tempo: {
690
- mainnet: { caip2: "eip155:4217", chainId: 4217 },
691
- testnet: { caip2: "eip155:42431", chainId: 42431 }
692
- }
693
- };
694
- }
695
- });
696
-
697
661
  // node_modules/ox/_esm/core/Abi.js
698
662
  var init_Abi = __esm({
699
663
  "node_modules/ox/_esm/core/Abi.js"() {
@@ -20305,6 +20269,64 @@ var init_dist2 = __esm({
20305
20269
  }
20306
20270
  });
20307
20271
 
20272
+ // src/payment/usdc.ts
20273
+ var USDC;
20274
+ var init_usdc = __esm({
20275
+ "src/payment/usdc.ts"() {
20276
+ "use strict";
20277
+ USDC = {
20278
+ base: {
20279
+ mainnet: { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", decimals: 6 },
20280
+ sepolia: { address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", decimals: 6 }
20281
+ },
20282
+ solana: {
20283
+ mainnet: { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", decimals: 6 },
20284
+ devnet: { mint: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", decimals: 6 }
20285
+ },
20286
+ tempo: {
20287
+ mainnet: { address: "0x20C000000000000000000000b9537d11c60E8b50", decimals: 6 },
20288
+ testnet: { address: "0x20c0000000000000000000000000000000000000", decimals: 6 }
20289
+ }
20290
+ };
20291
+ }
20292
+ });
20293
+
20294
+ // src/payment/wwwauthenticate.ts
20295
+ function paymentRequiredHeader({
20296
+ x402Version,
20297
+ accepts,
20298
+ resource
20299
+ }) {
20300
+ return Buffer.from(JSON.stringify({ x402Version, accepts, ...resource ? { resource } : {} })).toString("base64");
20301
+ }
20302
+ var init_wwwauthenticate = __esm({
20303
+ "src/payment/wwwauthenticate.ts"() {
20304
+ "use strict";
20305
+ }
20306
+ });
20307
+
20308
+ // src/payment/networks.ts
20309
+ var networks;
20310
+ var init_networks = __esm({
20311
+ "src/payment/networks.ts"() {
20312
+ "use strict";
20313
+ networks = {
20314
+ base: {
20315
+ mainnet: { caip2: "eip155:8453", chainId: 8453 },
20316
+ sepolia: { caip2: "eip155:84532", chainId: 84532 }
20317
+ },
20318
+ solana: {
20319
+ mainnet: { caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" },
20320
+ devnet: { caip2: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" }
20321
+ },
20322
+ tempo: {
20323
+ mainnet: { caip2: "eip155:4217", chainId: 4217 },
20324
+ testnet: { caip2: "eip155:42431", chainId: 42431 }
20325
+ }
20326
+ };
20327
+ }
20328
+ });
20329
+
20308
20330
  // src/payment/rails.ts
20309
20331
  function lookupRail(name) {
20310
20332
  return rails[name];
@@ -20968,6 +20990,20 @@ var RESERVED_FIELDS = /* @__PURE__ */ new Set([
20968
20990
  "actual_signer",
20969
20991
  "linked_wallets"
20970
20992
  ]);
20993
+ function buildVerificationRequiredBody(reason, opts = {}) {
20994
+ const body = denialReasonToBody(reason);
20995
+ body.error = {
20996
+ code: "operator_verification_required",
20997
+ message: opts.message ?? "Identity verification is required."
20998
+ };
20999
+ if (opts.agentInstructions !== void 0) {
21000
+ body.agent_instructions = opts.agentInstructions;
21001
+ }
21002
+ if (opts.extra) {
21003
+ for (const [k, v] of Object.entries(opts.extra)) body[k] = v;
21004
+ }
21005
+ return body;
21006
+ }
20971
21007
  function denialReasonToBody(reason) {
20972
21008
  const message = reason.message ?? DEFAULT_MESSAGES[reason.code];
20973
21009
  const body = { error: { code: reason.code, message } };
@@ -21125,7 +21161,7 @@ function createAgentScoreCore(options) {
21125
21161
  } = options;
21126
21162
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21127
21163
  const agentMemoryHint = buildAgentMemoryHint();
21128
- const defaultUa = `@agent-score/commerce@${"2.0.2"}`;
21164
+ const defaultUa = `@agent-score/commerce@${"2.1.1"}`;
21129
21165
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21130
21166
  const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21131
21167
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21417,6 +21453,13 @@ function createAgentScoreCore(options) {
21417
21453
  return { evaluate, captureWallet, getSignerVerdict };
21418
21454
  }
21419
21455
 
21456
+ // src/_headers.ts
21457
+ function normalizeHeadersToLowercase(headers) {
21458
+ const out = {};
21459
+ for (const [k, v] of Object.entries(headers)) out[k.toLowerCase()] = v;
21460
+ return out;
21461
+ }
21462
+
21420
21463
  // src/signer.ts
21421
21464
  var TOKEN_PROGRAM = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
21422
21465
  var TOKEN_2022_PROGRAM = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
@@ -21499,13 +21542,8 @@ async function extractPaymentSignerFromAuth(authHeader, x402PaymentHeader) {
21499
21542
  function readX402PaymentHeader(request) {
21500
21543
  return request.headers.get("payment-signature") ?? request.headers.get("x-payment") ?? void 0;
21501
21544
  }
21502
- function lowerHeaders(headers) {
21503
- const out = {};
21504
- for (const [k, v] of Object.entries(headers)) out[k.toLowerCase()] = v;
21505
- return out;
21506
- }
21507
21545
  async function extractSignerForPrecheck(headers) {
21508
- const lower = lowerHeaders(headers);
21546
+ const lower = normalizeHeadersToLowercase(headers);
21509
21547
  const x402 = lower["payment-signature"] ?? lower["x-payment"];
21510
21548
  if (x402) {
21511
21549
  const signer = await extractPaymentSignerFromAuth(void 0, x402);
@@ -21520,7 +21558,7 @@ async function extractSignerForPrecheck(headers) {
21520
21558
 
21521
21559
  // src/identity/a2a.ts
21522
21560
  var PROTOCOL_VERSION = "1.0";
21523
- var DEFAULT_PROTOCOL_BINDING = "HTTP+JSON";
21561
+ var DEFAULT_TRANSPORT = "JSONRPC";
21524
21562
  var DEFAULT_INPUT_MODE = "application/json";
21525
21563
  var DEFAULT_OUTPUT_MODE = "application/json";
21526
21564
  var UCP_A2A_EXTENSION_URI = "https://ucp.dev/2026-04-08/specification/reference";
@@ -21540,30 +21578,33 @@ function buildA2AAgentCard(input) {
21540
21578
  }
21541
21579
  const capabilities = {};
21542
21580
  if (input.streaming !== void 0) capabilities.streaming = input.streaming;
21543
- if (input.push_notifications !== void 0) capabilities.push_notifications = input.push_notifications;
21581
+ if (input.pushNotifications !== void 0) capabilities.pushNotifications = input.pushNotifications;
21582
+ if (input.stateTransitionHistory !== void 0) capabilities.stateTransitionHistory = input.stateTransitionHistory;
21544
21583
  if (input.extensions && input.extensions.length > 0) capabilities.extensions = input.extensions;
21545
- if (input.extended_agent_card !== void 0) capabilities.extended_agent_card = input.extended_agent_card;
21546
- const primaryInterface = {
21547
- url: input.url,
21548
- protocol_binding: input.protocol_binding ?? DEFAULT_PROTOCOL_BINDING,
21549
- protocol_version: input.a2a_protocol_version ?? PROTOCOL_VERSION
21550
- };
21551
21584
  const card = {
21552
21585
  name: input.name,
21553
21586
  description: input.description,
21554
- supported_interfaces: [primaryInterface],
21587
+ url: input.url,
21588
+ preferredTransport: input.preferredTransport ?? "HTTP+JSON",
21589
+ protocolVersion: input.protocolVersion ?? PROTOCOL_VERSION,
21555
21590
  version: input.version ?? "1.0.0",
21556
21591
  capabilities,
21557
- default_input_modes: input.default_input_modes ?? [DEFAULT_INPUT_MODE],
21558
- default_output_modes: input.default_output_modes ?? [DEFAULT_OUTPUT_MODE],
21592
+ defaultInputModes: input.defaultInputModes ?? [DEFAULT_INPUT_MODE],
21593
+ defaultOutputModes: input.defaultOutputModes ?? [DEFAULT_OUTPUT_MODE],
21559
21594
  skills: input.skills
21560
21595
  };
21596
+ if (input.additionalInterfaces !== void 0 && input.additionalInterfaces.length > 0) {
21597
+ card.additionalInterfaces = input.additionalInterfaces;
21598
+ }
21561
21599
  if (input.provider !== void 0) card.provider = input.provider;
21562
- if (input.documentation_url !== void 0) card.documentation_url = input.documentation_url;
21563
- if (input.icon_url !== void 0) card.icon_url = input.icon_url;
21600
+ if (input.documentationUrl !== void 0) card.documentationUrl = input.documentationUrl;
21601
+ if (input.iconUrl !== void 0) card.iconUrl = input.iconUrl;
21602
+ if (input.supportsAuthenticatedExtendedCard !== void 0) {
21603
+ card.supportsAuthenticatedExtendedCard = input.supportsAuthenticatedExtendedCard;
21604
+ }
21564
21605
  if (input.signatures !== void 0 && input.signatures.length > 0) card.signatures = input.signatures;
21565
- if (input.security_schemes !== void 0) card.security_schemes = input.security_schemes;
21566
- if (input.security_requirements !== void 0) card.security_requirements = input.security_requirements;
21606
+ if (input.security !== void 0) card.security = input.security;
21607
+ if (input.securitySchemes !== void 0) card.securitySchemes = input.securitySchemes;
21567
21608
  if (input.extras) {
21568
21609
  for (const [k, v] of Object.entries(input.extras)) {
21569
21610
  card[k] = v;
@@ -21571,89 +21612,250 @@ function buildA2AAgentCard(input) {
21571
21612
  }
21572
21613
  return card;
21573
21614
  }
21615
+ var A2A_PROTOCOL_VERSION = PROTOCOL_VERSION;
21616
+ var A2A_DEFAULT_TRANSPORT = DEFAULT_TRANSPORT;
21574
21617
 
21575
21618
  // src/index.ts
21576
21619
  init_ucp();
21577
21620
  init_ucp_jwks();
21578
21621
 
21579
- // src/checkout.ts
21580
- import { randomUUID } from "crypto";
21581
-
21582
- // src/payment/rail_spec.ts
21583
- init_usdc();
21584
- async function resolveRecipient(r) {
21585
- if (typeof r === "string") return r;
21586
- return Promise.resolve(r());
21587
- }
21588
- var RAIL_SPEC_DEFAULTS = {
21589
- tempo: {
21590
- network: "tempo-mainnet",
21591
- chainId: 4217,
21592
- token: USDC.tempo.mainnet.address,
21593
- symbol: "USDC.e",
21594
- decimals: 6,
21595
- testnet: false,
21596
- recommend: "both"
21597
- },
21598
- x402Base: {
21599
- network: "eip155:8453",
21600
- chainId: 8453,
21601
- token: USDC.base.mainnet.address,
21602
- symbol: "USDC",
21603
- decimals: 6,
21604
- mode: "exact"
21605
- },
21606
- solanaMpp: {
21607
- network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
21608
- token: USDC.solana.mainnet.mint,
21609
- symbol: "USDC",
21610
- decimals: 6
21611
- },
21612
- stripe: {
21613
- rails: ["card", "link", "shared_payment_token"]
21614
- },
21615
- tempoSession: {
21616
- currency: USDC.tempo.mainnet.address,
21617
- testnet: false
21622
+ // src/errors.ts
21623
+ var CheckoutValidationError = class extends Error {
21624
+ code;
21625
+ action;
21626
+ status;
21627
+ extra;
21628
+ constructor(opts) {
21629
+ super(opts.message);
21630
+ this.name = "CheckoutValidationError";
21631
+ this.code = opts.code;
21632
+ this.action = opts.action ?? "fix_request";
21633
+ this.status = opts.status ?? 400;
21634
+ this.extra = opts.extra;
21618
21635
  }
21619
21636
  };
21620
21637
 
21621
- // src/challenge/accepted_methods.ts
21622
- async function buildAcceptedMethods({
21623
- tempo,
21624
- x402_base,
21625
- solana_mpp,
21626
- stripe
21627
- }) {
21628
- const out = [];
21629
- if (tempo) {
21630
- out.push({
21631
- method: "tempo/charge",
21632
- network: tempo.network ?? RAIL_SPEC_DEFAULTS.tempo.network,
21633
- chain_id: tempo.chainId ?? RAIL_SPEC_DEFAULTS.tempo.chainId,
21634
- token: tempo.token ?? RAIL_SPEC_DEFAULTS.tempo.token,
21635
- symbol: tempo.symbol ?? RAIL_SPEC_DEFAULTS.tempo.symbol,
21636
- decimals: tempo.decimals ?? RAIL_SPEC_DEFAULTS.tempo.decimals,
21637
- pay_to: await resolveRecipient(tempo.recipient)
21638
- });
21639
- }
21640
- if (x402_base) {
21641
- out.push({
21642
- method: "x402/exact",
21643
- network: x402_base.network ?? RAIL_SPEC_DEFAULTS.x402Base.network,
21644
- chain_id: x402_base.chainId ?? RAIL_SPEC_DEFAULTS.x402Base.chainId,
21645
- token: x402_base.token ?? RAIL_SPEC_DEFAULTS.x402Base.token,
21646
- symbol: x402_base.symbol ?? RAIL_SPEC_DEFAULTS.x402Base.symbol,
21647
- decimals: x402_base.decimals ?? RAIL_SPEC_DEFAULTS.x402Base.decimals,
21648
- pay_to: await resolveRecipient(x402_base.recipient)
21649
- });
21638
+ // src/identity/policy.ts
21639
+ function buildGateFromPolicy(policy, base) {
21640
+ if (!policy || !policy.enforcement) return null;
21641
+ return {
21642
+ apiKey: base.apiKey,
21643
+ ...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
21644
+ ...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
21645
+ ...policy.requireSanctionsClear !== void 0 && {
21646
+ requireSanctionsClear: policy.requireSanctionsClear
21647
+ },
21648
+ ...policy.minAge !== void 0 && { minAge: policy.minAge },
21649
+ ...policy.allowedJurisdictions !== void 0 && {
21650
+ allowedJurisdictions: [...policy.allowedJurisdictions]
21651
+ }
21652
+ };
21653
+ }
21654
+ async function runGateWithEnforcement(enforcement, runGate) {
21655
+ if (!runGate || !enforcement) return { status: "anonymous" };
21656
+ const outcome = await runGate();
21657
+ if (outcome.ok) return { status: "verified" };
21658
+ if (enforcement === "hard") {
21659
+ return {
21660
+ status: "denied",
21661
+ denialStatus: outcome.status,
21662
+ denialBody: outcome.body,
21663
+ ...outcome.reason !== void 0 && { denialReason: outcome.reason }
21664
+ };
21650
21665
  }
21651
- if (solana_mpp) {
21652
- out.push({
21653
- method: "solana/charge",
21654
- network: solana_mpp.network ?? RAIL_SPEC_DEFAULTS.solanaMpp.network,
21655
- token: solana_mpp.token ?? RAIL_SPEC_DEFAULTS.solanaMpp.token,
21656
- symbol: solana_mpp.symbol ?? RAIL_SPEC_DEFAULTS.solanaMpp.symbol,
21666
+ return {
21667
+ status: "unverified",
21668
+ denialStatus: outcome.status,
21669
+ denialBody: outcome.body,
21670
+ ...outcome.reason !== void 0 && { denialReason: outcome.reason }
21671
+ };
21672
+ }
21673
+ function shippingCountryAllowed(country, policy) {
21674
+ if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
21675
+ const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
21676
+ return allowed.has(country.toUpperCase());
21677
+ }
21678
+ function shippingStateAllowed(state, country, policy) {
21679
+ if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
21680
+ if (country.toUpperCase() !== "US") return true;
21681
+ const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
21682
+ return allowed.has(state.toUpperCase());
21683
+ }
21684
+ function validateShippingAgainstPolicy(opts) {
21685
+ const code = opts.errorCode ?? "unsupported_jurisdiction";
21686
+ const action = opts.errorAction ?? "change_shipping_state";
21687
+ const item = opts.productName ? `'${opts.productName}'` : "this item";
21688
+ if (!shippingCountryAllowed(opts.country, opts.policy)) {
21689
+ throw new CheckoutValidationError({
21690
+ code,
21691
+ message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
21692
+ action
21693
+ });
21694
+ }
21695
+ if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
21696
+ throw new CheckoutValidationError({
21697
+ code,
21698
+ message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
21699
+ action
21700
+ });
21701
+ }
21702
+ }
21703
+
21704
+ // src/identity/tokens.ts
21705
+ import { createHash } from "crypto";
21706
+
21707
+ // src/payment/payment_header.ts
21708
+ function toTitleCase(name) {
21709
+ return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
21710
+ }
21711
+ function readHeader(headers, name) {
21712
+ if (typeof headers.get === "function") {
21713
+ return headers.get(name);
21714
+ }
21715
+ const rec = headers;
21716
+ const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
21717
+ if (typeof v === "string") return v;
21718
+ if (Array.isArray(v) && typeof v[0] === "string") return v[0];
21719
+ return null;
21720
+ }
21721
+ function asHeaders(input) {
21722
+ return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
21723
+ }
21724
+ function hasPaymentHeader(input) {
21725
+ const headers = asHeaders(input);
21726
+ return Boolean(
21727
+ readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
21728
+ );
21729
+ }
21730
+ function hasX402Header(input) {
21731
+ const headers = asHeaders(input);
21732
+ return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
21733
+ }
21734
+ function hasMppxHeader(input) {
21735
+ const headers = asHeaders(input);
21736
+ return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
21737
+ }
21738
+
21739
+ // src/identity/tokens.ts
21740
+ function hashOperatorToken(plaintext) {
21741
+ return createHash("sha256").update(plaintext, "utf8").digest("hex");
21742
+ }
21743
+ function extractOwnerScope(input) {
21744
+ const headers = asHeaders(input);
21745
+ const walletAddress = readHeader(headers, "x-wallet-address");
21746
+ const operatorToken = readHeader(headers, "x-operator-token");
21747
+ return {
21748
+ ...walletAddress ? { walletAddress } : {},
21749
+ ...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
21750
+ };
21751
+ }
21752
+
21753
+ // src/checkout.ts
21754
+ import { randomUUID } from "crypto";
21755
+
21756
+ // src/_mppx_receipt.ts
21757
+ function extractMppxReceiptHeaderFromRaw(raw) {
21758
+ if (!raw || typeof raw !== "object" || !("withReceipt" in raw)) return null;
21759
+ const fn = raw.withReceipt;
21760
+ if (typeof fn !== "function") return null;
21761
+ try {
21762
+ const wrapped = fn.call(raw, new Response());
21763
+ return wrapped.headers.get("Payment-Receipt");
21764
+ } catch {
21765
+ return null;
21766
+ }
21767
+ }
21768
+ async function extractMppxReceiptMethod(header) {
21769
+ try {
21770
+ const { Receipt } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
21771
+ return Receipt.deserialize(header).method;
21772
+ } catch {
21773
+ return void 0;
21774
+ }
21775
+ }
21776
+ async function deriveMppxReceiptMethod(raw) {
21777
+ const direct = raw?.receipt?.method;
21778
+ if (direct) return direct;
21779
+ const header = extractMppxReceiptHeaderFromRaw(raw);
21780
+ if (!header) return void 0;
21781
+ return extractMppxReceiptMethod(header);
21782
+ }
21783
+
21784
+ // src/payment/rail_spec.ts
21785
+ init_usdc();
21786
+ async function resolveRecipient(r) {
21787
+ if (typeof r === "string") return r;
21788
+ return Promise.resolve(r());
21789
+ }
21790
+ var RAIL_SPEC_DEFAULTS = {
21791
+ tempo: {
21792
+ network: "tempo-mainnet",
21793
+ chainId: 4217,
21794
+ token: USDC.tempo.mainnet.address,
21795
+ symbol: "USDC.e",
21796
+ decimals: 6,
21797
+ testnet: false,
21798
+ recommend: "both"
21799
+ },
21800
+ x402Base: {
21801
+ network: "eip155:8453",
21802
+ chainId: 8453,
21803
+ token: USDC.base.mainnet.address,
21804
+ symbol: "USDC",
21805
+ decimals: 6,
21806
+ mode: "exact"
21807
+ },
21808
+ solanaMpp: {
21809
+ network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
21810
+ token: USDC.solana.mainnet.mint,
21811
+ symbol: "USDC",
21812
+ decimals: 6
21813
+ },
21814
+ stripe: {
21815
+ rails: ["card", "link", "shared_payment_token"]
21816
+ },
21817
+ tempoSession: {
21818
+ currency: USDC.tempo.mainnet.address,
21819
+ testnet: false
21820
+ }
21821
+ };
21822
+
21823
+ // src/challenge/accepted_methods.ts
21824
+ async function buildAcceptedMethods({
21825
+ tempo,
21826
+ x402_base,
21827
+ solana_mpp,
21828
+ stripe
21829
+ }) {
21830
+ const out = [];
21831
+ if (tempo) {
21832
+ out.push({
21833
+ method: "tempo/charge",
21834
+ network: tempo.network ?? RAIL_SPEC_DEFAULTS.tempo.network,
21835
+ chain_id: tempo.chainId ?? RAIL_SPEC_DEFAULTS.tempo.chainId,
21836
+ token: tempo.token ?? RAIL_SPEC_DEFAULTS.tempo.token,
21837
+ symbol: tempo.symbol ?? RAIL_SPEC_DEFAULTS.tempo.symbol,
21838
+ decimals: tempo.decimals ?? RAIL_SPEC_DEFAULTS.tempo.decimals,
21839
+ pay_to: await resolveRecipient(tempo.recipient)
21840
+ });
21841
+ }
21842
+ if (x402_base) {
21843
+ out.push({
21844
+ method: "x402/exact",
21845
+ network: x402_base.network ?? RAIL_SPEC_DEFAULTS.x402Base.network,
21846
+ chain_id: x402_base.chainId ?? RAIL_SPEC_DEFAULTS.x402Base.chainId,
21847
+ token: x402_base.token ?? RAIL_SPEC_DEFAULTS.x402Base.token,
21848
+ symbol: x402_base.symbol ?? RAIL_SPEC_DEFAULTS.x402Base.symbol,
21849
+ decimals: x402_base.decimals ?? RAIL_SPEC_DEFAULTS.x402Base.decimals,
21850
+ pay_to: await resolveRecipient(x402_base.recipient)
21851
+ });
21852
+ }
21853
+ if (solana_mpp) {
21854
+ out.push({
21855
+ method: "solana/charge",
21856
+ network: solana_mpp.network ?? RAIL_SPEC_DEFAULTS.solanaMpp.network,
21857
+ token: solana_mpp.token ?? RAIL_SPEC_DEFAULTS.solanaMpp.token,
21858
+ symbol: solana_mpp.symbol ?? RAIL_SPEC_DEFAULTS.solanaMpp.symbol,
21657
21859
  decimals: solana_mpp.decimals ?? RAIL_SPEC_DEFAULTS.solanaMpp.decimals,
21658
21860
  pay_to: await resolveRecipient(solana_mpp.recipient)
21659
21861
  });
@@ -21803,10 +22005,13 @@ function buildHowToPay({
21803
22005
  totalUsd,
21804
22006
  rails: rails2,
21805
22007
  opTokenPlaceholder,
21806
- maxSpend
22008
+ maxSpend,
22009
+ decimals
21807
22010
  }) {
21808
22011
  const totalNum = typeof totalUsd === "string" ? Number(totalUsd) : totalUsd;
21809
- const maxSpendStr = String(maxSpend ?? (Math.ceil(totalNum) + 1).toFixed(2));
22012
+ const d = decimals ?? 2;
22013
+ const defaultMaxSpend = totalNum >= 1 ? (Math.ceil(totalNum) + 1).toFixed(d) : totalNum.toFixed(d);
22014
+ const maxSpendStr = String(maxSpend ?? defaultMaxSpend);
21810
22015
  const opToken = opTokenPlaceholder ?? "<your_opc_token>";
21811
22016
  const block = {};
21812
22017
  if (rails2.tempo) {
@@ -21899,26 +22104,26 @@ function buildPricingBlock({
21899
22104
  totalCents,
21900
22105
  taxRate,
21901
22106
  taxState,
21902
- currency
22107
+ currency,
22108
+ decimals
21903
22109
  }) {
21904
22110
  const shipping = shippingCents ?? 0;
21905
22111
  const discount = discountCents ?? 0;
21906
22112
  const total = totalCents ?? Math.max(0, subtotalCents + taxCents + shipping - discount);
22113
+ const d = decimals ?? 2;
22114
+ const fmt = (cents) => (cents / 100).toFixed(d);
21907
22115
  const block = {
21908
- subtotal: formatCents(subtotalCents),
21909
- tax: formatCents(taxCents),
21910
- total: formatCents(total)
22116
+ subtotal: fmt(subtotalCents),
22117
+ tax: fmt(taxCents),
22118
+ total: fmt(total)
21911
22119
  };
21912
- if (shippingCents !== void 0) block.shipping = formatCents(shipping);
21913
- if (discountCents !== void 0) block.discount = formatCents(discount);
22120
+ if (shippingCents !== void 0) block.shipping = fmt(shipping);
22121
+ if (discountCents !== void 0) block.discount = fmt(discount);
21914
22122
  if (taxRate !== void 0) block.tax_rate = taxRate;
21915
22123
  if (taxState !== void 0) block.tax_state = taxState;
21916
22124
  if (currency !== void 0) block.currency = currency;
21917
22125
  return block;
21918
22126
  }
21919
- function formatCents(cents) {
21920
- return (cents / 100).toFixed(2);
21921
- }
21922
22127
 
21923
22128
  // src/challenge/respond_402.ts
21924
22129
  init_wwwauthenticate();
@@ -21927,10 +22132,7 @@ function respond402({
21927
22132
  body,
21928
22133
  x402
21929
22134
  }) {
21930
- const headers = {};
21931
- for (const [k, v] of Object.entries(mppxChallengeHeaders)) {
21932
- headers[k.toLowerCase()] = v;
21933
- }
22135
+ const headers = normalizeHeadersToLowercase(mppxChallengeHeaders);
21934
22136
  headers["content-type"] = "application/json";
21935
22137
  if (x402) {
21936
22138
  headers["payment-required"] = paymentRequiredHeader(x402);
@@ -21957,6 +22159,12 @@ function buildValidationError({
21957
22159
  return body;
21958
22160
  }
21959
22161
 
22162
+ // src/payment/constants.ts
22163
+ var STRIPE_MIN_CHARGE_USD = 0.5;
22164
+
22165
+ // src/payment/mppx_server.ts
22166
+ import { AsyncLocalStorage } from "async_hooks";
22167
+
21960
22168
  // src/stripe-multichain/mppx_stripe.ts
21961
22169
  async function createMppxStripe({
21962
22170
  profileId,
@@ -21993,7 +22201,8 @@ function isSolanaMppRailSpec(s) {
21993
22201
  return s.network?.startsWith("solana:") ?? false;
21994
22202
  }
21995
22203
  function solanaNetworkFromCAIP2(caip2) {
21996
- if (caip2 === networks.solana.devnet.caip2) return "devnet";
22204
+ if (caip2 === "devnet" || caip2 === networks.solana.devnet.caip2) return "devnet";
22205
+ if (caip2 === "localnet") return "localnet";
21997
22206
  return "mainnet-beta";
21998
22207
  }
21999
22208
  function solanaDefaultRpcUrl(network) {
@@ -22136,6 +22345,31 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
22136
22345
  }
22137
22346
  };
22138
22347
  }
22348
+ var mppxCapture = new AsyncLocalStorage();
22349
+ var consoleErrorPatched = false;
22350
+ function ensureConsoleErrorPatch() {
22351
+ if (consoleErrorPatched) return;
22352
+ consoleErrorPatched = true;
22353
+ const original = console.error.bind(console);
22354
+ console.error = function captureMppxInternal(...args) {
22355
+ if (args[0] === "mppx: internal verification error" && args[1] !== void 0) {
22356
+ const ctx = mppxCapture.getStore();
22357
+ if (ctx) {
22358
+ const e = args[1];
22359
+ const reason = typeof e?.shortMessage === "string" ? e.shortMessage : typeof e?.message === "string" ? e.message : String(args[1]);
22360
+ const details = e?.details;
22361
+ ctx.reason = typeof details === "string" && details.length > 0 ? `${reason} (${details})` : reason;
22362
+ }
22363
+ }
22364
+ return original(...args);
22365
+ };
22366
+ }
22367
+ async function runWithMppxFailureCapture(fn) {
22368
+ ensureConsoleErrorPatch();
22369
+ const ctx = { reason: null };
22370
+ const result = await mppxCapture.run(ctx, fn);
22371
+ return { result, failureReason: ctx.reason };
22372
+ }
22139
22373
 
22140
22374
  // src/payment/x402_server.ts
22141
22375
  init_networks();
@@ -22277,6 +22511,29 @@ function lazyMppxServer(opts) {
22277
22511
  };
22278
22512
  }
22279
22513
 
22514
+ // src/payment/mppx_failures.ts
22515
+ var TEMPO_KEY_NOT_REGISTERED = {
22516
+ code: "tempo_key_not_registered",
22517
+ status: 401,
22518
+ message: "Tempo rejected the transaction: signer wallet is not registered with Tempo's keychain.",
22519
+ nextSteps: {
22520
+ action: "register_tempo_key",
22521
+ user_message: "Your wallet is not enrolled with Tempo. Run `tempo wallet login` to complete the one-time WebAuthn enrollment (or use `tempo request` directly), then retry. To skip enrollment, switch to the Base or Solana rail on this 402."
22522
+ },
22523
+ extra: { upstream_error: "KeyNotFound", chain: "tempo" }
22524
+ };
22525
+ function classifyMppxFailure(reason) {
22526
+ if (!reason) return null;
22527
+ const lower = reason.toLowerCase();
22528
+ if (lower.includes("keychain validation failed") || lower.includes("keynotfound")) {
22529
+ return TEMPO_KEY_NOT_REGISTERED;
22530
+ }
22531
+ return null;
22532
+ }
22533
+
22534
+ // src/checkout.ts
22535
+ init_network_kind();
22536
+
22280
22537
  // src/payment/x402_settle.ts
22281
22538
  function classifyX402SettleResult(result) {
22282
22539
  if (result.success) return null;
@@ -22568,12 +22825,14 @@ function pricingResult(opts) {
22568
22825
  ...opts.discountCents !== void 0 && { discountCents: opts.discountCents },
22569
22826
  ...opts.taxRate !== void 0 && { taxRate: opts.taxRate },
22570
22827
  ...opts.taxState !== void 0 && { taxState: opts.taxState },
22571
- currency
22828
+ currency,
22829
+ ...opts.decimals !== void 0 && { decimals: opts.decimals }
22572
22830
  });
22573
22831
  return {
22574
22832
  amountUsd: derivedAmount,
22575
22833
  currency,
22576
22834
  block,
22835
+ ...opts.decimals !== void 0 && { decimals: opts.decimals },
22577
22836
  ...opts.product !== void 0 && { product: opts.product },
22578
22837
  ...opts.bodyExtras !== void 0 && { bodyExtras: opts.bodyExtras }
22579
22838
  };
@@ -22584,6 +22843,7 @@ function pricingResult(opts) {
22584
22843
  return {
22585
22844
  amountUsd: opts.amountUsd,
22586
22845
  currency,
22846
+ ...opts.decimals !== void 0 && { decimals: opts.decimals },
22587
22847
  ...opts.product !== void 0 && { product: opts.product },
22588
22848
  ...opts.bodyExtras !== void 0 && { bodyExtras: opts.bodyExtras }
22589
22849
  };
@@ -22595,35 +22855,8 @@ function getIdentityStatus(ctx) {
22595
22855
  if (decision === "allow") return "verified";
22596
22856
  return "unverified";
22597
22857
  }
22598
- var CheckoutValidationError = class extends Error {
22599
- code;
22600
- action;
22601
- status;
22602
- extra;
22603
- constructor(opts) {
22604
- super(opts.message);
22605
- this.name = "CheckoutValidationError";
22606
- this.code = opts.code;
22607
- this.action = opts.action ?? "fix_request";
22608
- this.status = opts.status ?? 400;
22609
- this.extra = opts.extra;
22610
- }
22611
- };
22612
- function lowerHeaders2(headers) {
22613
- const out = {};
22614
- for (const [k, v] of Object.entries(headers)) out[k.toLowerCase()] = v;
22615
- return out;
22616
- }
22617
- function hasX402Header(headers) {
22618
- const h = lowerHeaders2(headers);
22619
- return Boolean(h["payment-signature"] ?? h["x-payment"]);
22620
- }
22621
- function hasMppxHeader(headers) {
22622
- const h = lowerHeaders2(headers);
22623
- return (h["authorization"] ?? "").startsWith("Payment ");
22624
- }
22625
22858
  function resolveIdentityMetadata(ctx) {
22626
- const h = lowerHeaders2(ctx.request.headers);
22859
+ const h = normalizeHeadersToLowercase(ctx.request.headers);
22627
22860
  const wallet = h["x-wallet-address"];
22628
22861
  if (!wallet) return void 0;
22629
22862
  let linkedWallets;
@@ -22652,26 +22885,24 @@ function isTempoSessionRailSpec3(s) {
22652
22885
  function specRailKey(spec) {
22653
22886
  if (isStripeRailSpec2(spec)) return "stripe";
22654
22887
  if (isTempoSessionRailSpec3(spec)) return "tempo_mpp";
22655
- const network = spec.network ?? "";
22656
- if (network.startsWith("eip155:")) return "x402_base";
22657
- if (network.startsWith("solana:") || "rpcUrl" in spec) return "solana_mpp";
22888
+ if (isEvmNetwork(spec)) return "x402_base";
22889
+ if (isSolanaNetwork(spec) || "rpcUrl" in spec) return "solana_mpp";
22658
22890
  return "tempo_mpp";
22659
22891
  }
22660
22892
  function specMethodName(spec) {
22661
22893
  if (isStripeRailSpec2(spec)) return "stripe/spt";
22662
22894
  if (isTempoSessionRailSpec3(spec)) return "tempo/charge";
22663
- const network = spec.network ?? "";
22664
- if (network.startsWith("eip155:")) return "x402/exact (base)";
22665
- if (network.startsWith("solana:") || "rpcUrl" in spec) return "solana/charge";
22895
+ if (isEvmNetwork(spec)) return "x402/exact (base)";
22896
+ if (isSolanaNetwork(spec) || "rpcUrl" in spec) return "solana/charge";
22666
22897
  return "tempo/charge";
22667
22898
  }
22668
22899
  function makeMppxComposeHook(opts) {
22669
22900
  return async (ctx) => {
22670
22901
  if (ctx.pricing === null) return { status: 402 };
22671
22902
  const mpp = await opts.serverGetter();
22672
- const lower = lowerHeaders2(ctx.request.headers);
22903
+ const lower = normalizeHeadersToLowercase(ctx.request.headers);
22673
22904
  const authorization = lower["authorization"];
22674
- const amountStr = ctx.pricing.amountUsd.toFixed(2);
22905
+ const amountStr = ctx.pricing.amountUsd.toFixed(ctx.pricing.decimals ?? 2);
22675
22906
  let result;
22676
22907
  try {
22677
22908
  result = await mpp.charge({ authorization, amount: amountStr });
@@ -22755,7 +22986,7 @@ var Checkout = class {
22755
22986
  let x402ServerGetter;
22756
22987
  if (x402Server === void 0) {
22757
22988
  const baseSpec = Object.values(opts.rails).find(
22758
- (s) => !isTempoSessionRailSpec3(s) && !isStripeRailSpec2(s) && "recipient" in s && (s.network ?? "").startsWith("eip155:")
22989
+ (s) => !isTempoSessionRailSpec3(s) && !isStripeRailSpec2(s) && "recipient" in s && isEvmNetwork(s)
22759
22990
  );
22760
22991
  if (baseSpec !== void 0) {
22761
22992
  x402ServerGetter = lazyX402Server({
@@ -22845,7 +23076,7 @@ var Checkout = class {
22845
23076
  * `"x402_base"` when no match found. */
22846
23077
  x402RailKey() {
22847
23078
  for (const [k, v] of Object.entries(this.rails)) {
22848
- if (!isStripeRailSpec2(v) && !isTempoSessionRailSpec3(v) && (v.network ?? "").startsWith("eip155:")) {
23079
+ if (!isStripeRailSpec2(v) && !isTempoSessionRailSpec3(v) && isEvmNetwork(v)) {
22849
23080
  return k;
22850
23081
  }
22851
23082
  }
@@ -22854,8 +23085,7 @@ var Checkout = class {
22854
23085
  /** Return the rails-dict key for the primary MPP rail. */
22855
23086
  mppRailKey() {
22856
23087
  for (const [k, v] of Object.entries(this.rails)) {
22857
- const network = v.network ?? "";
22858
- if (!isStripeRailSpec2(v) && !network.startsWith("eip155:")) return k;
23088
+ if (!isStripeRailSpec2(v) && !isEvmNetwork(v)) return k;
22859
23089
  }
22860
23090
  return "tempo";
22861
23091
  }
@@ -22874,17 +23104,15 @@ var Checkout = class {
22874
23104
  if (method === "solana") {
22875
23105
  for (const [k, v] of Object.entries(this.rails)) {
22876
23106
  if (isStripeRailSpec2(v) || isTempoSessionRailSpec3(v)) continue;
22877
- const network = v.network ?? "";
22878
- if (network.startsWith("solana:") || "rpcUrl" in v || "tokenProgram" in v) return k;
23107
+ if (isSolanaNetwork(v) || "rpcUrl" in v || "tokenProgram" in v) return k;
22879
23108
  }
22880
23109
  return void 0;
22881
23110
  }
22882
23111
  if (method === "tempo") {
22883
23112
  for (const [k, v] of Object.entries(this.rails)) {
22884
23113
  if (isStripeRailSpec2(v)) continue;
22885
- const network = v.network ?? "";
22886
- if (network.startsWith("solana:") || "rpcUrl" in v || "tokenProgram" in v) continue;
22887
- if (network.startsWith("eip155:")) continue;
23114
+ if (isSolanaNetwork(v) || "rpcUrl" in v || "tokenProgram" in v) continue;
23115
+ if (isEvmNetwork(v)) continue;
22888
23116
  return k;
22889
23117
  }
22890
23118
  return void 0;
@@ -22897,7 +23125,7 @@ var Checkout = class {
22897
23125
  get x402BaseNetwork() {
22898
23126
  if (!this.x402ServerAvailable()) return null;
22899
23127
  for (const spec of Object.values(this.rails)) {
22900
- if (!isStripeRailSpec2(spec) && !isTempoSessionRailSpec3(spec) && (spec.network ?? "").startsWith("eip155:")) {
23128
+ if (!isStripeRailSpec2(spec) && !isTempoSessionRailSpec3(spec) && isEvmNetwork(spec)) {
22901
23129
  return spec.network ?? "eip155:8453";
22902
23130
  }
22903
23131
  }
@@ -22949,8 +23177,8 @@ var Checkout = class {
22949
23177
  throw err;
22950
23178
  }
22951
23179
  }
22952
- const hasPaymentHeader = hasX402Header(request.headers) || hasMppxHeader(request.headers);
22953
- if (this.gate !== void 0 && hasPaymentHeader) {
23180
+ const hasPaymentHeader2 = hasX402Header(request.headers) || hasMppxHeader(request.headers);
23181
+ if (this.gate !== void 0 && hasPaymentHeader2) {
22954
23182
  const denial = await this.runGate(ctx);
22955
23183
  if (denial !== null) {
22956
23184
  return {
@@ -22963,7 +23191,14 @@ var Checkout = class {
22963
23191
  }
22964
23192
  }
22965
23193
  ctx.pricing = await this.computePricing(ctx);
22966
- await this.resolveRecipientsForCtx(ctx);
23194
+ try {
23195
+ await this.resolveRecipientsForCtx(ctx);
23196
+ } catch (err) {
23197
+ if (err instanceof Error && err.name === "CheckoutValidationError") {
23198
+ return this.validationErrorResult(ctx, err);
23199
+ }
23200
+ throw err;
23201
+ }
22967
23202
  const x402ServerOk = this.x402ServerAvailable() && this.x402BaseNetwork !== null;
22968
23203
  if (hasX402Header(request.headers) && x402ServerOk) {
22969
23204
  const zero = await this.handleZeroSettle(ctx, "x402-base");
@@ -23034,13 +23269,21 @@ var Checkout = class {
23034
23269
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23035
23270
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23036
23271
  ...gate.chain !== void 0 && { chain: gate.chain },
23037
- ...gate.createSessionOnMissing !== void 0 && {
23038
- createSessionOnMissing: gate.createSessionOnMissing
23272
+ // Auto-default `createSessionOnMissing` from gate config when the merchant
23273
+ // didn't supply one. Matches python-commerce's behavior — every gated route
23274
+ // gets the bootstrap session-mint UX out of the box. Merchants who need
23275
+ // custom session context or onBeforeSession side effects (goods merchants
23276
+ // pre-minting an order_id) supply their own config instead.
23277
+ createSessionOnMissing: gate.createSessionOnMissing ?? {
23278
+ apiKey: gate.apiKey,
23279
+ ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
23280
+ ...gate.context !== void 0 && { context: gate.context },
23281
+ ...gate.merchantName !== void 0 && { productName: gate.merchantName }
23039
23282
  },
23040
23283
  ...policyOverride ?? {}
23041
23284
  };
23042
23285
  const core = createAgentScoreCore(coreOpts);
23043
- const headers = lowerHeaders2(ctx.request.headers);
23286
+ const headers = normalizeHeadersToLowercase(ctx.request.headers);
23044
23287
  const walletAddress = headers["x-wallet-address"];
23045
23288
  const operatorToken = headers["x-operator-token"];
23046
23289
  const identity = walletAddress !== void 0 || operatorToken !== void 0 ? {
@@ -23102,7 +23345,7 @@ var Checkout = class {
23102
23345
  if (!this.zeroSettleCarveOut || ctx.pricing === null) return null;
23103
23346
  const cents = Math.round(ctx.pricing.amountUsd * 100);
23104
23347
  if (cents !== 0) return null;
23105
- const headers = lowerHeaders2(ctx.request.headers);
23348
+ const headers = normalizeHeadersToLowercase(ctx.request.headers);
23106
23349
  let zero;
23107
23350
  if (rail === "x402-base") {
23108
23351
  const x402Header = headers["payment-signature"] ?? headers["x-payment"];
@@ -23176,7 +23419,7 @@ var Checkout = class {
23176
23419
  resourceConfig: {
23177
23420
  scheme: "exact",
23178
23421
  network: verified.signedNetwork,
23179
- price: `$${ctx.pricing.amountUsd.toFixed(2)}`,
23422
+ price: `$${ctx.pricing.amountUsd.toFixed(ctx.pricing.decimals ?? 2)}`,
23180
23423
  payTo: verified.signedPayTo,
23181
23424
  maxTimeoutSeconds: 300
23182
23425
  },
@@ -23235,7 +23478,9 @@ var Checkout = class {
23235
23478
  if (this.composeMppx === void 0) {
23236
23479
  throw new Error("Checkout.handleMppx: composeMppx hook not configured");
23237
23480
  }
23238
- const composed = await this.composeMppx(ctx);
23481
+ const { result: composed, failureReason } = await runWithMppxFailureCapture(
23482
+ async () => this.composeMppx(ctx)
23483
+ );
23239
23484
  if (composed.status === 200) {
23240
23485
  const paymentReceiptHeader = composed.paymentReceiptHeader ?? extractMppxReceiptHeaderFromRaw(composed.raw);
23241
23486
  const directMethod = composed.raw?.receipt?.method;
@@ -23254,6 +23499,22 @@ var Checkout = class {
23254
23499
  };
23255
23500
  return await this.buildSuccess(ctx, outcome);
23256
23501
  }
23502
+ const classified = classifyMppxFailure(failureReason);
23503
+ if (classified !== null) {
23504
+ return {
23505
+ status: classified.status,
23506
+ body: buildValidationError({
23507
+ code: classified.code,
23508
+ message: classified.message,
23509
+ nextSteps: classified.nextSteps,
23510
+ ...classified.extra && { extra: classified.extra }
23511
+ }),
23512
+ headers: { ...composed.headers ?? {} },
23513
+ referenceId: ctx.referenceId,
23514
+ settled: false,
23515
+ settlePhase: "verify_failed"
23516
+ };
23517
+ }
23257
23518
  return {
23258
23519
  status: 400,
23259
23520
  body: buildValidationError({
@@ -23272,7 +23533,11 @@ var Checkout = class {
23272
23533
  throw new Error("Checkout.emit402: pricing not computed");
23273
23534
  }
23274
23535
  await this.resolveRecipientsForCtx(ctx);
23275
- const emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
23536
+ let emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
23537
+ if (ctx.pricing.amountUsd < STRIPE_MIN_CHARGE_USD && emitRails.stripe !== void 0) {
23538
+ const { stripe: _stripe, ...rest } = emitRails;
23539
+ emitRails = rest;
23540
+ }
23276
23541
  const accepted = await buildAcceptedMethods({
23277
23542
  tempo: pickRail(emitRails, "tempo"),
23278
23543
  x402_base: pickRail(emitRails, "x402_base"),
@@ -23285,15 +23550,18 @@ var Checkout = class {
23285
23550
  howToPayRails[k] = v;
23286
23551
  }
23287
23552
  }
23553
+ const pricingDecimals = ctx.pricing.decimals ?? 2;
23288
23554
  const howToPay = buildHowToPay({
23289
23555
  url: this.url,
23290
23556
  retryBodyJson: JSON.stringify(ctx.request.body),
23291
- totalUsd: ctx.pricing.amountUsd.toFixed(2),
23292
- rails: howToPayRails
23557
+ totalUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
23558
+ rails: howToPayRails,
23559
+ ...ctx.pricing.decimals !== void 0 && { decimals: ctx.pricing.decimals }
23293
23560
  });
23294
23561
  const pricingBlock = ctx.pricing.block ?? buildPricingBlock({
23295
- subtotalCents: Math.round(ctx.pricing.amountUsd * 100),
23296
- currency: ctx.pricing.currency ?? "USD"
23562
+ subtotalCents: ctx.pricing.amountUsd * 100,
23563
+ currency: ctx.pricing.currency ?? "USD",
23564
+ ...ctx.pricing.decimals !== void 0 && { decimals: ctx.pricing.decimals }
23297
23565
  });
23298
23566
  let x402Accepts = [];
23299
23567
  let x402Resource;
@@ -23306,7 +23574,7 @@ var Checkout = class {
23306
23574
  try {
23307
23575
  x402Accepts = await buildX402AcceptsFor402(x402Server, {
23308
23576
  network: baseNetwork,
23309
- price: `$${ctx.pricing.amountUsd.toFixed(2)}`,
23577
+ price: `$${ctx.pricing.amountUsd.toFixed(pricingDecimals)}`,
23310
23578
  payTo: recipient,
23311
23579
  maxTimeoutSeconds: 300
23312
23580
  });
@@ -23322,7 +23590,7 @@ var Checkout = class {
23322
23590
  agentInstructions: buildAgentInstructions({ howToPay }),
23323
23591
  ...identityMetadata !== void 0 ? { identityMetadata } : {},
23324
23592
  pricing: pricingBlock,
23325
- amountUsd: ctx.pricing.amountUsd.toFixed(2),
23593
+ amountUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
23326
23594
  retryBody: ctx.request.body,
23327
23595
  agentMemory: firstEncounterAgentMemory({ firstEncounter: true }),
23328
23596
  ...ctx.pricing.product ? { product: ctx.pricing.product } : {},
@@ -23430,25 +23698,6 @@ function stripContentType(headers) {
23430
23698
  }
23431
23699
  return out;
23432
23700
  }
23433
- function extractMppxReceiptHeaderFromRaw(raw) {
23434
- if (!raw || typeof raw !== "object" || !("withReceipt" in raw)) return null;
23435
- const fn = raw.withReceipt;
23436
- if (typeof fn !== "function") return null;
23437
- try {
23438
- const wrapped = fn.call(raw, new Response());
23439
- return wrapped.headers.get("Payment-Receipt");
23440
- } catch {
23441
- return null;
23442
- }
23443
- }
23444
- async function extractMppxReceiptMethod(header) {
23445
- try {
23446
- const { Receipt } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
23447
- return Receipt.deserialize(header).method;
23448
- } catch {
23449
- return void 0;
23450
- }
23451
- }
23452
23701
  function headersToRecord(h) {
23453
23702
  if (h === void 0) return {};
23454
23703
  if (h instanceof Headers) {
@@ -23691,78 +23940,6 @@ Checkout.prototype.mountUcpRoutesFastify = function(app, opts) {
23691
23940
  app.options(jwksPath, preflight);
23692
23941
  };
23693
23942
 
23694
- // src/identity/policy.ts
23695
- function buildGateFromPolicy(policy, base) {
23696
- if (!policy || !policy.enforcement) return null;
23697
- return {
23698
- apiKey: base.apiKey,
23699
- ...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
23700
- ...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
23701
- ...policy.requireSanctionsClear !== void 0 && {
23702
- requireSanctionsClear: policy.requireSanctionsClear
23703
- },
23704
- ...policy.minAge !== void 0 && { minAge: policy.minAge },
23705
- ...policy.allowedJurisdictions !== void 0 && {
23706
- allowedJurisdictions: [...policy.allowedJurisdictions]
23707
- }
23708
- };
23709
- }
23710
- async function runGateWithEnforcement(enforcement, runGate) {
23711
- if (!runGate || !enforcement) return { status: "anonymous" };
23712
- const outcome = await runGate();
23713
- if (outcome.ok) return { status: "verified" };
23714
- if (enforcement === "hard") {
23715
- return {
23716
- status: "denied",
23717
- denialStatus: outcome.status,
23718
- denialBody: outcome.body,
23719
- ...outcome.reason !== void 0 && { denialReason: outcome.reason }
23720
- };
23721
- }
23722
- return {
23723
- status: "unverified",
23724
- denialStatus: outcome.status,
23725
- denialBody: outcome.body,
23726
- ...outcome.reason !== void 0 && { denialReason: outcome.reason }
23727
- };
23728
- }
23729
- function shippingCountryAllowed(country, policy) {
23730
- if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
23731
- const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
23732
- return allowed.has(country.toUpperCase());
23733
- }
23734
- function shippingStateAllowed(state, country, policy) {
23735
- if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
23736
- if (country.toUpperCase() !== "US") return true;
23737
- const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
23738
- return allowed.has(state.toUpperCase());
23739
- }
23740
- function validateShippingAgainstPolicy(opts) {
23741
- const code = opts.errorCode ?? "unsupported_jurisdiction";
23742
- const action = opts.errorAction ?? "change_shipping_state";
23743
- const item = opts.productName ? `'${opts.productName}'` : "this item";
23744
- if (!shippingCountryAllowed(opts.country, opts.policy)) {
23745
- throw new CheckoutValidationError({
23746
- code,
23747
- message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
23748
- action
23749
- });
23750
- }
23751
- if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
23752
- throw new CheckoutValidationError({
23753
- code,
23754
- message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
23755
- action
23756
- });
23757
- }
23758
- }
23759
-
23760
- // src/identity/tokens.ts
23761
- import { createHash } from "crypto";
23762
- function hashOperatorToken(plaintext) {
23763
- return createHash("sha256").update(plaintext, "utf8").digest("hex");
23764
- }
23765
-
23766
23943
  // src/payment/index.ts
23767
23944
  init_directive();
23768
23945
  init_networks();
@@ -23775,8 +23952,45 @@ init_directive();
23775
23952
  init_wwwauthenticate();
23776
23953
 
23777
23954
  // src/payment/amounts.ts
23778
- function formatUsdCents(cents) {
23779
- return (cents / 100).toFixed(2);
23955
+ function usdToAtomic(usd, opts) {
23956
+ const { decimals } = opts;
23957
+ if (!Number.isInteger(decimals) || decimals < 0) {
23958
+ throw new RangeError(`decimals must be a non-negative integer, got ${decimals}`);
23959
+ }
23960
+ if (typeof usd === "number") {
23961
+ if (!Number.isFinite(usd)) {
23962
+ throw new RangeError(`usd must be finite, got ${usd}`);
23963
+ }
23964
+ if (usd < 0) {
23965
+ throw new RangeError(`usd must be non-negative, got ${usd}`);
23966
+ }
23967
+ }
23968
+ const s = (typeof usd === "number" ? usd.toString() : usd).trim();
23969
+ if (s.startsWith("-")) {
23970
+ throw new RangeError(`usd must be non-negative, got ${s}`);
23971
+ }
23972
+ if (s === "NaN" || s === "Infinity") {
23973
+ throw new RangeError(`usd must be finite, got ${s}`);
23974
+ }
23975
+ const match = /^(\d*)(?:\.(\d*))?$/.exec(s);
23976
+ if (!match || match[1] === "" && (match[2] === void 0 || match[2] === "")) {
23977
+ throw new SyntaxError(`invalid usd value: ${JSON.stringify(usd)}`);
23978
+ }
23979
+ const intPart = match[1] || "0";
23980
+ const fracPart = match[2] ?? "";
23981
+ if (fracPart.length <= decimals) {
23982
+ return BigInt(intPart + fracPart.padEnd(decimals, "0"));
23983
+ }
23984
+ const kept = fracPart.slice(0, decimals);
23985
+ const roundDigit = fracPart[decimals];
23986
+ let result = BigInt(intPart + kept);
23987
+ if (roundDigit >= "5") {
23988
+ result += 1n;
23989
+ }
23990
+ return result;
23991
+ }
23992
+ function formatUsdCents(cents, decimals = 2) {
23993
+ return (cents / 100).toFixed(decimals);
23780
23994
  }
23781
23995
 
23782
23996
  // src/payment/solana.ts
@@ -23799,7 +24013,643 @@ async function loadSolanaFeePayer(opts) {
23799
24013
  }
23800
24014
  return kit.createKeyPairSignerFromPrivateKeyBytes(bytes);
23801
24015
  }
24016
+
24017
+ // src/payment/compose_rails.ts
24018
+ init_usdc();
24019
+ var warnedStripeBelowMinimum = false;
24020
+ function buildMppxComposeRails(opts) {
24021
+ const rails2 = [];
24022
+ if (opts.tempoRecipient) {
24023
+ rails2.push(["tempo/charge", {
24024
+ amount: opts.amountUsd,
24025
+ currency: opts.tempoTokenAddress ?? USDC.tempo.mainnet.address,
24026
+ decimals: 6,
24027
+ recipient: opts.tempoRecipient
24028
+ }]);
24029
+ }
24030
+ if (opts.solanaRecipient) {
24031
+ const atomic = usdToAtomic(opts.amountUsd, { decimals: 6 });
24032
+ rails2.push(["solana/charge", {
24033
+ amount: atomic.toString(),
24034
+ currency: opts.solanaTokenMint ?? USDC.solana.mainnet.mint,
24035
+ decimals: 6,
24036
+ recipient: opts.solanaRecipient,
24037
+ network: opts.solanaNetwork ?? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
24038
+ }]);
24039
+ }
24040
+ if (opts.includeStripe !== false) {
24041
+ const amountUsdNumeric = Number(opts.amountUsd);
24042
+ if (Number.isFinite(amountUsdNumeric) && amountUsdNumeric < STRIPE_MIN_CHARGE_USD) {
24043
+ if (!warnedStripeBelowMinimum) {
24044
+ warnedStripeBelowMinimum = true;
24045
+ console.warn(
24046
+ `[buildMppxComposeRails] Dropping stripe/charge rail: amountUsd=${opts.amountUsd} is below Stripe's $${STRIPE_MIN_CHARGE_USD.toFixed(2)} USD minimum. Stripe's fixed ~$0.30 fee makes sub-50-cent charges unprofitable (and many accounts reject PI creation with amount_too_small below this floor). Pass includeStripe: false to suppress this warning.`
24047
+ );
24048
+ }
24049
+ } else {
24050
+ rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
24051
+ }
24052
+ }
24053
+ return rails2;
24054
+ }
24055
+
24056
+ // src/payment/default_rails.ts
24057
+ init_networks();
24058
+ init_usdc();
24059
+ function buildDefaultCheckoutRails(opts) {
24060
+ const out = {};
24061
+ if (opts.tempo) {
24062
+ out.tempo = { recipient: "", ...RAIL_SPEC_DEFAULTS.tempo, ...opts.tempo };
24063
+ }
24064
+ if (opts.x402Base) {
24065
+ const merged = { recipient: "", ...RAIL_SPEC_DEFAULTS.x402Base, ...opts.x402Base };
24066
+ if (merged.network === networks.base.sepolia.caip2) {
24067
+ if (opts.x402Base.chainId === void 0) merged.chainId = networks.base.sepolia.chainId;
24068
+ if (opts.x402Base.token === void 0) merged.token = USDC.base.sepolia.address;
24069
+ } else if (merged.network === networks.base.mainnet.caip2) {
24070
+ if (opts.x402Base.chainId === void 0) merged.chainId = networks.base.mainnet.chainId;
24071
+ if (opts.x402Base.token === void 0) merged.token = USDC.base.mainnet.address;
24072
+ }
24073
+ out.x402_base = merged;
24074
+ }
24075
+ if (opts.solanaMpp) {
24076
+ const merged = { recipient: "", ...RAIL_SPEC_DEFAULTS.solanaMpp, ...opts.solanaMpp };
24077
+ const isDevnet = merged.network === "devnet" || merged.network === networks.solana.devnet.caip2;
24078
+ if (isDevnet && opts.solanaMpp.token === void 0) {
24079
+ merged.token = USDC.solana.devnet.mint;
24080
+ }
24081
+ out.solana_mpp = merged;
24082
+ }
24083
+ if (opts.stripe) {
24084
+ out.stripe = { ...RAIL_SPEC_DEFAULTS.stripe, ...opts.stripe };
24085
+ }
24086
+ return out;
24087
+ }
24088
+
24089
+ // src/payment/index.ts
24090
+ init_network_kind();
24091
+
24092
+ // src/checkout_compute_first.ts
24093
+ import { randomUUID as randomUUID2 } from "crypto";
24094
+
24095
+ // src/discovery/index.ts
24096
+ init_probe();
24097
+
24098
+ // src/discovery/agentscore_content.ts
24099
+ var PURCHASE_MODE_NOTES = Object.freeze({
24100
+ redemption_only: "Requires a single-use redemption code (printed on a mailer or other out-of-band delivery). Submit the code in the request body as `redemption_code`. Without a valid code the order is rejected.",
24101
+ coupon_applicable: "Codes are optional. Without one, settle at list price. With a valid code the discount is applied automatically (percent_off, fixed_off, or fixed_settle).",
24102
+ paid_only: "Codes are NOT accepted. Settle at the listed price. Submitting a `redemption_code` field returns 400 codes_not_accepted."
24103
+ });
24104
+ function buildSuccessNextSteps(opts) {
24105
+ const out = {
24106
+ action: "done",
24107
+ user_message: opts.userMessage ?? "Payment complete. Your AgentScore Passport is now active across every AgentScore-gated merchant."
24108
+ };
24109
+ if (opts.orderStatusUrl) out.order_status_url = opts.orderStatusUrl;
24110
+ if (opts.fulfillmentEta !== void 0) out.fulfillment_eta = opts.fulfillmentEta;
24111
+ return out;
24112
+ }
24113
+
24114
+ // src/discovery/index.ts
24115
+ init_well_known();
24116
+
24117
+ // src/quote_cache.ts
24118
+ import { createHash as createHash2 } from "crypto";
24119
+
24120
+ // src/_redis.ts
24121
+ async function tryCreateRedis(opts) {
24122
+ const url2 = opts.url ?? process.env.REDIS_URL;
24123
+ if (!url2) return null;
24124
+ try {
24125
+ const mod = await import("ioredis");
24126
+ const client = new mod.default(url2, {
24127
+ connectTimeout: opts.connectTimeout ?? 3e3,
24128
+ maxRetriesPerRequest: opts.maxRetriesPerRequest ?? 1,
24129
+ tls: url2.startsWith("rediss://") ? {} : void 0
24130
+ });
24131
+ client.on("error", (err) => console.error(`[${opts.label}] Redis error:`, err.message));
24132
+ return client;
24133
+ } catch {
24134
+ return null;
24135
+ }
24136
+ }
24137
+ function memoizedRedis(opts) {
24138
+ let promise2 = null;
24139
+ return () => {
24140
+ if (!promise2) promise2 = tryCreateRedis(opts);
24141
+ return promise2;
24142
+ };
24143
+ }
24144
+
24145
+ // src/quote_cache.ts
24146
+ function canonicalize2(value) {
24147
+ if (Array.isArray(value)) return value.map(canonicalize2);
24148
+ if (value && typeof value === "object") {
24149
+ const sorted = {};
24150
+ for (const key of Object.keys(value).sort()) {
24151
+ sorted[key] = canonicalize2(value[key]);
24152
+ }
24153
+ return sorted;
24154
+ }
24155
+ return value;
24156
+ }
24157
+ function createQuoteCache(opts = {}) {
24158
+ const ttlMs = opts.ttlMs ?? 5 * 6e4;
24159
+ const keyPrefix = opts.keyPrefix ?? "quote:";
24160
+ const memMap = /* @__PURE__ */ new Map();
24161
+ const getRedis = memoizedRedis({ url: opts.redisUrl, label: "quote-cache" });
24162
+ const evictExpired = () => {
24163
+ const now = Date.now();
24164
+ for (const [k, v] of memMap.entries()) {
24165
+ if (v.expiresAt <= now) memMap.delete(k);
24166
+ }
24167
+ };
24168
+ return {
24169
+ bodyHashKey(prefix, body) {
24170
+ const canonical = JSON.stringify(canonicalize2(body));
24171
+ const hash3 = createHash2("sha256").update(`${prefix}::${canonical}`).digest("hex").slice(0, 24);
24172
+ return `${prefix}::${hash3}`;
24173
+ },
24174
+ async read(key) {
24175
+ const r = await getRedis();
24176
+ if (r) {
24177
+ try {
24178
+ const raw = await r.get(`${keyPrefix}${key}`);
24179
+ if (!raw) return null;
24180
+ return JSON.parse(raw);
24181
+ } catch {
24182
+ }
24183
+ }
24184
+ evictExpired();
24185
+ const entry = memMap.get(key);
24186
+ return entry ? entry.entry : null;
24187
+ },
24188
+ async write(key, body, priceCents, recipients = {}) {
24189
+ const cached2 = { body, priceCents, recipients };
24190
+ const r = await getRedis();
24191
+ if (r) {
24192
+ try {
24193
+ await r.set(`${keyPrefix}${key}`, JSON.stringify(cached2), "PX", ttlMs);
24194
+ return;
24195
+ } catch {
24196
+ }
24197
+ }
24198
+ memMap.set(key, { entry: cached2, expiresAt: Date.now() + ttlMs });
24199
+ },
24200
+ async clear() {
24201
+ memMap.clear();
24202
+ const r = await getRedis();
24203
+ if (r) {
24204
+ try {
24205
+ await r.flushdb();
24206
+ } catch {
24207
+ }
24208
+ }
24209
+ }
24210
+ };
24211
+ }
24212
+
24213
+ // src/checkout_compute_first.ts
24214
+ var DEFAULT_TTL_MS = 5 * 6e4;
24215
+ function decimalsForUnit(unitPriceCents) {
24216
+ if (Number.isInteger(unitPriceCents)) return 2;
24217
+ const str = unitPriceCents.toString();
24218
+ const dotIdx = str.indexOf(".");
24219
+ const frac = dotIdx === -1 ? 0 : str.length - dotIdx - 1;
24220
+ return 2 + frac;
24221
+ }
24222
+ function computeFirstCheckout(opts) {
24223
+ const cache = opts.cache ?? createQuoteCache({ ttlMs: opts.cacheTtlMs ?? DEFAULT_TTL_MS });
24224
+ const decimals = opts.decimals ?? decimalsForUnit(opts.unitPriceCents);
24225
+ const appUrl = opts.appUrl ?? new URL(opts.url).origin;
24226
+ async function mintAndResolveRecipients(req, body, priceCents) {
24227
+ const minted = opts.mintRecipients ? await opts.mintRecipients({ request: req, body, priceCents }) : {};
24228
+ const out = {};
24229
+ const tempo = minted.tempo ?? (opts.rails.tempo ? await resolveRecipient(opts.rails.tempo.recipient) : void 0);
24230
+ const x402Base = minted.x402_base ?? (opts.rails.x402_base ? await resolveRecipient(opts.rails.x402_base.recipient) : void 0);
24231
+ const solana = minted.solana_mpp ?? (opts.rails.solana_mpp ? await resolveRecipient(opts.rails.solana_mpp.recipient) : void 0);
24232
+ if (tempo) out.tempo = tempo;
24233
+ if (x402Base) out.x402_base = x402Base;
24234
+ if (solana) out.solana_mpp = solana;
24235
+ return out;
24236
+ }
24237
+ async function emit402(req, body, priceCents, recipients) {
24238
+ const totalUsd = formatUsdCents(priceCents, decimals);
24239
+ const tempoRecipient = recipients.tempo;
24240
+ const x402BaseRecipient = recipients.x402_base;
24241
+ const solanaRecipient = recipients.solana_mpp;
24242
+ const includeStripeInDiscovery = opts.rails.stripe !== void 0 && Number(totalUsd) >= STRIPE_MIN_CHARGE_USD;
24243
+ const accepted = await buildAcceptedMethods({
24244
+ ...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
24245
+ ...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
24246
+ ...includeStripeInDiscovery && { stripe: opts.rails.stripe }
24247
+ });
24248
+ if (x402BaseRecipient && opts.rails.x402_base) {
24249
+ try {
24250
+ const resolvedX402PayTo = await resolveRecipient(x402BaseRecipient);
24251
+ const x402Entries = await buildX402AcceptsFor402(opts.x402Server, {
24252
+ network: opts.rails.x402_base.network ?? "eip155:8453",
24253
+ price: `$${totalUsd}`,
24254
+ payTo: resolvedX402PayTo,
24255
+ maxTimeoutSeconds: 300
24256
+ });
24257
+ accepted.push(...x402Entries);
24258
+ } catch (err) {
24259
+ console.warn(
24260
+ `[${opts.name}.computeFirst] buildX402AcceptsFor402 failed; dropping x402 from accepts:`,
24261
+ err instanceof Error ? err.message : err
24262
+ );
24263
+ }
24264
+ }
24265
+ const howToPay = buildHowToPay({
24266
+ url: opts.url,
24267
+ retryBodyJson: JSON.stringify(body),
24268
+ totalUsd,
24269
+ decimals,
24270
+ rails: {
24271
+ ...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
24272
+ ...x402BaseRecipient && opts.rails.x402_base && { x402_base: { ...opts.rails.x402_base, recipient: x402BaseRecipient } },
24273
+ ...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
24274
+ ...opts.rails.stripe && { stripe: opts.rails.stripe }
24275
+ }
24276
+ });
24277
+ const pricing = buildPricingBlock({ subtotalCents: priceCents, currency: "USD", decimals });
24278
+ const agentInstructions = buildAgentInstructions({
24279
+ howToPay,
24280
+ warnings: [
24281
+ "The quoted price is exact: it was derived from the actual number of results returned by the work on the probe leg.",
24282
+ "The merchant cached the result against a hash of this request body. Retry with the same body within the quote TTL (default 5 min) to settle and receive the cached results; if the quote expires, re-probe."
24283
+ ]
24284
+ });
24285
+ let mppChallengeHeaders = {};
24286
+ if (opts.composeMppx) {
24287
+ try {
24288
+ const mppResult = await opts.composeMppx({
24289
+ request: req,
24290
+ cachedBody: body,
24291
+ priceCents,
24292
+ priceUsd: totalUsd,
24293
+ recipients
24294
+ });
24295
+ if (mppResult.status === 402 && mppResult.headers) {
24296
+ mppChallengeHeaders = mppResult.headers;
24297
+ }
24298
+ } catch (err) {
24299
+ console.warn(
24300
+ `[${opts.name}.computeFirst] composeMppx probe-leg failed; dropping MPP rails from 402 challenge:`,
24301
+ err instanceof Error ? err.message : err
24302
+ );
24303
+ }
24304
+ }
24305
+ const body402 = build402Body({
24306
+ product: { id: opts.name, name: opts.name },
24307
+ acceptedMethods: accepted,
24308
+ pricing,
24309
+ agentInstructions,
24310
+ amountUsd: totalUsd,
24311
+ currency: "USD",
24312
+ orderId: null,
24313
+ retryBody: body
24314
+ });
24315
+ const headers = new Headers({ "Content-Type": "application/json" });
24316
+ for (const [k, v] of Object.entries(mppChallengeHeaders)) headers.set(k, v);
24317
+ headers.set(
24318
+ "PAYMENT-REQUIRED",
24319
+ paymentRequiredHeader({ x402Version: 2, accepts: accepted, resource: { url: opts.url } })
24320
+ );
24321
+ return new Response(JSON.stringify(body402), { status: 402, headers });
24322
+ }
24323
+ async function handleX402Settle(req, referenceId, cachedBody, priceCents, recipients) {
24324
+ const verified = await verifyX402Request({
24325
+ request: req,
24326
+ isCachedAddress: async () => true,
24327
+ acceptedNetwork: opts.rails.x402_base?.network ?? "eip155:8453"
24328
+ });
24329
+ if (!verified.ok) {
24330
+ return new Response(JSON.stringify(verified.body), {
24331
+ status: verified.status,
24332
+ headers: { "Content-Type": "application/json" }
24333
+ });
24334
+ }
24335
+ const actualUsd = formatUsdCents(priceCents, decimals);
24336
+ const settle = await processX402Settle({
24337
+ x402Server: opts.x402Server,
24338
+ payload: verified.payload,
24339
+ resourceConfig: {
24340
+ scheme: "exact",
24341
+ network: verified.signedNetwork,
24342
+ price: `$${actualUsd}`,
24343
+ payTo: verified.signedPayTo,
24344
+ maxTimeoutSeconds: 300
24345
+ },
24346
+ resourceMeta: {
24347
+ url: req.url,
24348
+ description: `Agent purchase via x402-exact (${opts.name})`,
24349
+ mimeType: "application/json"
24350
+ }
24351
+ });
24352
+ if (!settle.success) {
24353
+ const detail = settle.error?.message ?? "unknown";
24354
+ return new Response(
24355
+ JSON.stringify({
24356
+ id: referenceId,
24357
+ endpoint: opts.name,
24358
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24359
+ payment_status: "failed",
24360
+ charged_usd: "0.00",
24361
+ rail: `x402-base (${verified.signedNetwork})`,
24362
+ error: {
24363
+ code: "settle_failed",
24364
+ message: "Facilitator rejected the exact settle; no on-chain capture occurred.",
24365
+ detail
24366
+ }
24367
+ }),
24368
+ { status: 502, headers: { "Content-Type": "application/json" } }
24369
+ );
24370
+ }
24371
+ const signer = await extractPaymentSigner(req, readX402PaymentHeader(req));
24372
+ const signerInfo = signer ? { address: signer.address, network: signer.network } : void 0;
24373
+ const railLabel = `Base (${verified.signedNetwork})`;
24374
+ if (opts.onSettled) {
24375
+ try {
24376
+ await opts.onSettled({
24377
+ request: req,
24378
+ rail: "x402",
24379
+ cachedBody,
24380
+ priceCents,
24381
+ priceUsd: actualUsd,
24382
+ recipients,
24383
+ ...signerInfo ? { signer: signerInfo } : {}
24384
+ });
24385
+ } catch (err) {
24386
+ console.warn(`[${opts.name}.computeFirst.onSettled] x402 side-effect failed:`, err instanceof Error ? err.message : err);
24387
+ }
24388
+ }
24389
+ const buildBody = opts.buildSuccessBody ?? defaultSuccessBody(appUrl);
24390
+ const body = buildBody({
24391
+ referenceId,
24392
+ endpoint: opts.name,
24393
+ chargedUsd: actualUsd,
24394
+ rail: railLabel,
24395
+ ...signerInfo ? { signer: signerInfo } : {},
24396
+ cachedBody
24397
+ });
24398
+ return new Response(JSON.stringify(body), { status: 200, headers: { "Content-Type": "application/json" } });
24399
+ }
24400
+ function mppRailLabel(method) {
24401
+ const scheme = method?.split("/")[0];
24402
+ if (scheme === "tempo") {
24403
+ const networkName = opts.rails.tempo?.testnet ? "tempo-testnet" : opts.rails.tempo?.network ?? "tempo-mainnet";
24404
+ return `Tempo (${networkName})`;
24405
+ }
24406
+ if (scheme === "solana") {
24407
+ const networkName = opts.rails.solana_mpp?.network ?? "solana";
24408
+ return `Solana (${networkName})`;
24409
+ }
24410
+ if (scheme === "stripe") return "Stripe (card+link)";
24411
+ return "MPP";
24412
+ }
24413
+ async function handleMppSettle(req, referenceId, cachedBody, priceCents, recipients) {
24414
+ if (!opts.composeMppx) {
24415
+ return new Response(
24416
+ JSON.stringify({
24417
+ id: referenceId,
24418
+ endpoint: opts.name,
24419
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24420
+ payment_status: "failed",
24421
+ charged_usd: "0.00",
24422
+ error: { code: "mpp_unavailable", message: "MPP settle hook not configured on this endpoint." }
24423
+ }),
24424
+ { status: 503, headers: { "Content-Type": "application/json" } }
24425
+ );
24426
+ }
24427
+ const priceUsd = formatUsdCents(priceCents, decimals);
24428
+ const result = await opts.composeMppx({ request: req, cachedBody, priceCents, priceUsd, recipients });
24429
+ if (result.status !== 200) {
24430
+ const headers = result.headers ?? {};
24431
+ return new Response(
24432
+ JSON.stringify({
24433
+ id: referenceId,
24434
+ endpoint: opts.name,
24435
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24436
+ payment_status: "failed",
24437
+ charged_usd: "0.00",
24438
+ error: { code: "mpp_settle_failed", message: "MPP compose did not return 200; credential rejected." }
24439
+ }),
24440
+ { status: 400, headers: { "Content-Type": "application/json", ...headers } }
24441
+ );
24442
+ }
24443
+ const signer = result.signerAddress ? { address: result.signerAddress, network: result.signerNetwork ?? "evm" } : await extractPaymentSigner(req, readX402PaymentHeader(req)).then((s) => s ? { address: s.address, network: s.network } : void 0);
24444
+ const method = await deriveMppxReceiptMethod(result.raw);
24445
+ const railLabel = mppRailLabel(method);
24446
+ if (opts.onSettled) {
24447
+ try {
24448
+ await opts.onSettled({
24449
+ request: req,
24450
+ rail: "mpp",
24451
+ mppMethod: method,
24452
+ cachedBody,
24453
+ priceCents,
24454
+ priceUsd,
24455
+ recipients,
24456
+ ...signer ? { signer } : {},
24457
+ ...result.txHash ? { paymentIntentId: result.txHash } : {}
24458
+ });
24459
+ } catch (err) {
24460
+ console.warn(`[${opts.name}.computeFirst.onSettled] MPP side-effect failed:`, err instanceof Error ? err.message : err);
24461
+ }
24462
+ }
24463
+ const buildBody = opts.buildSuccessBody ?? defaultSuccessBody(appUrl);
24464
+ const body = buildBody({
24465
+ referenceId,
24466
+ endpoint: opts.name,
24467
+ chargedUsd: priceUsd,
24468
+ rail: railLabel,
24469
+ ...result.txHash ? { paymentIntentId: result.txHash } : {},
24470
+ ...signer ? { signer } : {},
24471
+ cachedBody
24472
+ });
24473
+ return new Response(JSON.stringify(body), { status: 200, headers: { "Content-Type": "application/json" } });
24474
+ }
24475
+ async function handle(req) {
24476
+ const referenceId = `${opts.name}_${randomUUID2()}`;
24477
+ let body;
24478
+ try {
24479
+ body = await req.clone().json();
24480
+ } catch {
24481
+ body = {};
24482
+ }
24483
+ try {
24484
+ opts.validateInput?.(body);
24485
+ } catch (err) {
24486
+ if (err instanceof CheckoutValidationError) {
24487
+ return new Response(
24488
+ JSON.stringify({
24489
+ error: { code: err.code, message: err.message },
24490
+ ...err.action ? { next_steps: { action: err.action, user_message: err.message } } : {},
24491
+ ...err.extra
24492
+ }),
24493
+ { status: err.status, headers: { "Content-Type": "application/json" } }
24494
+ );
24495
+ }
24496
+ throw err;
24497
+ }
24498
+ const cacheKey2 = cache.bodyHashKey(opts.name, body);
24499
+ if (hasX402Header(req.headers) || hasMppxHeader(req.headers)) {
24500
+ const quote2 = await cache.read(cacheKey2);
24501
+ if (!quote2) {
24502
+ return new Response(
24503
+ JSON.stringify({
24504
+ id: referenceId,
24505
+ endpoint: opts.name,
24506
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24507
+ payment_status: "failed",
24508
+ charged_usd: "0.00",
24509
+ error: {
24510
+ code: "stale_quote",
24511
+ message: "No active quote for this request body. The quote may have expired or the body changed since the probe."
24512
+ },
24513
+ next_steps: {
24514
+ action: "re_probe",
24515
+ suggestion: "Send the same body without a payment header to get a fresh 402 quote, then retry with the payment credential."
24516
+ }
24517
+ }),
24518
+ { status: 400, headers: { "Content-Type": "application/json" } }
24519
+ );
24520
+ }
24521
+ if (hasX402Header(req.headers)) return handleX402Settle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
24522
+ return handleMppSettle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
24523
+ }
24524
+ let quote = await cache.read(cacheKey2);
24525
+ if (!quote) {
24526
+ let outcome;
24527
+ try {
24528
+ outcome = await opts.runWork(body, { request: req });
24529
+ } catch {
24530
+ return new Response(
24531
+ JSON.stringify({
24532
+ id: referenceId,
24533
+ endpoint: opts.name,
24534
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24535
+ payment_status: "no_charge",
24536
+ charged_usd: "0.00",
24537
+ result: { matches: [], total: 0 },
24538
+ error: {
24539
+ code: "upstream_failed",
24540
+ message: "The wrapped endpoint failed; no charge was applied."
24541
+ }
24542
+ }),
24543
+ { status: 200, headers: { "Content-Type": "application/json" } }
24544
+ );
24545
+ }
24546
+ if (outcome.resultCount === 0) {
24547
+ return new Response(
24548
+ JSON.stringify({
24549
+ id: referenceId,
24550
+ endpoint: opts.name,
24551
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24552
+ payment_status: "no_charge",
24553
+ charged_usd: "0.00",
24554
+ result: outcome.body
24555
+ }),
24556
+ { status: 200, headers: { "Content-Type": "application/json" } }
24557
+ );
24558
+ }
24559
+ const priceCents = opts.unitPriceCents * outcome.resultCount;
24560
+ const recipients = await mintAndResolveRecipients(req, body, priceCents);
24561
+ await cache.write(cacheKey2, outcome.body, priceCents, recipients);
24562
+ quote = { body: outcome.body, priceCents, recipients };
24563
+ }
24564
+ return emit402(req, body, quote.priceCents, quote.recipients);
24565
+ }
24566
+ return {
24567
+ handleWeb: handle,
24568
+ async handleHono(c) {
24569
+ return handle(c.req.raw);
24570
+ }
24571
+ };
24572
+ }
24573
+ function defaultSuccessBody(appUrl) {
24574
+ return ({ referenceId, endpoint, chargedUsd, rail, paymentIntentId, signer, cachedBody }) => ({
24575
+ id: referenceId,
24576
+ endpoint,
24577
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24578
+ payment_status: "completed",
24579
+ charged_usd: chargedUsd,
24580
+ rail,
24581
+ ...paymentIntentId ? { payment_intent_id: paymentIntentId } : {},
24582
+ ...signer ? { signer } : {},
24583
+ result: cachedBody,
24584
+ next_steps: buildSuccessNextSteps({ orderStatusUrl: `${appUrl}/health` }),
24585
+ agent_memory: firstEncounterAgentMemory({ firstEncounter: true })
24586
+ });
24587
+ }
24588
+
24589
+ // src/identity/default_denied.ts
24590
+ function createDefaultOnDenied(opts) {
24591
+ const supportContext = opts.supportContext ?? "Contact support if you believe this denial is in error.";
24592
+ const paymentRequiredMessage = opts.paymentRequiredMessage ?? "AgentScore tier does not support assess. Contact support.";
24593
+ const walletNotTrustedMessage = opts.walletNotTrustedMessage ?? `Identity check did not satisfy policy for ${opts.merchantName}.`;
24594
+ return function defaultOnDenied(reason) {
24595
+ if (reason.code === "wallet_signer_mismatch" || reason.code === "wallet_auth_requires_wallet_signing") {
24596
+ const body = buildSignerMismatchBody({
24597
+ result: {
24598
+ kind: reason.code,
24599
+ claimedOperator: reason.claimed_operator ?? null,
24600
+ actualSignerOperator: reason.actual_signer_operator ?? null,
24601
+ expectedSigner: reason.expected_signer ?? "",
24602
+ actualSigner: reason.actual_signer ?? "",
24603
+ linkedWallets: reason.linked_wallets ?? [],
24604
+ agentInstructions: reason.agent_instructions ?? "",
24605
+ claimedWallet: reason.expected_signer ?? ""
24606
+ }
24607
+ });
24608
+ return { status: 403, body: body ?? denialReasonToBody(reason) };
24609
+ }
24610
+ if (reason.code === "wallet_not_trusted") {
24611
+ return {
24612
+ status: 403,
24613
+ body: {
24614
+ error: { code: "compliance_denied", message: walletNotTrustedMessage },
24615
+ reasons: reason.reasons ?? [],
24616
+ policy_result: reason.data?.policy_result,
24617
+ verify_url: reason.verify_url,
24618
+ next_steps: buildContactSupportNextSteps(opts.supportEmail, supportContext)
24619
+ }
24620
+ };
24621
+ }
24622
+ if (reason.code === "payment_required") {
24623
+ return {
24624
+ status: 403,
24625
+ body: {
24626
+ ...denialReasonToBody(reason),
24627
+ error: { code: "compliance_error", message: paymentRequiredMessage }
24628
+ }
24629
+ };
24630
+ }
24631
+ const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
24632
+ return {
24633
+ status,
24634
+ body: denialReasonToBody(reason),
24635
+ ...status >= 500 && { headers: { "Cache-Control": "no-store" } }
24636
+ };
24637
+ };
24638
+ }
24639
+ function defaultReadOnlyOnDenied(reason) {
24640
+ const message = reason.code === "missing_identity" ? "X-Wallet-Address or X-Operator-Token header required" : "Invalid identity";
24641
+ return {
24642
+ status: 401,
24643
+ body: {
24644
+ ...denialReasonToBody(reason),
24645
+ error: { code: "unauthorized", message }
24646
+ },
24647
+ headers: { "Cache-Control": "no-store" }
24648
+ };
24649
+ }
23802
24650
  export {
24651
+ A2A_DEFAULT_TRANSPORT,
24652
+ A2A_PROTOCOL_VERSION,
23803
24653
  AGENTSCORE_UCP_CAPABILITY,
23804
24654
  Checkout,
23805
24655
  CheckoutValidationError,
@@ -23810,18 +24660,29 @@ export {
23810
24660
  buildA2AAgentCard,
23811
24661
  buildAgentMemoryHint,
23812
24662
  buildContactSupportNextSteps,
24663
+ buildDefaultCheckoutRails,
23813
24664
  buildGateFromPolicy,
23814
24665
  buildJWKSResponse,
24666
+ buildMppxComposeRails,
23815
24667
  buildSignerMismatchBody,
23816
24668
  buildUCPProfile,
24669
+ buildVerificationRequiredBody,
24670
+ computeFirstCheckout,
24671
+ createDefaultOnDenied,
24672
+ createQuoteCache,
24673
+ defaultReadOnlyOnDenied,
23817
24674
  denialReasonStatus,
23818
24675
  denialReasonToBody,
24676
+ extractOwnerScope,
23819
24677
  extractPaymentSigner,
23820
24678
  extractPaymentSignerFromAuth,
23821
24679
  extractSignerForPrecheck,
23822
24680
  formatUsdCents,
23823
24681
  generateUCPSigningKey,
23824
24682
  getIdentityStatus,
24683
+ hasMppxHeader,
24684
+ hasPaymentHeader,
24685
+ hasX402Header,
23825
24686
  hashOperatorToken,
23826
24687
  isFixableDenial,
23827
24688
  loadSolanaFeePayer,