@agent-score/commerce 2.1.0 → 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 (64) hide show
  1. package/README.md +1 -1
  2. package/dist/challenge/index.js.map +1 -1
  3. package/dist/challenge/index.mjs.map +1 -1
  4. package/dist/{checkout-Bd_4aQ6c.d.mts → checkout-BRw_caGr.d.mts} +1 -22
  5. package/dist/{checkout-BH-I_Ns8.d.ts → checkout-CuSNUJFX.d.ts} +1 -22
  6. package/dist/core.js +1 -1
  7. package/dist/core.js.map +1 -1
  8. package/dist/core.mjs +1 -1
  9. package/dist/core.mjs.map +1 -1
  10. package/dist/{default_rails-BxBzcCA1.d.ts → default_rails-C5gKZJMI.d.ts} +11 -1
  11. package/dist/{default_rails-BWAquZeu.d.mts → default_rails-XFCuRddA.d.mts} +11 -1
  12. package/dist/discovery/index.d.mts +1 -1
  13. package/dist/discovery/index.d.ts +1 -1
  14. package/dist/identity/express.js +1 -1
  15. package/dist/identity/express.js.map +1 -1
  16. package/dist/identity/express.mjs +1 -1
  17. package/dist/identity/express.mjs.map +1 -1
  18. package/dist/identity/fastify.js +1 -1
  19. package/dist/identity/fastify.js.map +1 -1
  20. package/dist/identity/fastify.mjs +1 -1
  21. package/dist/identity/fastify.mjs.map +1 -1
  22. package/dist/identity/hono.js +1 -1
  23. package/dist/identity/hono.js.map +1 -1
  24. package/dist/identity/hono.mjs +1 -1
  25. package/dist/identity/hono.mjs.map +1 -1
  26. package/dist/identity/nextjs.js +1 -1
  27. package/dist/identity/nextjs.js.map +1 -1
  28. package/dist/identity/nextjs.mjs +1 -1
  29. package/dist/identity/nextjs.mjs.map +1 -1
  30. package/dist/identity/policy.js +22 -23363
  31. package/dist/identity/policy.js.map +1 -1
  32. package/dist/identity/policy.mjs +1 -23366
  33. package/dist/identity/policy.mjs.map +1 -1
  34. package/dist/identity/web.js +1 -1
  35. package/dist/identity/web.js.map +1 -1
  36. package/dist/identity/web.mjs +1 -1
  37. package/dist/identity/web.mjs.map +1 -1
  38. package/dist/index.d.mts +72 -5
  39. package/dist/index.d.ts +72 -5
  40. package/dist/index.js +256 -136
  41. package/dist/index.js.map +1 -1
  42. package/dist/index.mjs +253 -134
  43. package/dist/index.mjs.map +1 -1
  44. package/dist/middleware/express.js.map +1 -1
  45. package/dist/middleware/express.mjs.map +1 -1
  46. package/dist/middleware/fastify.js.map +1 -1
  47. package/dist/middleware/fastify.mjs.map +1 -1
  48. package/dist/middleware/hono.js.map +1 -1
  49. package/dist/middleware/hono.mjs.map +1 -1
  50. package/dist/middleware/nextjs.js.map +1 -1
  51. package/dist/middleware/nextjs.mjs.map +1 -1
  52. package/dist/middleware/web.js.map +1 -1
  53. package/dist/middleware/web.mjs.map +1 -1
  54. package/dist/payment/index.d.mts +13 -17
  55. package/dist/payment/index.d.ts +13 -17
  56. package/dist/payment/index.js +80 -4
  57. package/dist/payment/index.js.map +1 -1
  58. package/dist/payment/index.mjs +79 -4
  59. package/dist/payment/index.mjs.map +1 -1
  60. package/dist/stripe-multichain/index.js +53 -4
  61. package/dist/stripe-multichain/index.js.map +1 -1
  62. package/dist/stripe-multichain/index.mjs +53 -4
  63. package/dist/stripe-multichain/index.mjs.map +1 -1
  64. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -20825,6 +20825,7 @@ __export(index_exports, {
20825
20825
  buildMppxComposeRails: () => buildMppxComposeRails,
20826
20826
  buildSignerMismatchBody: () => buildSignerMismatchBody,
20827
20827
  buildUCPProfile: () => buildUCPProfile,
20828
+ buildVerificationRequiredBody: () => buildVerificationRequiredBody,
20828
20829
  computeFirstCheckout: () => computeFirstCheckout,
20829
20830
  createDefaultOnDenied: () => createDefaultOnDenied,
20830
20831
  createQuoteCache: () => createQuoteCache,
@@ -21049,6 +21050,20 @@ var RESERVED_FIELDS = /* @__PURE__ */ new Set([
21049
21050
  "actual_signer",
21050
21051
  "linked_wallets"
21051
21052
  ]);
21053
+ function buildVerificationRequiredBody(reason, opts = {}) {
21054
+ const body = denialReasonToBody(reason);
21055
+ body.error = {
21056
+ code: "operator_verification_required",
21057
+ message: opts.message ?? "Identity verification is required."
21058
+ };
21059
+ if (opts.agentInstructions !== void 0) {
21060
+ body.agent_instructions = opts.agentInstructions;
21061
+ }
21062
+ if (opts.extra) {
21063
+ for (const [k, v] of Object.entries(opts.extra)) body[k] = v;
21064
+ }
21065
+ return body;
21066
+ }
21052
21067
  function denialReasonToBody(reason) {
21053
21068
  const message = reason.message ?? DEFAULT_MESSAGES[reason.code];
21054
21069
  const body = { error: { code: reason.code, message } };
@@ -21206,7 +21221,7 @@ function createAgentScoreCore(options) {
21206
21221
  } = options;
21207
21222
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21208
21223
  const agentMemoryHint = buildAgentMemoryHint();
21209
- const defaultUa = `@agent-score/commerce@${"2.1.0"}`;
21224
+ const defaultUa = `@agent-score/commerce@${"2.1.1"}`;
21210
21225
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21211
21226
  const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21212
21227
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21664,9 +21679,140 @@ var A2A_DEFAULT_TRANSPORT = DEFAULT_TRANSPORT;
21664
21679
  init_ucp();
21665
21680
  init_ucp_jwks();
21666
21681
 
21667
- // src/checkout.ts
21682
+ // src/errors.ts
21683
+ var CheckoutValidationError = class extends Error {
21684
+ code;
21685
+ action;
21686
+ status;
21687
+ extra;
21688
+ constructor(opts) {
21689
+ super(opts.message);
21690
+ this.name = "CheckoutValidationError";
21691
+ this.code = opts.code;
21692
+ this.action = opts.action ?? "fix_request";
21693
+ this.status = opts.status ?? 400;
21694
+ this.extra = opts.extra;
21695
+ }
21696
+ };
21697
+
21698
+ // src/identity/policy.ts
21699
+ function buildGateFromPolicy(policy, base) {
21700
+ if (!policy || !policy.enforcement) return null;
21701
+ return {
21702
+ apiKey: base.apiKey,
21703
+ ...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
21704
+ ...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
21705
+ ...policy.requireSanctionsClear !== void 0 && {
21706
+ requireSanctionsClear: policy.requireSanctionsClear
21707
+ },
21708
+ ...policy.minAge !== void 0 && { minAge: policy.minAge },
21709
+ ...policy.allowedJurisdictions !== void 0 && {
21710
+ allowedJurisdictions: [...policy.allowedJurisdictions]
21711
+ }
21712
+ };
21713
+ }
21714
+ async function runGateWithEnforcement(enforcement, runGate) {
21715
+ if (!runGate || !enforcement) return { status: "anonymous" };
21716
+ const outcome = await runGate();
21717
+ if (outcome.ok) return { status: "verified" };
21718
+ if (enforcement === "hard") {
21719
+ return {
21720
+ status: "denied",
21721
+ denialStatus: outcome.status,
21722
+ denialBody: outcome.body,
21723
+ ...outcome.reason !== void 0 && { denialReason: outcome.reason }
21724
+ };
21725
+ }
21726
+ return {
21727
+ status: "unverified",
21728
+ denialStatus: outcome.status,
21729
+ denialBody: outcome.body,
21730
+ ...outcome.reason !== void 0 && { denialReason: outcome.reason }
21731
+ };
21732
+ }
21733
+ function shippingCountryAllowed(country, policy) {
21734
+ if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
21735
+ const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
21736
+ return allowed.has(country.toUpperCase());
21737
+ }
21738
+ function shippingStateAllowed(state, country, policy) {
21739
+ if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
21740
+ if (country.toUpperCase() !== "US") return true;
21741
+ const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
21742
+ return allowed.has(state.toUpperCase());
21743
+ }
21744
+ function validateShippingAgainstPolicy(opts) {
21745
+ const code = opts.errorCode ?? "unsupported_jurisdiction";
21746
+ const action = opts.errorAction ?? "change_shipping_state";
21747
+ const item = opts.productName ? `'${opts.productName}'` : "this item";
21748
+ if (!shippingCountryAllowed(opts.country, opts.policy)) {
21749
+ throw new CheckoutValidationError({
21750
+ code,
21751
+ message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
21752
+ action
21753
+ });
21754
+ }
21755
+ if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
21756
+ throw new CheckoutValidationError({
21757
+ code,
21758
+ message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
21759
+ action
21760
+ });
21761
+ }
21762
+ }
21763
+
21764
+ // src/identity/tokens.ts
21668
21765
  var import_node_crypto = require("crypto");
21669
21766
 
21767
+ // src/payment/payment_header.ts
21768
+ function toTitleCase(name) {
21769
+ return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
21770
+ }
21771
+ function readHeader(headers, name) {
21772
+ if (typeof headers.get === "function") {
21773
+ return headers.get(name);
21774
+ }
21775
+ const rec = headers;
21776
+ const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
21777
+ if (typeof v === "string") return v;
21778
+ if (Array.isArray(v) && typeof v[0] === "string") return v[0];
21779
+ return null;
21780
+ }
21781
+ function asHeaders(input) {
21782
+ return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
21783
+ }
21784
+ function hasPaymentHeader(input) {
21785
+ const headers = asHeaders(input);
21786
+ return Boolean(
21787
+ readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
21788
+ );
21789
+ }
21790
+ function hasX402Header(input) {
21791
+ const headers = asHeaders(input);
21792
+ return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
21793
+ }
21794
+ function hasMppxHeader(input) {
21795
+ const headers = asHeaders(input);
21796
+ return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
21797
+ }
21798
+
21799
+ // src/identity/tokens.ts
21800
+ function hashOperatorToken(plaintext) {
21801
+ return (0, import_node_crypto.createHash)("sha256").update(plaintext, "utf8").digest("hex");
21802
+ }
21803
+ function extractOwnerScope(input) {
21804
+ const headers = asHeaders(input);
21805
+ const walletAddress = readHeader(headers, "x-wallet-address");
21806
+ const operatorToken = readHeader(headers, "x-operator-token");
21807
+ return {
21808
+ ...walletAddress ? { walletAddress } : {},
21809
+ ...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
21810
+ };
21811
+ }
21812
+
21813
+ // src/checkout.ts
21814
+ var import_node_crypto2 = require("crypto");
21815
+
21670
21816
  // src/_mppx_receipt.ts
21671
21817
  function extractMppxReceiptHeaderFromRaw(raw) {
21672
21818
  if (!raw || typeof raw !== "object" || !("withReceipt" in raw)) return null;
@@ -22073,6 +22219,12 @@ function buildValidationError({
22073
22219
  return body;
22074
22220
  }
22075
22221
 
22222
+ // src/payment/constants.ts
22223
+ var STRIPE_MIN_CHARGE_USD = 0.5;
22224
+
22225
+ // src/payment/mppx_server.ts
22226
+ var import_node_async_hooks = require("async_hooks");
22227
+
22076
22228
  // src/stripe-multichain/mppx_stripe.ts
22077
22229
  async function createMppxStripe({
22078
22230
  profileId,
@@ -22253,6 +22405,31 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
22253
22405
  }
22254
22406
  };
22255
22407
  }
22408
+ var mppxCapture = new import_node_async_hooks.AsyncLocalStorage();
22409
+ var consoleErrorPatched = false;
22410
+ function ensureConsoleErrorPatch() {
22411
+ if (consoleErrorPatched) return;
22412
+ consoleErrorPatched = true;
22413
+ const original = console.error.bind(console);
22414
+ console.error = function captureMppxInternal(...args) {
22415
+ if (args[0] === "mppx: internal verification error" && args[1] !== void 0) {
22416
+ const ctx = mppxCapture.getStore();
22417
+ if (ctx) {
22418
+ const e = args[1];
22419
+ const reason = typeof e?.shortMessage === "string" ? e.shortMessage : typeof e?.message === "string" ? e.message : String(args[1]);
22420
+ const details = e?.details;
22421
+ ctx.reason = typeof details === "string" && details.length > 0 ? `${reason} (${details})` : reason;
22422
+ }
22423
+ }
22424
+ return original(...args);
22425
+ };
22426
+ }
22427
+ async function runWithMppxFailureCapture(fn) {
22428
+ ensureConsoleErrorPatch();
22429
+ const ctx = { reason: null };
22430
+ const result = await mppxCapture.run(ctx, fn);
22431
+ return { result, failureReason: ctx.reason };
22432
+ }
22256
22433
 
22257
22434
  // src/payment/x402_server.ts
22258
22435
  init_networks();
@@ -22394,40 +22571,28 @@ function lazyMppxServer(opts) {
22394
22571
  };
22395
22572
  }
22396
22573
 
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);
22574
+ // src/payment/mppx_failures.ts
22575
+ var TEMPO_KEY_NOT_REGISTERED = {
22576
+ code: "tempo_key_not_registered",
22577
+ status: 401,
22578
+ message: "Tempo rejected the transaction: signer wallet is not registered with Tempo's keychain.",
22579
+ nextSteps: {
22580
+ action: "register_tempo_key",
22581
+ 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."
22582
+ },
22583
+ extra: { upstream_error: "KeyNotFound", chain: "tempo" }
22584
+ };
22585
+ function classifyMppxFailure(reason) {
22586
+ if (!reason) return null;
22587
+ const lower = reason.toLowerCase();
22588
+ if (lower.includes("keychain validation failed") || lower.includes("keynotfound")) {
22589
+ return TEMPO_KEY_NOT_REGISTERED;
22407
22590
  }
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
22591
  return null;
22413
22592
  }
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
- }
22593
+
22594
+ // src/checkout.ts
22595
+ init_network_kind();
22431
22596
 
