@agent-score/commerce 2.1.0 → 2.2.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 (76) hide show
  1. package/README.md +1 -1
  2. package/dist/challenge/index.d.mts +2 -2
  3. package/dist/challenge/index.d.ts +2 -2
  4. package/dist/challenge/index.js +7 -5
  5. package/dist/challenge/index.js.map +1 -1
  6. package/dist/challenge/index.mjs +7 -5
  7. package/dist/challenge/index.mjs.map +1 -1
  8. package/dist/{checkout-Bd_4aQ6c.d.mts → checkout-CKQE2QpJ.d.mts} +38 -23
  9. package/dist/{checkout-BH-I_Ns8.d.ts → checkout-CfgxgPZL.d.ts} +38 -23
  10. package/dist/core.js +4 -3
  11. package/dist/core.js.map +1 -1
  12. package/dist/core.mjs +4 -3
  13. package/dist/core.mjs.map +1 -1
  14. package/dist/{default_rails-BxBzcCA1.d.ts → default_rails-C5gKZJMI.d.ts} +11 -1
  15. package/dist/{default_rails-BWAquZeu.d.mts → default_rails-XFCuRddA.d.mts} +11 -1
  16. package/dist/discovery/index.d.mts +3 -3
  17. package/dist/discovery/index.d.ts +3 -3
  18. package/dist/identity/express.d.mts +4 -3
  19. package/dist/identity/express.d.ts +4 -3
  20. package/dist/identity/express.js +4 -3
  21. package/dist/identity/express.js.map +1 -1
  22. package/dist/identity/express.mjs +4 -3
  23. package/dist/identity/express.mjs.map +1 -1
  24. package/dist/identity/fastify.d.mts +4 -3
  25. package/dist/identity/fastify.d.ts +4 -3
  26. package/dist/identity/fastify.js +4 -3
  27. package/dist/identity/fastify.js.map +1 -1
  28. package/dist/identity/fastify.mjs +4 -3
  29. package/dist/identity/fastify.mjs.map +1 -1
  30. package/dist/identity/hono.d.mts +4 -3
  31. package/dist/identity/hono.d.ts +4 -3
  32. package/dist/identity/hono.js +4 -3
  33. package/dist/identity/hono.js.map +1 -1
  34. package/dist/identity/hono.mjs +4 -3
  35. package/dist/identity/hono.mjs.map +1 -1
  36. package/dist/identity/nextjs.js +4 -3
  37. package/dist/identity/nextjs.js.map +1 -1
  38. package/dist/identity/nextjs.mjs +4 -3
  39. package/dist/identity/nextjs.mjs.map +1 -1
  40. package/dist/identity/policy.js +22 -23363
  41. package/dist/identity/policy.js.map +1 -1
  42. package/dist/identity/policy.mjs +1 -23366
  43. package/dist/identity/policy.mjs.map +1 -1
  44. package/dist/identity/web.js +4 -3
  45. package/dist/identity/web.js.map +1 -1
  46. package/dist/identity/web.mjs +4 -3
  47. package/dist/identity/web.mjs.map +1 -1
  48. package/dist/index.d.mts +73 -6
  49. package/dist/index.d.ts +73 -6
  50. package/dist/index.js +392 -148
  51. package/dist/index.js.map +1 -1
  52. package/dist/index.mjs +389 -146
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/middleware/express.js.map +1 -1
  55. package/dist/middleware/express.mjs.map +1 -1
  56. package/dist/middleware/fastify.js.map +1 -1
  57. package/dist/middleware/fastify.mjs.map +1 -1
  58. package/dist/middleware/hono.js.map +1 -1
  59. package/dist/middleware/hono.mjs.map +1 -1
  60. package/dist/middleware/nextjs.js.map +1 -1
  61. package/dist/middleware/nextjs.mjs.map +1 -1
  62. package/dist/middleware/web.js.map +1 -1
  63. package/dist/middleware/web.mjs.map +1 -1
  64. package/dist/payment/index.d.mts +13 -17
  65. package/dist/payment/index.d.ts +13 -17
  66. package/dist/payment/index.js +80 -4
  67. package/dist/payment/index.js.map +1 -1
  68. package/dist/payment/index.mjs +79 -4
  69. package/dist/payment/index.mjs.map +1 -1
  70. package/dist/{pricing-4n5Ota0D.d.mts → pricing-dSI3ePmE.d.mts} +4 -2
  71. package/dist/{pricing-DHfH3ogG.d.ts → pricing-uFGRNoGl.d.ts} +4 -2
  72. package/dist/stripe-multichain/index.js +55 -5
  73. package/dist/stripe-multichain/index.js.map +1 -1
  74. package/dist/stripe-multichain/index.mjs +55 -5
  75. package/dist/stripe-multichain/index.mjs.map +1 -1
  76. package/package.json +8 -8
package/dist/index.js CHANGED
@@ -20061,11 +20061,12 @@ function toClient(method, options) {
20061
20061
  };
20062
20062
  }
