@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.mjs CHANGED
@@ -20990,6 +20990,20 @@ var RESERVED_FIELDS = /* @__PURE__ */ new Set([
20990
20990
  "actual_signer",
20991
20991
  "linked_wallets"
20992
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
+ }
20993
21007
  function denialReasonToBody(reason) {
20994
21008
  const message = reason.message ?? DEFAULT_MESSAGES[reason.code];
20995
21009
  const body = { error: { code: reason.code, message } };
@@ -21147,7 +21161,7 @@ function createAgentScoreCore(options) {
21147
21161
  } = options;
21148
21162
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21149
21163
  const agentMemoryHint = buildAgentMemoryHint();
21150
- const defaultUa = `@agent-score/commerce@${"2.1.0"}`;
21164
+ const defaultUa = `@agent-score/commerce@${"2.1.1"}`;
21151
21165
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21152
21166
  const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21153
21167
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21605,6 +21619,137 @@ var A2A_DEFAULT_TRANSPORT = DEFAULT_TRANSPORT;
21605
21619
  init_ucp();
21606
21620
  init_ucp_jwks();
21607
21621
 
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;
21635
+ }
21636
+ };
21637
+
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
+ };
21665
+ }
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
+
21608
21753
  // src/checkout.ts
21609
21754
  import { randomUUID } from "crypto";
21610
21755
 
@@ -22014,6 +22159,12 @@ function buildValidationError({
22014
22159
  return body;
22015
22160
  }
22016
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
+
22017
22168
  // src/stripe-multichain/mppx_stripe.ts
22018
22169
  async function createMppxStripe({
22019
22170
  profileId,
@@ -22194,6 +22345,31 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
22194
22345
  }
22195
22346
  };
22196
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
+ }
22197
22373
 
22198
22374
  // src/payment/x402_server.ts
22199
22375
  init_networks();
@@ -22335,40 +22511,28 @@ function lazyMppxServer(opts) {
22335
22511
  };
22336
22512
  }
22337
22513
 
22338
- // src/checkout.ts
22339
- init_network_kind();
22340
-
22341
- // src/payment/payment_header.ts
22342
- function toTitleCase(name) {
22343
- return name.replace(/(^|-)([a-z])/g, (_m, sep, c) => sep + c.toUpperCase());
22344
- }
22345
- function readHeader(headers, name) {
22346
- if (typeof headers.get === "function") {
22347
- return headers.get(name);
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;
22348
22530
  }
22349
- const rec = headers;
22350
- const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];
22351
- if (typeof v === "string") return v;
22352
- if (Array.isArray(v) && typeof v[0] === "string") return v[0];
22353
22531
  return null;
22354
22532
  }
22355
- function asHeaders(input) {
22356
- return typeof input.headers === "object" && input instanceof Request ? input.headers : input;
22357
- }
22358
- function hasPaymentHeader(input) {
22359
- const headers = asHeaders(input);
22360
- return Boolean(
22361
- readHeader(headers, "payment-signature") || readHeader(headers, "x-payment") || readHeader(headers, "authorization")?.startsWith("Payment ")
22362
- );
22363
- }
22364
- function hasX402Header(input) {
22365
- const headers = asHeaders(input);
22366
- return Boolean(readHeader(headers, "payment-signature") || readHeader(headers, "x-payment"));
22367
- }
22368
- function hasMppxHeader(input) {
22369
- const headers = asHeaders(input);
22370
- return Boolean(readHeader(headers, "authorization")?.startsWith("Payment "));
22371
- }
22533
+
22534
+ // src/checkout.ts
22535
+ init_network_kind();
22372
22536
 
22373
22537
  // src/payment/x402_settle.ts
22374
22538
  function classifyX402SettleResult(result) {
@@ -22691,20 +22855,6 @@ function getIdentityStatus(ctx) {
22691
22855
  if (decision === "allow") return "verified";
22692
22856
  return "unverified";
22693
22857
  }
22694
- var CheckoutValidationError = class extends Error {
22695
- code;
22696
- action;
22697
- status;
22698
- extra;
22699
- constructor(opts) {
22700
- super(opts.message);
22701
- this.name = "CheckoutValidationError";
22702
- this.code = opts.code;
22703
- this.action = opts.action ?? "fix_request";
22704
- this.status = opts.status ?? 400;
22705
- this.extra = opts.extra;
22706
- }
22707
- };
22708
22858
  function resolveIdentityMetadata(ctx) {
22709
22859
  const h = normalizeHeadersToLowercase(ctx.request.headers);
22710
22860
  const wallet = h["x-wallet-address"];
@@ -23041,7 +23191,14 @@ var Checkout = class {
23041
23191
  }
23042
23192
  }
23043
23193
  ctx.pricing = await this.computePricing(ctx);
23044
- 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
+ }
23045
23202
  const x402ServerOk = this.x402ServerAvailable() && this.x402BaseNetwork !== null;