22432
22597
  // src/payment/x402_settle.ts
22433
22598
  function classifyX402SettleResult(result) {
@@ -22750,20 +22915,6 @@ function getIdentityStatus(ctx) {
22750
22915
  if (decision === "allow") return "verified";
22751
22916
  return "unverified";
22752
22917
  }
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
22918
  function resolveIdentityMetadata(ctx) {
22768
22919
  const h = normalizeHeadersToLowercase(ctx.request.headers);
22769
22920
  const wallet = h["x-wallet-address"];
@@ -23100,7 +23251,14 @@ var Checkout = class {
23100
23251
  }
23101
23252
  }
23102
23253
  ctx.pricing = await this.computePricing(ctx);
23103
- await this.resolveRecipientsForCtx(ctx);
23254
+ try {
23255
+ await this.resolveRecipientsForCtx(ctx);
23256
+ } catch (err) {
23257
+ if (err instanceof Error && err.name === "CheckoutValidationError") {
23258
+ return this.validationErrorResult(ctx, err);
23259
+ }
23260
+ throw err;
23261
+ }
23104
23262
  const x402ServerOk = this.x402ServerAvailable() && this.x402BaseNetwork !== null;
23105
23263
  if (hasX402Header(request.headers) && x402ServerOk) {
23106
23264
  const zero = await this.handleZeroSettle(ctx, "x402-base");
@@ -23171,8 +23329,16 @@ var Checkout = class {
23171
23329
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23172
23330
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23173
23331
  ...gate.chain !== void 0 && { chain: gate.chain },
23174
- ...gate.createSessionOnMissing !== void 0 && {
23175
- createSessionOnMissing: gate.createSessionOnMissing
23332
+ // Auto-default `createSessionOnMissing` from gate config when the merchant
23333
+ // didn't supply one. Matches python-commerce's behavior — every gated route
23334
+ // gets the bootstrap session-mint UX out of the box. Merchants who need
23335
+ // custom session context or onBeforeSession side effects (goods merchants
23336
+ // pre-minting an order_id) supply their own config instead.
23337
+ createSessionOnMissing: gate.createSessionOnMissing ?? {
23338
+ apiKey: gate.apiKey,
23339
+ ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
23340
+ ...gate.context !== void 0 && { context: gate.context },
23341
+ ...gate.merchantName !== void 0 && { productName: gate.merchantName }
23176
23342
  },
23177
23343
  ...policyOverride ?? {}
23178
23344
  };
@@ -23269,7 +23435,7 @@ var Checkout = class {
23269
23435
  return await this.buildSuccess(ctx, outcome);
23270
23436
  }
23271
23437
  async mintRefId(request) {
23272
- if (this.mintReferenceId === void 0) return (0, import_node_crypto.randomUUID)();
23438
+ if (this.mintReferenceId === void 0) return (0, import_node_crypto2.randomUUID)();
23273
23439
  const seedCtx = { request, referenceId: "", pricing: null, recipients: {}, state: {} };
23274
23440
  return await this.mintReferenceId(seedCtx);
23275
23441
  }
@@ -23372,7 +23538,9 @@ var Checkout = class {
23372
23538
  if (this.composeMppx === void 0) {
23373
23539
  throw new Error("Checkout.handleMppx: composeMppx hook not configured");
23374
23540
  }
23375
- const composed = await this.composeMppx(ctx);
23541
+ const { result: composed, failureReason } = await runWithMppxFailureCapture(
23542
+ async () => this.composeMppx(ctx)
23543
+ );
23376
23544
  if (composed.status === 200) {
23377
23545
  const paymentReceiptHeader = composed.paymentReceiptHeader ?? extractMppxReceiptHeaderFromRaw(composed.raw);
23378
23546
  const directMethod = composed.raw?.receipt?.method;
@@ -23391,6 +23559,22 @@ var Checkout = class {
23391
23559
  };
23392
23560
  return await this.buildSuccess(ctx, outcome);
23393
23561
  }
23562
+ const classified = classifyMppxFailure(failureReason);
23563
+ if (classified !== null) {
23564
+ return {
23565
+ status: classified.status,
23566
+ body: buildValidationError({
23567
+ code: classified.code,
23568
+ message: classified.message,
23569
+ nextSteps: classified.nextSteps,
23570
+ ...classified.extra && { extra: classified.extra }
23571
+ }),
23572
+ headers: { ...composed.headers ?? {} },
23573
+ referenceId: ctx.referenceId,
23574
+ settled: false,
23575
+ settlePhase: "verify_failed"
23576
+ };
23577
+ }
23394
23578
  return {
23395
23579
  status: 400,
23396
23580
  body: buildValidationError({
@@ -23409,7 +23593,11 @@ var Checkout = class {
23409
23593
  throw new Error("Checkout.emit402: pricing not computed");
23410
23594
  }
23411
23595
  await this.resolveRecipientsForCtx(ctx);
23412
- const emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
23596
+ let emitRails = applyRecipientOverrides(this.rails, ctx.recipients);
23597
+ if (ctx.pricing.amountUsd < STRIPE_MIN_CHARGE_USD && emitRails.stripe !== void 0) {
23598
+ const { stripe: _stripe, ...rest } = emitRails;
23599
+ emitRails = rest;
23600
+ }
23413
23601
  const accepted = await buildAcceptedMethods({
23414
23602
  tempo: pickRail(emitRails, "tempo"),
23415
23603
  x402_base: pickRail(emitRails, "x402_base"),
@@ -23812,87 +24000,6 @@ Checkout.prototype.mountUcpRoutesFastify = function(app, opts) {
23812
24000
  app.options(jwksPath, preflight);
23813
24001
  };
23814
24002
 
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
24003
  // src/payment/index.ts
23897
24004
  init_directive();
23898
24005
  init_networks();
@@ -23969,6 +24076,7 @@ async function loadSolanaFeePayer(opts) {
23969
24076
 
23970
24077
  // src/payment/compose_rails.ts
23971
24078
  init_usdc();
24079
+ var warnedStripeBelowMinimum = false;
23972
24080
  function buildMppxComposeRails(opts) {
23973
24081
  const rails2 = [];
23974
24082
  if (opts.tempoRecipient) {
@@ -23990,7 +24098,17 @@ function buildMppxComposeRails(opts) {
23990
24098
  }]);
23991
24099
  }
23992
24100
  if (opts.includeStripe !== false) {
23993
- rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
24101
+ const amountUsdNumeric = Number(opts.amountUsd);
24102
+ if (Number.isFinite(amountUsdNumeric) && amountUsdNumeric < STRIPE_MIN_CHARGE_USD) {
24103
+ if (!warnedStripeBelowMinimum) {
24104
+ warnedStripeBelowMinimum = true;
24105
+ console.warn(
24106
+ `[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.`
24107
+ );
24108
+ }
24109
+ } else {
24110
+ rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
24111
+ }
23994
24112
  }
23995
24113
  return rails2;
23996
24114
  }
@@ -24181,10 +24299,11 @@ function computeFirstCheckout(opts) {
24181
24299
  const tempoRecipient = recipients.tempo;
24182
24300
  const x402BaseRecipient = recipients.x402_base;
24183
24301
  const solanaRecipient = recipients.solana_mpp;
24302
+ const includeStripeInDiscovery = opts.rails.stripe !== void 0 && Number(totalUsd) >= STRIPE_MIN_CHARGE_USD;
24184
24303
  const accepted = await buildAcceptedMethods({
24185
24304
  ...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
24186
24305
  ...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
24187
- ...opts.rails.stripe && { stripe: opts.rails.stripe }
24306
+ ...includeStripeInDiscovery && { stripe: opts.rails.stripe }
24188
24307
  });
24189
24308
  if (x402BaseRecipient && opts.rails.x402_base) {
24190
24309
  try {
@@ -24608,6 +24727,7 @@ function defaultReadOnlyOnDenied(reason) {
24608
24727
  buildMppxComposeRails,
24609
24728
  buildSignerMismatchBody,
24610
24729
  buildUCPProfile,
24730
+ buildVerificationRequiredBody,
24611
24731
  computeFirstCheckout,
24612
24732
  createDefaultOnDenied,
24613
24733
  createQuoteCache,