20063
20063
  function toServer(method, options) {
20064
- const { authorize, defaults, html, request, respond, stableBinding, transport, verify: verify3 } = options;
20064
+ const { authorize, defaults, extensions, html, request, respond, stableBinding, transport, verify: verify3 } = options;
20065
20065
  return {
20066
20066
  ...method,
20067
20067
  authorize,
20068
20068
  defaults,
20069
+ extensions,
20069
20070
  html,
20070
20071
  request,
20071
20072
  respond,
@@ -20825,6 +20826,7 @@ __export(index_exports, {
20825
20826
  buildMppxComposeRails: () => buildMppxComposeRails,
20826
20827
  buildSignerMismatchBody: () => buildSignerMismatchBody,
20827
20828
  buildUCPProfile: () => buildUCPProfile,
20829
+ buildVerificationRequiredBody: () => buildVerificationRequiredBody,
20828
20830
  computeFirstCheckout: () => computeFirstCheckout,
20829
20831
  createDefaultOnDenied: () => createDefaultOnDenied,
20830
20832
  createQuoteCache: () => createQuoteCache,
@@ -21049,6 +21051,20 @@ var RESERVED_FIELDS = /* @__PURE__ */ new Set([
21049
21051
  "actual_signer",
21050
21052
  "linked_wallets"
21051
21053
  ]);
21054
+ function buildVerificationRequiredBody(reason, opts = {}) {
21055
+ const body = denialReasonToBody(reason);
21056
+ body.error = {
21057
+ code: "operator_verification_required",
21058
+ message: opts.message ?? "Identity verification is required."
21059
+ };
21060
+ if (opts.agentInstructions !== void 0) {
21061
+ body.agent_instructions = opts.agentInstructions;
21062
+ }
21063
+ if (opts.extra) {
21064
+ for (const [k, v] of Object.entries(opts.extra)) body[k] = v;
21065
+ }
21066
+ return body;
21067
+ }
21052
21068
  function denialReasonToBody(reason) {
21053
21069
  const message = reason.message ?? DEFAULT_MESSAGES[reason.code];
21054
21070
  const body = { error: { code: reason.code, message } };
@@ -21206,7 +21222,7 @@ function createAgentScoreCore(options) {
21206
21222
  } = options;
21207
21223
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21208
21224
  const agentMemoryHint = buildAgentMemoryHint();
21209
- const defaultUa = `@agent-score/commerce@${"2.1.0"}`;
21225
+ const defaultUa = `@agent-score/commerce@${"2.2.0"}`;
21210
21226
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21211
21227
  const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21212
21228
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21343,8 +21359,9 @@ function createAgentScoreCore(options) {
21343
21359
  ...Object.keys(policy).length > 0 ? { policy } : {},
21344
21360
  // Pre-extracted payment signer (by the adapter middleware). When present, the API
21345
21361
  // composes BOTH signer_match (wallet-binding) and signer_sanctions (OFAC SDN wallet
21346
- // check) verdicts on the response in one round trip. Under
21347
- // policy.require_sanctions_clear, a signer_sanctions hit flips decision -> deny inline.
21362
+ // check) verdicts on the response in one round trip. Wallet-OFAC enforcement on the
21363
+ // signer block is unconditional — a signer_sanctions hit flips decision -> deny
21364
+ // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
21348
21365
  ...signer && { signer: { address: signer.address, network: signer.network } }
21349
21366
  };
21350
21367
  const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
@@ -21664,9 +21681,140 @@ var A2A_DEFAULT_TRANSPORT = DEFAULT_TRANSPORT;
21664
21681
  init_ucp();
21665
21682
  init_ucp_jwks();
21666
21683
 
21667
- // src/checkout.ts
21684
+ // src/errors.ts
21685
+ var CheckoutValidationError = class extends Error {
21686
+ code;
21687
+ action;
21688
+ status;
21689
+ extra;
21690
+ constructor(opts) {
21691
+ super(opts.message);
21692
+ this.name = "CheckoutValidationError";
21693
+ this.code = opts.code;
21694
+ this.action = opts.action ?? "fix_request";
21695
+ this.status = opts.status ?? 400;
21696
+ this.extra = opts.extra;
21697
+ }
21698
+ };
21699
+
21700
+ // src/identity/policy.ts
21701
+ function buildGateFromPolicy(policy, base) {
21702
+ if (!policy || !policy.enforcement) return null;
21703
+ return {
21704
+ apiKey: base.apiKey,
21705
+ ...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
21706
+ ...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
21707
+ ...policy.requireSanctionsClear !== void 0 && {
21708
+ requireSanctionsClear: policy.requireSanctionsClear
21709
+ },
21710
+ ...policy.minAge !== void 0 && { minAge: policy.minAge },
21711
+ ...policy.allowedJurisdictions !== void 0 && {
21712
+ allowedJurisdictions: [...policy.allowedJurisdictions]
21713
+ }
21714
+ };
21715
+ }
21716
+ async function runGateWithEnforcement(enforcement, runGate) {
21717
+ if (!runGate || !enforcement) return { status: "anonymous" };
21718
+ const outcome = await runGate();
21719
+ if (outcome.ok) return { status: "verified" };
21720
+ if (enforcement === "hard") {
21721
+ return {
21722
+ status: "denied",
21723
+ denialStatus: outcome.status,
21724
+ denialBody: outcome.body,
21725
+ ...outcome.reason !== void 0 && { denialReason: outcome.reason }
21726
+ };
21727
+ }
21728
+ return {
21729
+ status: "unverified",
21730
+ denialStatus: outcome.status,
21731
+ denialBody: outcome.body,
21732
+ ...outcome.reason !== void 0 && { denialReason: outcome.reason }
21733
+ };
21734
+ }
21735
+ function shippingCountryAllowed(country, policy) {
21736
+ if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
21737
+ const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
21738
+ return allowed.has(country.toUpperCase());
21739
+ }
21740
+ function shippingStateAllowed(state, country, policy) {
21741
+ if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
21742
+ if (country.toUpperCase() !== "US") return true;
21743
+ const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
21744
+ return allowed.has(state.toUpperCase());
21745
+ }
21746
+ function validateShippingAgainstPolicy(opts) {
21747
+ const code = opts.errorCode ?? "unsupported_jurisdiction";
21748
+ const action = opts.errorAction ?? "change_shipping_state";
21749
+ const item = opts.productName ? `'${opts.productName}'` : "this item";
21750
+ if (!shippingCountryAllowed(opts.country, opts.policy)) {
21751
+ throw new CheckoutValidationError({
21752
+ code,
21753
+ message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
21754
+ action
21755
+ });
21756
+ }
21757
+ if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
21758
+ throw new CheckoutValidationError({
21759
+ code,
21760
+ message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
21761
+ action
21762
+ });
21763
+ }
21764
+ }
21765
+
21766
+ // src/identity/tokens.ts
21668
21767
  var import_node_crypto = require("crypto");
21669
21768
 
21769
+ // src/payment/payment_header.ts
21770
+ function toTitleCase(name) {
21771
+ return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
21772
+ }
21773
+ function readHeader(headers, name) {
21774
+ if (typeof headers.get === "function") {
21775
+ return headers.get(name);
21776
+ }
21777
+ const rec = headers;
21778
+ const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
21779
+ if (typeof v === "string") return v;
21780
+ if (Array.isArray(v) && typeof v[0] === "string") return v[0];
21781
+ return null;
21782
+ }
21783
+ function asHeaders(input) {
21784
+ return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
21785
+ }
21786
+ function hasPaymentHeader(input) {
21787
+ const headers = asHeaders(input);
21788
+ return Boolean(
21789
+ readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
21790
+ );
21791
+ }
21792
+ function hasX402Header(input) {
21793
+ const headers = asHeaders(input);
21794
+ return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
21795
+ }
21796
+ function hasMppxHeader(input) {
21797
+ const headers = asHeaders(input);
21798
+ return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
21799
+ }
21800
+
21801
+ // src/identity/tokens.ts
21802
+ function hashOperatorToken(plaintext) {
21803
+ return (0, import_node_crypto.createHash)("sha256").update(plaintext, "utf8").digest("hex");
21804
+ }
21805
+ function extractOwnerScope(input) {
21806
+ const headers = asHeaders(input);
21807
+ const walletAddress = readHeader(headers, "x-wallet-address");
21808
+ const operatorToken = readHeader(headers, "x-operator-token");
21809
+ return {
21810
+ ...walletAddress ? { walletAddress } : {},
21811
+ ...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
21812
+ };
21813
+ }
21814
+
21815
+ // src/checkout.ts
21816
+ var import_node_crypto2 = require("crypto");
21817
+
21670
21818
  // src/_mppx_receipt.ts
21671
21819
  function extractMppxReceiptHeaderFromRaw(raw) {
21672
21820
  if (!raw || typeof raw !== "object" || !("withReceipt" in raw)) return null;
@@ -21695,6 +21843,16 @@ async function deriveMppxReceiptMethod(raw) {
21695
21843
  return extractMppxReceiptMethod(header);
21696
21844
  }
21697
21845
 
21846
+ // src/_warnings.ts
21847
+ var warnedNoApiKey = false;
21848
+ function warnMissingApiKeyOnce(label) {
21849
+ if (warnedNoApiKey) return;
21850
+ warnedNoApiKey = true;
21851
+ console.warn(
21852
+ `[${label}] AGENTSCORE_API_KEY is not set \u2014 wallet OFAC SDN sanctions are NOT being enforced. Set the env var to enable strict-liability protection on settle.`
21853
+ );
21854
+ }
21855
+
21698
21856
  // src/payment/rail_spec.ts
21699
21857
  init_usdc();
21700
21858
  async function resolveRecipient(r) {
@@ -21926,14 +22084,16 @@ function buildHowToPay({
21926
22084
  const d = decimals ?? 2;
21927
22085
  const defaultMaxSpend = totalNum >= 1 ? (Math.ceil(totalNum) + 1).toFixed(d) : totalNum.toFixed(d);
21928
22086
  const maxSpendStr = String(maxSpend ?? defaultMaxSpend);
22087
+ const gateless = opTokenPlaceholder === null;
21929
22088
  const opToken = opTokenPlaceholder ?? "<your_opc_token>";
22089
+ const opTokenHeaderFlag = gateless ? "" : `-H 'X-Operator-Token: ${opToken}' `;
21930
22090
  const block = {};
21931
22091
  if (rails2.tempo) {
21932
22092
  const networkName = rails2.tempo.testnet ? "tempo-testnet" : rails2.tempo.network ?? RAIL_SPEC_DEFAULTS.tempo.network;
21933
22093
  const chainId = rails2.tempo.chainId ?? RAIL_SPEC_DEFAULTS.tempo.chainId;
21934
22094
  const recommend = rails2.tempo.recommend ?? RAIL_SPEC_DEFAULTS.tempo.recommend;
21935
- const tempoCommand = `tempo request -X POST -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' --json '${retryBodyJson}' --max-spend ${maxSpendStr} ${url2}`;
21936
- const payCommand = `agentscore-pay pay POST ${url2} --chain tempo -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`;
22095
+ const tempoCommand = `tempo request -X POST ${opTokenHeaderFlag}-H 'Content-Type: application/json' --json '${retryBodyJson}' --max-spend ${maxSpendStr} ${url2}`;
22096
+ const payCommand = `agentscore-pay pay POST ${url2} --chain tempo ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`;
21937
22097
  block.tempo = {
21938
22098
  setup: TEMPO_SETUP,
21939
22099
  prerequisite: `Run \`tempo wallet whoami\` and confirm USDC.e balance on ${networkName} (chain ${chainId}) is at least $${maxSpendStr}. If the tempo CLI is not installed, run the setup commands above first.`,
@@ -21947,7 +22107,7 @@ function buildHowToPay({
21947
22107
  block.x402_base = {
21948
22108
  setup: PAY_SETUP_BASE,
21949
22109
  prerequisite: `Run \`agentscore-pay balance --chain base\` and confirm USDC balance on Base (${network}) is at least $${maxSpendStr}. If the CLI is not installed, run the setup commands above first.`,
21950
- command: `agentscore-pay pay POST ${url2} --chain base -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
22110
+ command: `agentscore-pay pay POST ${url2} --chain base ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
21951
22111
  what_it_does: "Pays via USDC on Base."
21952
22112
  };
21953
22113
  }
@@ -21956,7 +22116,7 @@ function buildHowToPay({
21956
22116
  block.solana_mpp = {
21957
22117
  setup: PAY_SETUP_SOLANA,
21958
22118
  prerequisite: `Run \`agentscore-pay balance --chain solana\` and confirm USDC balance on Solana (${network}) is at least $${maxSpendStr}. If the CLI is not installed, run the setup commands above first.`,
21959
- command: `agentscore-pay pay POST ${url2} --chain solana -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
22119
+ command: `agentscore-pay pay POST ${url2} --chain solana ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
21960
22120
  what_it_does: "Pays via USDC on Solana."
21961
22121
  };
21962
22122
  }
@@ -21978,7 +22138,7 @@ function buildHowToPay({
21978
22138
  ];
21979
22139
  stripe.command_link_cli = [
21980
22140
  `SPEND_ID=$(link-cli spend-request create --payment-method-id <csmrpd_id_from_payment_methods_list> --credential-type shared_payment_token --network-id ${stripeCfg.profileId} --amount ${amountCents} --context "${sptContext}" --request-approval --output-json | jq -r .id)`,
21981
- `link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --header 'X-Operator-Token: ${opToken}' --output-json`
22141
+ gateless ? `link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --output-json` : `link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --header 'X-Operator-Token: ${opToken}' --output-json`
21982
22142
  ];
21983
22143
  stripe.what_it_does_link_cli = "Mints a one-time-use SharedPaymentToken scoped to this purchase (user approves in Link wallet), then submits it as the payment credential.";
21984
22144
  } else if (linkCliBlocked) {
@@ -22073,6 +22233,12 @@ function buildValidationError({
22073
22233
  return body;
22074
22234
  }
22075
22235
 
22236
+ // src/payment/constants.ts
22237
+ var STRIPE_MIN_CHARGE_USD = 0.5;
22238
+
22239
+ // src/payment/mppx_server.ts
22240
+ var import_node_async_hooks = require("async_hooks");
22241
+
22076
22242
  // src/stripe-multichain/mppx_stripe.ts
22077
22243
  async function createMppxStripe({
22078
22244
  profileId,
@@ -22253,6 +22419,31 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
22253
22419
  }
22254
22420
  };
22255
22421
  }
22422
+ var mppxCapture = new import_node_async_hooks.AsyncLocalStorage();
22423
+ var consoleErrorPatched = false;
22424
+ function ensureConsoleErrorPatch() {
22425
+ if (consoleErrorPatched) return;
22426
+ consoleErrorPatched = true;
22427
+ const original = console.error.bind(console);
22428
+ console.error = function captureMppxInternal(...args) {
22429
+ if (args[0] === "mppx: internal verification error" && args[1] !== void 0) {
22430
+ const ctx = mppxCapture.getStore();
22431
+ if (ctx) {
22432
+ const e = args[1];
22433
+ const reason = typeof e?.shortMessage === "string" ? e.shortMessage : typeof e?.message === "string" ? e.message : String(args[1]);
22434
+ const details = e?.details;
22435
+ ctx.reason = typeof details === "string" && details.length > 0 ? `${reason} (${details})` : reason;
22436
+ }
22437
+ }
22438
+ return original(...args);
22439
+ };
22440
+ }
22441
+ async function runWithMppxFailureCapture(fn) {
22442
+ ensureConsoleErrorPatch();
22443
+ const ctx = { reason: null };
22444
+ const result = await mppxCapture.run(ctx, fn);
22445
+ return { result, failureReason: ctx.reason };
22446
+ }
22256
22447
 
22257
22448
  // src/payment/x402_server.ts
22258
22449
  init_networks();
@@ -22394,40 +22585,28 @@ function lazyMppxServer(opts) {
22394
22585
  };
22395
22586
  }
22396
22587
 
22397
- // src/checkout.ts
22398
- init_network_kind();
22399
-
22400
- // src/payment/payment_header.ts
22401
- function toTitleCase(name) {
22402
- return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
22403
- }
22404
- function readHeader(headers, name) {
22405
- if (typeof headers.get === "function") {
22406
- return headers.get(name);
22588
+ // src/payment/mppx_failures.ts
22589
+ var TEMPO_KEY_NOT_REGISTERED = {
22590
+ code: "tempo_key_not_registered",
22591
+ status: 401,
22592
+ message: "Tempo rejected the transaction: signer wallet is not registered with Tempo's keychain.",
22593
+ nextSteps: {
22594
+ action: "register_tempo_key",
22595
+ 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."
22596
+ },
22597
+ extra: { upstream_error: "KeyNotFound", chain: "tempo" }
22598
+ };
22599
+ function classifyMppxFailure(reason) {
22600
+ if (!reason) return null;
22601
+ const lower = reason.toLowerCase();
22602
+ if (lower.includes("keychain validation failed") || lower.includes("keynotfound")) {
22603
+ return TEMPO_KEY_NOT_REGISTERED;
22407
22604
  }
22408
- const rec = headers;
22409
- const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
22410
- if (typeof v === "string") return v;
22411
- if (Array.isArray(v) && typeof v[0] === "string") return v[0];
22412
22605
  return null;
22413
22606
  }
22414
- function asHeaders(input) {
22415
- return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
22416
- }
22417
- function hasPaymentHeader(input) {
22418
- const headers = asHeaders(input);
22419
- return Boolean(
22420
- readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
22421
- );
22422
- }
22423
- function hasX402Header(input) {
22424
- const headers = asHeaders(input);
22425
- return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
22426
- }
22427
- function hasMppxHeader(input) {
22428
- const headers = asHeaders(input);
22429
- return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
22430
- }
22607
+
22608
+ // src/checkout.ts
22609
+ init_network_kind();
22431
22610
 
22432
22611
  // src/payment/x402_settle.ts
22433
22612
  function classifyX402SettleResult(result) {
@@ -22750,20 +22929,6 @@ function getIdentityStatus(ctx) {
22750
22929
  if (decision === "allow") return "verified";
22751
22930
  return "unverified";
22752
22931
  }
22753
- var CheckoutValidationError = class extends Error {
22754
- code;
22755
- action;
22756
- status;
22757
- extra;
22758
- constructor(opts) {
22759
- super(opts.message);
22760
- this.name = "CheckoutValidationError";
22761
- this.code = opts.code;
22762
- this.action = opts.action ?? "fix_request";
22763
- this.status = opts.status ?? 400;
22764
- this.extra = opts.extra;
22765
- }
22766
- };
22767
22932
  function resolveIdentityMetadata(ctx) {
22768
22933
  const h = normalizeHeadersToLowercase(ctx.request.headers);
22769
22934
  const wallet = h["x-wallet-address"];
@@ -22890,6 +23055,23 @@ var Checkout = class {
22890
23055
  discoveryExtensions;
22891
23056
  discoveryProbe;
22892
23057
  _x402ServerGetter;
23058
+ /**
23059
+ * True when the merchant has configured an identity-bearing policy flag —
23060
+ * `require_kyc`, `require_sanctions_clear` (name screening on the KYC
23061
+ * identity), `min_age`, or jurisdiction lists. Wallet OFAC SDN enforcement
23062
+ * (the always-on default) does NOT count as an identity gate; agents don't
23063
+ * need an AgentScore credential to satisfy it.
23064
+ *
23065
+ * Used to conditionally emit AgentScore identity boilerplate in 402 bodies
23066
+ * (`agent_memory`, `X-Operator-Token` references in per-rail commands).
23067
+ */
23068
+ hasIdentityGate() {
23069
+ const g = this.gate;
23070
+ if (!g) return false;
23071
+ return Boolean(
23072
+ g.requireKyc || g.requireSanctionsClear || g.minAge !== void 0 || g.allowedJurisdictions && g.allowedJurisdictions.length > 0 || g.blockedJurisdictions && g.blockedJurisdictions.length > 0
23073
+ );
23074
+ }
22893
23075
  constructor(opts) {
22894
23076
  const x402Server = opts.x402Server;
22895
23077
  let x402ServerGetter;
@@ -23087,8 +23269,8 @@ var Checkout = class {
23087
23269
  }
23088
23270
  }
23089
23271
  const hasPaymentHeader2 = hasX402Header(request.headers) || hasMppxHeader(request.headers);
23090
- if (this.gate !== void 0 && hasPaymentHeader2) {
23091
- const denial = await this.runGate(ctx);
23272
+ if (hasPaymentHeader2) {
23273
+ const denial = this.gate !== void 0 ? await this.runGate(ctx) : await this.runWalletSanctionsOnly(ctx);
23092
23274
  if (denial !== null) {
23093
23275
  return {
23094
23276
  status: denial.status,
@@ -23100,7 +23282,14 @@ var Checkout = class {
23100
23282
  }
23101
23283
  }
23102
23284
  ctx.pricing = await this.computePricing(ctx);
23103
- await this.resolveRecipientsForCtx(ctx);
23285
+ try {
23286
+ await this.resolveRecipientsForCtx(ctx);
23287
+ } catch (err) {
23288
+ if (err instanceof Error && err.name === "CheckoutValidationError") {
23289
+ return this.validationErrorResult(ctx, err);
23290
+ }
23291
+ throw err;
23292
+ }
23104
23293
  const x402ServerOk = this.x402ServerAvailable() && this.x402BaseNetwork !== null;
23105
23294
  if (hasX402Header(request.headers) && x402ServerOk) {
23106
23295
  const zero = await this.handleZeroSettle(ctx, "x402-base");
@@ -23153,7 +23342,9 @@ var Checkout = class {
23153
23342
  }
23154
23343
  return result;
23155
23344
  }
23156
- if (gate.apiKey === void 0) return null;
23345
+ if (gate.apiKey === void 0) {
23346
+ return this.runWalletSanctionsOnly(ctx);
23347
+ }
23157
23348
  let policyOverride;
23158
23349
  if (gate.perRequestPolicy !== void 0) {
23159
23350
  policyOverride = await gate.perRequestPolicy(ctx);
@@ -23171,8 +23362,16 @@ var Checkout = class {
23171
23362
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23172
23363
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23173
23364
  ...gate.chain !== void 0 && { chain: gate.chain },
23174
- ...gate.createSessionOnMissing !== void 0 && {
23175
- createSessionOnMissing: gate.createSessionOnMissing
23365
+ // Auto-default `createSessionOnMissing` from gate config when the merchant
23366
+ // didn't supply one. Matches python-commerce's behavior — every gated route
23367
+ // gets the bootstrap session-mint UX out of the box. Merchants who need
23368
+ // custom session context or onBeforeSession side effects (goods merchants
23369
+ // pre-minting an order_id) supply their own config instead.
23370
+ createSessionOnMissing: gate.createSessionOnMissing ?? {
23371
+ apiKey: gate.apiKey,
23372
+ ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
23373
+ ...gate.context !== void 0 && { context: gate.context },
23374
+ ...gate.merchantName !== void 0 && { productName: gate.merchantName }
23176
23375
  },
23177
23376
  ...policyOverride ?? {}
23178
23377
  };
@@ -23235,6 +23434,58 @@ var Checkout = class {
23235
23434
  const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
23236
23435
  return { status, body };
23237
23436
  }
23437
+ /**
23438
+ * Wallet OFAC SDN enforcement.
23439
+ *
23440
+ * Runs on settle (payment header present) when either `this.gate` is
23441
+ * undefined OR a gate is configured but has no `apiKey` to reach
23442
+ * `/v1/assess` for full policy enforcement (fallback to the
23443
+ * strict-liability default).
23444
+ *
23445
+ * Env knobs:
23446
+ * - `AGENTSCORE_API_KEY` — required. No key → one-time warning + skip
23447
+ * (dev/testnet pattern; production should always configure a key).
23448
+ * - `AGENTSCORE_BASE_URL` — optional override for staging/dev API
23449
+ * (e.g. `https://api-dev.agentscore.sh` or `http://localhost:3002`).
23450
+ *
23451
+ * Stripe SPT (no extractable wallet signer) → skip silently; Stripe runs
23452
+ * its own OFAC screen on the buyer's Stripe account at customer creation.
23453
+ *
23454
+ * Calls `/v1/assess` with the signer wallet as both the primary address
23455
+ * and the signer block. The API enforces signer-sanctions unconditionally
23456
+ * when a signer is present (no policy flag needed). Denies on OFAC SDN
23457
+ * hit; fail-closed on unavailable lookup (strict liability — falsely
23458
+ * allowing a sanctioned settle is an OFAC violation, falsely denying a
23459
+ * clean buyer is just bad UX).
23460
+ */
23461
+ async runWalletSanctionsOnly(ctx) {
23462
+ const apiKey = process.env.AGENTSCORE_API_KEY;
23463
+ if (!apiKey) {
23464
+ warnMissingApiKeyOnce("checkout");
23465
+ return null;
23466
+ }
23467
+ const headers = normalizeHeadersToLowercase(ctx.request.headers);
23468
+ const x402Header = headers["payment-signature"] ?? headers["x-payment"];
23469
+ const signer = await extractPaymentSignerFromAuth(headers["authorization"], x402Header);
23470
+ if (!signer) {
23471
+ return null;
23472
+ }
23473
+ const baseUrl = process.env.AGENTSCORE_BASE_URL;
23474
+ const core = createAgentScoreCore({
23475
+ apiKey,
23476
+ ...baseUrl !== void 0 && { baseUrl }
23477
+ });
23478
+ const outcome = await core.evaluate(
23479
+ { address: signer.address },
23480
+ ctx,
23481
+ signer
23482
+ );
23483
+ if (outcome.kind === "allow") return null;
23484
+ const reason = outcome.reason;
23485
+ const body = denialReasonToBody(reason);
23486
+ const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
23487
+ return { status, body };
23488
+ }
23238
23489
  async handleZeroSettle(ctx, rail) {
23239
23490
  if (!this.zeroSettleCarveOut || ctx.pricing === null) return null;
23240
23491
  const cents = Math.round(ctx.pricing.amountUsd * 100);
@@ -23269,7 +23520,7 @@ var Checkout = class {
23269
23520
  return await this.buildSuccess(ctx, outcome);
23270
23521
  }
23271
23522
  async mintRefId(request) {
23272
- if (this.mintReferenceId === void 0) return (0, import_node_crypto.randomUUID)();
23523
+ if (this.mintReferenceId === void 0) return (0, import_node_crypto2.randomUUID)();
23273
23524
  const seedCtx = { request, referenceId: "", pricing: null, recipients: {}, state: {} };
23274
23525
  return await this.mintReferenceId(seedCtx);
23275
23526
  }
@@ -23372,7 +23623,9 @@ var Checkout = class {
23372
23623
  if (this.composeMppx === void 0) {
23373
23624
  throw new Error("Checkout.handleMppx: composeMppx hook not configured");
23374
23625
  }
23375
- const composed = await this.composeMppx(ctx);
23626
+ const { result: composed, failureReason } = await runWithMppxFailureCapture(
23627
+ async () => this.composeMppx(ctx)
23628
+ );
23376
23629
  if (composed.status === 200) {
23377
23630
  const paymentReceiptHeader = composed.paymentReceiptHeader ?? extractMppxReceiptHeaderFromRaw(composed.raw);
23378
23631
  const directMethod = composed.raw?.receipt?.method;
@@ -23391,6 +23644,22 @@ var Checkout = class {
23391
23644
  };
23392
23645
  return await this.buildSuccess(ctx, outcome);
23393
23646
  }
23647
+ const classified = classifyMppxFailure(failureReason);
23648
+ if (classified !== null) {
23649
+ return {
23650
+ status: classified.status,
23651
+ body: buildValidationError({
23652
+ code: classified.code,
23653
+ message: classified.message,
23654
+ nextSteps: classified.nextSteps,
23655
+ ...classified.extra && { extra: classified.extra }
23656
+ }),
23657
+ headers: { ...composed.headers ?? {} },
23658
+ referenceId: ctx.referenceId,
23659
+ settled: false,
23660
+ settlePhase: "verify_failed"
23661
+ };
23662
+ }
23394
23663
  return {
23395
23664
  status: 400,
23396
23665
  body: buildValidationError({
@@ -23409,7 +23678,11 @@ var Checkout = class {
23409
23678
  throw new Error("Checkout.emit402: pricing not computed");
23410
23679
  }
23411
23680
  await this.resolveRecipientsForCtx(ctx);
23412
- const emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
23681
+ let emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
23682
+ if (ctx.pricing.amountUsd < STRIPE_MIN_CHARGE_USD && emitRails.stripe !== void 0) {
23683
+ const { stripe: _stripe, ...rest } = emitRails;
23684
+ emitRails = rest;
23685
+ }
23413
23686
  const accepted = await buildAcceptedMethods({
23414
23687
  tempo: pickRail(emitRails, "tempo"),
23415
23688
  x402_base: pickRail(emitRails, "x402_base"),
@@ -23428,6 +23701,10 @@ var Checkout = class {
23428
23701
  retryBodyJson: JSON.stringify(ctx.request.body),
23429
23702
  totalUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
23430
23703
  rails: howToPayRails,
23704
+ // Merchants without an identity-bearing policy flag get clean commands
23705
+ // without an X-Operator-Token header — agents don't need one to satisfy
23706
+ // wallet OFAC enforcement (the always-on default).
23707
+ ...this.hasIdentityGate() ? {} : { opTokenPlaceholder: null },
23431
23708
  ...ctx.pricing.decimals !== void 0 && { decimals: ctx.pricing.decimals }
23432
23709
  });
23433
23710
  const pricingBlock = ctx.pricing.block ?? buildPricingBlock({
@@ -23464,7 +23741,10 @@ var Checkout = class {
23464
23741
  pricing: pricingBlock,
23465
23742
  amountUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
23466
23743
  retryBody: ctx.request.body,
23467
- agentMemory: firstEncounterAgentMemory({ firstEncounter: true }),
23744
+ // Merchants without an identity-bearing gate get a clean 402: no
23745
+ // AgentScore-identity bootstrap describing a verification flow they
23746
+ // don't run. Wallet OFAC (the always-on default) doesn't need it.
23747
+ agentMemory: firstEncounterAgentMemory({ firstEncounter: this.hasIdentityGate() }),
23468
23748
  ...ctx.pricing.product ? { product: ctx.pricing.product } : {},
23469
23749
  ...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
23470
23750
  ...x402Accepts.length > 0 ? {
@@ -23812,87 +24092,6 @@ Checkout.prototype.mountUcpRoutesFastify = function(app, opts) {
23812
24092
  app.options(jwksPath, preflight);
23813
24093
  };
23814
24094
 
23815
- // src/identity/policy.ts
23816
- function buildGateFromPolicy(policy, base) {
23817
- if (!policy || !policy.enforcement) return null;
23818
- return {
23819
- apiKey: base.apiKey,
23820
- ...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
23821
- ...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
23822
- ...policy.requireSanctionsClear !== void 0 && {
23823
- requireSanctionsClear: policy.requireSanctionsClear
23824
- },
23825
- ...policy.minAge !== void 0 && { minAge: policy.minAge },
23826
- ...policy.allowedJurisdictions !== void 0 && {
23827
- allowedJurisdictions: [...policy.allowedJurisdictions]
23828
- }
23829
- };
23830
- }
23831
- async function runGateWithEnforcement(enforcement, runGate) {
23832
- if (!runGate || !enforcement) return { status: "anonymous" };
23833
- const outcome = await runGate();
23834
- if (outcome.ok) return { status: "verified" };
23835
- if (enforcement === "hard") {
23836
- return {
23837
- status: "denied",
23838
- denialStatus: outcome.status,
23839
- denialBody: outcome.body,
23840
- ...outcome.reason !== void 0 && { denialReason: outcome.reason }
23841
- };
23842
- }
23843
- return {
23844
- status: "unverified",
23845
- denialStatus: outcome.status,
23846
- denialBody: outcome.body,
23847
- ...outcome.reason !== void 0 && { denialReason: outcome.reason }
23848
- };
23849
- }
23850
- function shippingCountryAllowed(country, policy) {
23851
- if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
23852
- const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
23853
- return allowed.has(country.toUpperCase());
23854
- }
23855
- function shippingStateAllowed(state, country, policy) {
23856
- if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
23857
- if (country.toUpperCase() !== "US") return true;
23858
- const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
23859
- return allowed.has(state.toUpperCase());
23860
- }
23861
- function validateShippingAgainstPolicy(opts) {
23862
- const code = opts.errorCode ?? "unsupported_jurisdiction";
23863
- const action = opts.errorAction ?? "change_shipping_state";
23864
- const item = opts.productName ? `'${opts.productName}'` : "this item";
23865
- if (!shippingCountryAllowed(opts.country, opts.policy)) {
23866
- throw new CheckoutValidationError({
23867
- code,
23868
- message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
23869
- action
23870
- });
23871
- }
23872
- if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
23873
- throw new CheckoutValidationError({
23874
- code,
23875
- message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
23876
- action
23877
- });
23878
- }
23879
- }
23880
-
23881
- // src/identity/tokens.ts
23882
- var import_node_crypto2 = require("crypto");
23883
- function hashOperatorToken(plaintext) {
23884
- return (0, import_node_crypto2.createHash)("sha256").update(plaintext, "utf8").digest("hex");
23885
- }
23886
- function extractOwnerScope(input) {
23887
- const headers = asHeaders(input);
23888
- const walletAddress = readHeader(headers, "x-wallet-address");
23889
- const operatorToken = readHeader(headers, "x-operator-token");
23890
- return {
23891
- ...walletAddress ? { walletAddress } : {},
23892
- ...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
23893
- };
23894
- }
23895
-
23896
24095
  // src/payment/index.ts
23897
24096
  init_directive();
23898
24097
  init_networks();
@@ -23969,6 +24168,7 @@ async function loadSolanaFeePayer(opts) {
23969
24168
 
23970
24169
  // src/payment/compose_rails.ts
23971
24170
  init_usdc();
24171
+ var warnedStripeBelowMinimum = false;
23972
24172
  function buildMppxComposeRails(opts) {
23973
24173
  const rails2 = [];
23974
24174
  if (opts.tempoRecipient) {
@@ -23990,7 +24190,17 @@ function buildMppxComposeRails(opts) {
23990
24190
  }]);
23991
24191
  }
23992
24192
  if (opts.includeStripe !== false) {
23993
- rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
24193
+ const amountUsdNumeric = Number(opts.amountUsd);
24194
+ if (Number.isFinite(amountUsdNumeric) && amountUsdNumeric < STRIPE_MIN_CHARGE_USD) {
24195
+ if (!warnedStripeBelowMinimum) {
24196
+ warnedStripeBelowMinimum = true;
24197
+ console.warn(
24198
+ `[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.`
24199
+ );
24200
+ }
24201
+ } else {
24202
+ rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
24203
+ }
23994
24204
  }
23995
24205
  return rails2;
23996
24206
  }
@@ -24181,10 +24391,11 @@ function computeFirstCheckout(opts) {
24181
24391
  const tempoRecipient = recipients.tempo;
24182
24392
  const x402BaseRecipient = recipients.x402_base;
24183
24393
  const solanaRecipient = recipients.solana_mpp;
24394
+ const includeStripeInDiscovery = opts.rails.stripe !== void 0 && Number(totalUsd) >= STRIPE_MIN_CHARGE_USD;
24184
24395
  const accepted = await buildAcceptedMethods({
24185
24396
  ...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
24186
24397
  ...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
24187
- ...opts.rails.stripe && { stripe: opts.rails.stripe }
24398
+ ...includeStripeInDiscovery && { stripe: opts.rails.stripe }
24188
24399
  });
24189
24400
  if (x402BaseRecipient && opts.rails.x402_base) {
24190
24401
  try {
@@ -24261,6 +24472,36 @@ function computeFirstCheckout(opts) {
24261
24472
  );
24262
24473
  return new Response(JSON.stringify(body402), { status: 402, headers });
24263
24474
  }
24475
+ async function enforceWalletSanctions(req, referenceId) {
24476
+ const apiKey = process.env.AGENTSCORE_API_KEY;
24477
+ if (!apiKey) {
24478
+ warnMissingApiKeyOnce(`${opts.name}.computeFirst`);
24479
+ return null;
24480
+ }
24481
+ const x402Header = readX402PaymentHeader(req);
24482
+ const signer = await extractPaymentSigner(req, x402Header);
24483
+ if (!signer) return null;
24484
+ const baseUrl = process.env.AGENTSCORE_BASE_URL;
24485
+ const core = createAgentScoreCore({
24486
+ apiKey,
24487
+ ...baseUrl !== void 0 && { baseUrl }
24488
+ });
24489
+ const outcome = await core.evaluate({ address: signer.address }, void 0, signer);
24490
+ if (outcome.kind === "allow") return null;
24491
+ const reason = outcome.reason;
24492
+ const body = denialReasonToBody(reason);
24493
+ const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
24494
+ return new Response(
24495
+ JSON.stringify({
24496
+ id: referenceId,
24497
+ endpoint: opts.name,
24498
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24499
+ payment_status: "failed",
24500
+ ...body
24501
+ }),
24502
+ { status, headers: { "Content-Type": "application/json" } }
24503
+ );
24504
+ }
24264
24505
  async function handleX402Settle(req, referenceId, cachedBody, priceCents, recipients) {
24265
24506
  const verified = await verifyX402Request({
24266
24507
  request: req,
@@ -24459,6 +24700,8 @@ function computeFirstCheckout(opts) {
24459
24700
  { status: 400, headers: { "Content-Type": "application/json" } }
24460
24701
  );
24461
24702
  }
24703
+ const ofacDenial = await enforceWalletSanctions(req, referenceId);
24704
+ if (ofacDenial !== null) return ofacDenial;
24462
24705
  if (hasX402Header(req.headers)) return handleX402Settle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
24463
24706
  return handleMppSettle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
24464
24707
  }
@@ -24608,6 +24851,7 @@ function defaultReadOnlyOnDenied(reason) {
24608
24851
  buildMppxComposeRails,
24609
24852
  buildSignerMismatchBody,
24610
24853
  buildUCPProfile,
24854
+ buildVerificationRequiredBody,
24611
24855
  computeFirstCheckout,
24612
24856
  createDefaultOnDenied,
24613
24857
  createQuoteCache,