23046
23203
  if (hasX402Header(request.headers) && x402ServerOk) {
23047
23204
  const zero = await this.handleZeroSettle(ctx, "x402-base");
@@ -23112,8 +23269,16 @@ var Checkout = class {
23112
23269
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23113
23270
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23114
23271
  ...gate.chain !== void 0 && { chain: gate.chain },
23115
- ...gate.createSessionOnMissing !== void 0 && {
23116
- 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 }
23117
23282
  },
23118
23283
  ...policyOverride ?? {}
23119
23284
  };
@@ -23313,7 +23478,9 @@ var Checkout = class {
23313
23478
  if (this.composeMppx === void 0) {
23314
23479
  throw new Error("Checkout.handleMppx: composeMppx hook not configured");
23315
23480
  }
23316
- const composed = await this.composeMppx(ctx);
23481
+ const { result: composed, failureReason } = await runWithMppxFailureCapture(
23482
+ async () => this.composeMppx(ctx)
23483
+ );
23317
23484
  if (composed.status === 200) {
23318
23485
  const paymentReceiptHeader = composed.paymentReceiptHeader ?? extractMppxReceiptHeaderFromRaw(composed.raw);
23319
23486
  const directMethod = composed.raw?.receipt?.method;
@@ -23332,6 +23499,22 @@ var Checkout = class {
23332
23499
  };
23333
23500
  return await this.buildSuccess(ctx, outcome);
23334
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
+ }
23335
23518
  return {
23336
23519
  status: 400,
23337
23520
  body: buildValidationError({
@@ -23350,7 +23533,11 @@ var Checkout = class {
23350
23533
  throw new Error("Checkout.emit402: pricing not computed");
23351
23534
  }
23352
23535
  await this.resolveRecipientsForCtx(ctx);
23353
- 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
+ }
23354
23541
  const accepted = await buildAcceptedMethods({
23355
23542
  tempo: pickRail(emitRails, "tempo"),
23356
23543
  x402_base: pickRail(emitRails, "x402_base"),
@@ -23753,87 +23940,6 @@ Checkout.prototype.mountUcpRoutesFastify = function(app, opts) {
23753
23940
  app.options(jwksPath, preflight);
23754
23941
  };
23755
23942
 
23756
- // src/identity/policy.ts
23757
- function buildGateFromPolicy(policy, base) {
23758
- if (!policy || !policy.enforcement) return null;
23759
- return {
23760
- apiKey: base.apiKey,
23761
- ...base.baseUrl !== void 0 && { baseUrl: base.baseUrl },
23762
- ...policy.requireKyc !== void 0 && { requireKyc: policy.requireKyc },
23763
- ...policy.requireSanctionsClear !== void 0 && {
23764
- requireSanctionsClear: policy.requireSanctionsClear
23765
- },
23766
- ...policy.minAge !== void 0 && { minAge: policy.minAge },
23767
- ...policy.allowedJurisdictions !== void 0 && {
23768
- allowedJurisdictions: [...policy.allowedJurisdictions]
23769
- }
23770
- };
23771
- }
23772
- async function runGateWithEnforcement(enforcement, runGate) {
23773
- if (!runGate || !enforcement) return { status: "anonymous" };
23774
- const outcome = await runGate();
23775
- if (outcome.ok) return { status: "verified" };
23776
- if (enforcement === "hard") {
23777
- return {
23778
- status: "denied",
23779
- denialStatus: outcome.status,
23780
- denialBody: outcome.body,
23781
- ...outcome.reason !== void 0 && { denialReason: outcome.reason }
23782
- };
23783
- }
23784
- return {
23785
- status: "unverified",
23786
- denialStatus: outcome.status,
23787
- denialBody: outcome.body,
23788
- ...outcome.reason !== void 0 && { denialReason: outcome.reason }
23789
- };
23790
- }
23791
- function shippingCountryAllowed(country, policy) {
23792
- if (!policy?.allowedShippingCountries || policy.allowedShippingCountries.length === 0) return true;
23793
- const allowed = new Set(policy.allowedShippingCountries.map((c) => c.toUpperCase()));
23794
- return allowed.has(country.toUpperCase());
23795
- }
23796
- function shippingStateAllowed(state, country, policy) {
23797
- if (!policy?.allowedShippingStates || policy.allowedShippingStates.length === 0) return true;
23798
- if (country.toUpperCase() !== "US") return true;
23799
- const allowed = new Set(policy.allowedShippingStates.map((s) => s.toUpperCase()));
23800
- return allowed.has(state.toUpperCase());
23801
- }
23802
- function validateShippingAgainstPolicy(opts) {
23803
- const code = opts.errorCode ?? "unsupported_jurisdiction";
23804
- const action = opts.errorAction ?? "change_shipping_state";
23805
- const item = opts.productName ? `'${opts.productName}'` : "this item";
23806
- if (!shippingCountryAllowed(opts.country, opts.policy)) {
23807
- throw new CheckoutValidationError({
23808
- code,
23809
- message: opts.countryMessage ?? `We can't ship ${item} to ${opts.country.toUpperCase() || "<unset>"}.`,
23810
- action
23811
- });
23812
- }
23813
- if (!shippingStateAllowed(opts.state, opts.country, opts.policy)) {
23814
- throw new CheckoutValidationError({
23815
- code,
23816
- message: opts.stateMessage ?? `We can't ship ${item} to ${opts.state.toUpperCase() || "<unset>"}.`,
23817
- action
23818
- });
23819
- }
23820
- }
23821
-
23822
- // src/identity/tokens.ts
23823
- import { createHash } from "crypto";
23824
- function hashOperatorToken(plaintext) {
23825
- return createHash("sha256").update(plaintext, "utf8").digest("hex");
23826
- }
23827
- function extractOwnerScope(input) {
23828
- const headers = asHeaders(input);
23829
- const walletAddress = readHeader(headers, "x-wallet-address");
23830
- const operatorToken = readHeader(headers, "x-operator-token");
23831
- return {
23832
- ...walletAddress ? { walletAddress } : {},
23833
- ...operatorToken ? { operatorTokenHash: hashOperatorToken(operatorToken) } : {}
23834
- };
23835
- }
23836
-
23837
23943
  // src/payment/index.ts
23838
23944
  init_directive();
23839
23945
  init_networks();
@@ -23910,6 +24016,7 @@ async function loadSolanaFeePayer(opts) {
23910
24016
 
23911
24017
  // src/payment/compose_rails.ts
23912
24018
  init_usdc();
24019
+ var warnedStripeBelowMinimum = false;
23913
24020
  function buildMppxComposeRails(opts) {
23914
24021
  const rails2 = [];
23915
24022
  if (opts.tempoRecipient) {
@@ -23931,7 +24038,17 @@ function buildMppxComposeRails(opts) {
23931
24038
  }]);
23932
24039
  }
23933
24040
  if (opts.includeStripe !== false) {
23934
- rails2.push(["stripe/charge", { amount: opts.amountUsd, currency: "usd", decimals: 2 }]);
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
+ }
23935
24052
  }
23936
24053
  return rails2;
23937
24054
  }
@@ -24122,10 +24239,11 @@ function computeFirstCheckout(opts) {
24122
24239
  const tempoRecipient = recipients.tempo;
24123
24240
  const x402BaseRecipient = recipients.x402_base;
24124
24241
  const solanaRecipient = recipients.solana_mpp;
24242
+ const includeStripeInDiscovery = opts.rails.stripe !== void 0 && Number(totalUsd) >= STRIPE_MIN_CHARGE_USD;
24125
24243
  const accepted = await buildAcceptedMethods({
24126
24244
  ...tempoRecipient && opts.rails.tempo && { tempo: { ...opts.rails.tempo, recipient: tempoRecipient } },
24127
24245
  ...solanaRecipient && opts.rails.solana_mpp && { solana_mpp: { ...opts.rails.solana_mpp, recipient: solanaRecipient } },
24128
- ...opts.rails.stripe && { stripe: opts.rails.stripe }
24246
+ ...includeStripeInDiscovery && { stripe: opts.rails.stripe }
24129
24247
  });
24130
24248
  if (x402BaseRecipient && opts.rails.x402_base) {
24131
24249
  try {
@@ -24548,6 +24666,7 @@ export {
24548
24666
  buildMppxComposeRails,
24549
24667
  buildSignerMismatchBody,
24550
24668
  buildUCPProfile,
24669
+ buildVerificationRequiredBody,
24551
24670
  computeFirstCheckout,
24552
24671
  createDefaultOnDenied,
24553
24672
  createQuoteCache,