@agent-score/commerce 2.1.1 → 2.3.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 (66) hide show
  1. package/README.md +2 -2
  2. package/dist/challenge/index.d.mts +3 -3
  3. package/dist/challenge/index.d.ts +3 -3
  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-BRw_caGr.d.mts → checkout-Ceo1_rVJ.d.mts} +38 -2
  9. package/dist/{checkout-CuSNUJFX.d.ts → checkout-ChyOi7aU.d.ts} +38 -2
  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-C5gKZJMI.d.ts → default_rails-DtR_E9N9.d.ts} +1 -1
  15. package/dist/{default_rails-XFCuRddA.d.mts → default_rails-K25PtWrL.d.mts} +1 -1
  16. package/dist/discovery/index.d.mts +4 -4
  17. package/dist/discovery/index.d.ts +4 -4
  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/web.js +4 -3
  41. package/dist/identity/web.js.map +1 -1
  42. package/dist/identity/web.mjs +4 -3
  43. package/dist/identity/web.mjs.map +1 -1
  44. package/dist/index.d.mts +7 -7
  45. package/dist/index.d.ts +7 -7
  46. package/dist/index.js +139 -13
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +139 -13
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/payment/index.d.mts +3 -3
  51. package/dist/payment/index.d.ts +3 -3
  52. package/dist/payment/index.js +2 -0
  53. package/dist/payment/index.js.map +1 -1
  54. package/dist/payment/index.mjs +2 -0
  55. package/dist/payment/index.mjs.map +1 -1
  56. package/dist/{pricing-DHfH3ogG.d.ts → pricing-B3-aKxSz.d.ts} +5 -3
  57. package/dist/{pricing-4n5Ota0D.d.mts → pricing-BReyZiqN.d.mts} +5 -3
  58. package/dist/{rail_spec-D6qzh3J0.d.mts → rail_spec-B1239jPp.d.mts} +25 -0
  59. package/dist/{rail_spec-D6qzh3J0.d.ts → rail_spec-B1239jPp.d.ts} +25 -0
  60. package/dist/stripe-multichain/index.d.mts +61 -11
  61. package/dist/stripe-multichain/index.d.ts +61 -11
  62. package/dist/stripe-multichain/index.js +84 -43
  63. package/dist/stripe-multichain/index.js.map +1 -1
  64. package/dist/stripe-multichain/index.mjs +83 -43
  65. package/dist/stripe-multichain/index.mjs.map +1 -1
  66. package/package.json +9 -9
package/dist/index.mjs CHANGED
@@ -20059,11 +20059,12 @@ function toClient(method, options) {
20059
20059
  };
20060
20060
  }
20061
20061
  function toServer(method, options) {
20062
- const { authorize, defaults, html, request, respond, stableBinding, transport, verify: verify3 } = options;
20062
+ const { authorize, defaults, extensions, html, request, respond, stableBinding, transport, verify: verify3 } = options;
20063
20063
  return {
20064
20064
  ...method,
20065
20065
  authorize,
20066
20066
  defaults,
20067
+ extensions,
20067
20068
  html,
20068
20069
  request,
20069
20070
  respond,
@@ -21161,7 +21162,7 @@ function createAgentScoreCore(options) {
21161
21162
  } = options;
21162
21163
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21163
21164
  const agentMemoryHint = buildAgentMemoryHint();
21164
- const defaultUa = `@agent-score/commerce@${"2.1.1"}`;
21165
+ const defaultUa = `@agent-score/commerce@${"2.3.0"}`;
21165
21166
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21166
21167
  const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21167
21168
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21298,8 +21299,9 @@ function createAgentScoreCore(options) {
21298
21299
  ...Object.keys(policy).length > 0 ? { policy } : {},
21299
21300
  // Pre-extracted payment signer (by the adapter middleware). When present, the API
21300
21301
  // composes BOTH signer_match (wallet-binding) and signer_sanctions (OFAC SDN wallet
21301
- // check) verdicts on the response in one round trip. Under
21302
- // policy.require_sanctions_clear, a signer_sanctions hit flips decision -> deny inline.
21302
+ // check) verdicts on the response in one round trip. Wallet-OFAC enforcement on the
21303
+ // signer block is unconditional — a signer_sanctions hit flips decision -> deny
21304
+ // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
21303
21305
  ...signer && { signer: { address: signer.address, network: signer.network } }
21304
21306
  };
21305
21307
  const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
@@ -21781,6 +21783,16 @@ async function deriveMppxReceiptMethod(raw) {
21781
21783
  return extractMppxReceiptMethod(header);
21782
21784
  }
21783
21785
 
21786
+ // src/_warnings.ts
21787
+ var warnedNoApiKey = false;
21788
+ function warnMissingApiKeyOnce(label) {
21789
+ if (warnedNoApiKey) return;
21790
+ warnedNoApiKey = true;
21791
+ console.warn(
21792
+ `[${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.`
21793
+ );
21794
+ }
21795
+
21784
21796
  // src/payment/rail_spec.ts
21785
21797
  init_usdc();
21786
21798
  async function resolveRecipient(r) {
@@ -22012,14 +22024,16 @@ function buildHowToPay({
22012
22024
  const d = decimals ?? 2;
22013
22025
  const defaultMaxSpend = totalNum >= 1 ? (Math.ceil(totalNum) + 1).toFixed(d) : totalNum.toFixed(d);
22014
22026
  const maxSpendStr = String(maxSpend ?? defaultMaxSpend);
22027
+ const gateless = opTokenPlaceholder === null;
22015
22028
  const opToken = opTokenPlaceholder ?? "<your_opc_token>";
22029
+ const opTokenHeaderFlag = gateless ? "" : `-H 'X-Operator-Token: ${opToken}' `;
22016
22030
  const block = {};
22017
22031
  if (rails2.tempo) {
22018
22032
  const networkName = rails2.tempo.testnet ? "tempo-testnet" : rails2.tempo.network ?? RAIL_SPEC_DEFAULTS.tempo.network;
22019
22033
  const chainId = rails2.tempo.chainId ?? RAIL_SPEC_DEFAULTS.tempo.chainId;
22020
22034
  const recommend = rails2.tempo.recommend ?? RAIL_SPEC_DEFAULTS.tempo.recommend;
22021
- const tempoCommand = `tempo request -X POST -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' --json '${retryBodyJson}' --max-spend ${maxSpendStr} ${url2}`;
22022
- const payCommand = `agentscore-pay pay POST ${url2} --chain tempo -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`;
22035
+ const tempoCommand = `tempo request -X POST ${opTokenHeaderFlag}-H 'Content-Type: application/json' --json '${retryBodyJson}' --max-spend ${maxSpendStr} ${url2}`;
22036
+ const payCommand = `agentscore-pay pay POST ${url2} --chain tempo ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`;
22023
22037
  block.tempo = {
22024
22038
  setup: TEMPO_SETUP,
22025
22039
  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.`,
@@ -22033,7 +22047,7 @@ function buildHowToPay({
22033
22047
  block.x402_base = {
22034
22048
  setup: PAY_SETUP_BASE,
22035
22049
  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.`,
22036
- command: `agentscore-pay pay POST ${url2} --chain base -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
22050
+ command: `agentscore-pay pay POST ${url2} --chain base ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
22037
22051
  what_it_does: "Pays via USDC on Base."
22038
22052
  };
22039
22053
  }
@@ -22042,7 +22056,7 @@ function buildHowToPay({
22042
22056
  block.solana_mpp = {
22043
22057
  setup: PAY_SETUP_SOLANA,
22044
22058
  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.`,
22045
- command: `agentscore-pay pay POST ${url2} --chain solana -H 'X-Operator-Token: ${opToken}' -H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
22059
+ command: `agentscore-pay pay POST ${url2} --chain solana ${opTokenHeaderFlag}-H 'Content-Type: application/json' -d '${retryBodyJson}' --max-spend ${maxSpendStr}`,
22046
22060
  what_it_does: "Pays via USDC on Solana."
22047
22061
  };
22048
22062
  }
@@ -22064,7 +22078,7 @@ function buildHowToPay({
22064
22078
  ];
22065
22079
  stripe.command_link_cli = [
22066
22080
  `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)`,
22067
- `link-cli mpp pay ${url2} --spend-request-id $SPEND_ID --method POST --data '${retryBodyJson}' --header 'X-Operator-Token: ${opToken}' --output-json`
22081
+ 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`
22068
22082
  ];
22069
22083
  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.";
22070
22084
  } else if (linkCliBlocked) {
@@ -22284,11 +22298,13 @@ async function registerSolana(spec) {
22284
22298
  "createMppxServer: SolanaMppRailSpec requires a string recipient (per-order factories not supported here)."
22285
22299
  );
22286
22300
  }
22301
+ const ataCreationRequired = spec.ataCreationRequired !== false;
22287
22302
  const baseMethod = solanaMpp.charge({
22288
22303
  recipient: spec.recipient,
22289
22304
  currency: spec.token ?? defaultMint,
22290
22305
  decimals: spec.decimals ?? defaultDecimals,
22291
22306
  network,
22307
+ ...ataCreationRequired ? { splits: [{ recipient: spec.recipient, amount: "0", ataCreationRequired: true }] } : {},
22292
22308
  ...spec.rpcUrl ? { rpcUrl: spec.rpcUrl } : {},
22293
22309
  ...spec.signer ? { signer: spec.signer } : {},
22294
22310
  ...spec.tokenProgram ? { tokenProgram: spec.tokenProgram } : {}
@@ -22981,6 +22997,23 @@ var Checkout = class {
22981
22997
  discoveryExtensions;
22982
22998
  discoveryProbe;
22983
22999
  _x402ServerGetter;
23000
+ /**
23001
+ * True when the merchant has configured an identity-bearing policy flag —
23002
+ * `require_kyc`, `require_sanctions_clear` (name screening on the KYC
23003
+ * identity), `min_age`, or jurisdiction lists. Wallet OFAC SDN enforcement
23004
+ * (the always-on default) does NOT count as an identity gate; agents don't
23005
+ * need an AgentScore credential to satisfy it.
23006
+ *
23007
+ * Used to conditionally emit AgentScore identity boilerplate in 402 bodies
23008
+ * (`agent_memory`, `X-Operator-Token` references in per-rail commands).
23009
+ */
23010
+ hasIdentityGate() {
23011
+ const g = this.gate;
23012
+ if (!g) return false;
23013
+ return Boolean(
23014
+ g.requireKyc || g.requireSanctionsClear || g.minAge !== void 0 || g.allowedJurisdictions && g.allowedJurisdictions.length > 0 || g.blockedJurisdictions && g.blockedJurisdictions.length > 0
23015
+ );
23016
+ }
22984
23017
  constructor(opts) {
22985
23018
  const x402Server = opts.x402Server;
22986
23019
  let x402ServerGetter;
@@ -23178,8 +23211,8 @@ var Checkout = class {
23178
23211
  }
23179
23212
  }
23180
23213
  const hasPaymentHeader2 = hasX402Header(request.headers) || hasMppxHeader(request.headers);
23181
- if (this.gate !== void 0 && hasPaymentHeader2) {
23182
- const denial = await this.runGate(ctx);
23214
+ if (hasPaymentHeader2) {
23215
+ const denial = this.gate !== void 0 ? await this.runGate(ctx) : await this.runWalletSanctionsOnly(ctx);
23183
23216
  if (denial !== null) {
23184
23217
  return {
23185
23218
  status: denial.status,
@@ -23251,7 +23284,9 @@ var Checkout = class {
23251
23284
  }
23252
23285
  return result;
23253
23286
  }
23254
- if (gate.apiKey === void 0) return null;
23287
+ if (gate.apiKey === void 0) {
23288
+ return this.runWalletSanctionsOnly(ctx);
23289
+ }
23255
23290
  let policyOverride;
23256
23291
  if (gate.perRequestPolicy !== void 0) {
23257
23292
  policyOverride = await gate.perRequestPolicy(ctx);
@@ -23341,6 +23376,58 @@ var Checkout = class {
23341
23376
  const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
23342
23377
  return { status, body };
23343
23378
  }
23379
+ /**
23380
+ * Wallet OFAC SDN enforcement.
23381
+ *
23382
+ * Runs on settle (payment header present) when either `this.gate` is
23383
+ * undefined OR a gate is configured but has no `apiKey` to reach
23384
+ * `/v1/assess` for full policy enforcement (fallback to the
23385
+ * strict-liability default).
23386
+ *
23387
+ * Env knobs:
23388
+ * - `AGENTSCORE_API_KEY` — required. No key → one-time warning + skip
23389
+ * (dev/testnet pattern; production should always configure a key).
23390
+ * - `AGENTSCORE_BASE_URL` — optional override for staging/dev API
23391
+ * (e.g. `https://api-dev.agentscore.sh` or `http://localhost:3002`).
23392
+ *
23393
+ * Stripe SPT (no extractable wallet signer) → skip silently; Stripe runs
23394
+ * its own OFAC screen on the buyer's Stripe account at customer creation.
23395
+ *
23396
+ * Calls `/v1/assess` with the signer wallet as both the primary address
23397
+ * and the signer block. The API enforces signer-sanctions unconditionally
23398
+ * when a signer is present (no policy flag needed). Denies on OFAC SDN
23399
+ * hit; fail-closed on unavailable lookup (strict liability — falsely
23400
+ * allowing a sanctioned settle is an OFAC violation, falsely denying a
23401
+ * clean buyer is just bad UX).
23402
+ */
23403
+ async runWalletSanctionsOnly(ctx) {
23404
+ const apiKey = process.env.AGENTSCORE_API_KEY;
23405
+ if (!apiKey) {
23406
+ warnMissingApiKeyOnce("checkout");
23407
+ return null;
23408
+ }
23409
+ const headers = normalizeHeadersToLowercase(ctx.request.headers);
23410
+ const x402Header = headers["payment-signature"] ?? headers["x-payment"];
23411
+ const signer = await extractPaymentSignerFromAuth(headers["authorization"], x402Header);
23412
+ if (!signer) {
23413
+ return null;
23414
+ }
23415
+ const baseUrl = process.env.AGENTSCORE_BASE_URL;
23416
+ const core = createAgentScoreCore({
23417
+ apiKey,
23418
+ ...baseUrl !== void 0 && { baseUrl }
23419
+ });
23420
+ const outcome = await core.evaluate(
23421
+ { address: signer.address },
23422
+ ctx,
23423
+ signer
23424
+ );
23425
+ if (outcome.kind === "allow") return null;
23426
+ const reason = outcome.reason;
23427
+ const body = denialReasonToBody(reason);
23428
+ const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
23429
+ return { status, body };
23430
+ }
23344
23431
  async handleZeroSettle(ctx, rail) {
23345
23432
  if (!this.zeroSettleCarveOut || ctx.pricing === null) return null;
23346
23433
  const cents = Math.round(ctx.pricing.amountUsd * 100);
@@ -23556,6 +23643,10 @@ var Checkout = class {
23556
23643
  retryBodyJson: JSON.stringify(ctx.request.body),
23557
23644
  totalUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
23558
23645
  rails: howToPayRails,
23646
+ // Merchants without an identity-bearing policy flag get clean commands
23647
+ // without an X-Operator-Token header — agents don't need one to satisfy
23648
+ // wallet OFAC enforcement (the always-on default).
23649
+ ...this.hasIdentityGate() ? {} : { opTokenPlaceholder: null },
23559
23650
  ...ctx.pricing.decimals !== void 0 && { decimals: ctx.pricing.decimals }
23560
23651
  });
23561
23652
  const pricingBlock = ctx.pricing.block ?? buildPricingBlock({
@@ -23592,7 +23683,10 @@ var Checkout = class {
23592
23683
  pricing: pricingBlock,
23593
23684
  amountUsd: ctx.pricing.amountUsd.toFixed(pricingDecimals),
23594
23685
  retryBody: ctx.request.body,
23595
- agentMemory: firstEncounterAgentMemory({ firstEncounter: true }),
23686
+ // Merchants without an identity-bearing gate get a clean 402: no
23687
+ // AgentScore-identity bootstrap describing a verification flow they
23688
+ // don't run. Wallet OFAC (the always-on default) doesn't need it.
23689
+ agentMemory: firstEncounterAgentMemory({ firstEncounter: this.hasIdentityGate() }),
23596
23690
  ...ctx.pricing.product ? { product: ctx.pricing.product } : {},
23597
23691
  ...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
23598
23692
  ...x402Accepts.length > 0 ? {
@@ -24320,6 +24414,36 @@ function computeFirstCheckout(opts) {
24320
24414
  );
24321
24415
  return new Response(JSON.stringify(body402), { status: 402, headers });
24322
24416
  }
24417
+ async function enforceWalletSanctions(req, referenceId) {
24418
+ const apiKey = process.env.AGENTSCORE_API_KEY;
24419
+ if (!apiKey) {
24420
+ warnMissingApiKeyOnce(`${opts.name}.computeFirst`);
24421
+ return null;
24422
+ }
24423
+ const x402Header = readX402PaymentHeader(req);
24424
+ const signer = await extractPaymentSigner(req, x402Header);
24425
+ if (!signer) return null;
24426
+ const baseUrl = process.env.AGENTSCORE_BASE_URL;
24427
+ const core = createAgentScoreCore({
24428
+ apiKey,
24429
+ ...baseUrl !== void 0 && { baseUrl }
24430
+ });
24431
+ const outcome = await core.evaluate({ address: signer.address }, void 0, signer);
24432
+ if (outcome.kind === "allow") return null;
24433
+ const reason = outcome.reason;
24434
+ const body = denialReasonToBody(reason);
24435
+ const status = reason.code === "token_expired" || reason.code === "invalid_credential" ? 401 : reason.code === "api_error" ? 503 : 403;
24436
+ return new Response(
24437
+ JSON.stringify({
24438
+ id: referenceId,
24439
+ endpoint: opts.name,
24440
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
24441
+ payment_status: "failed",
24442
+ ...body
24443
+ }),
24444
+ { status, headers: { "Content-Type": "application/json" } }
24445
+ );
24446
+ }
24323
24447
  async function handleX402Settle(req, referenceId, cachedBody, priceCents, recipients) {
24324
24448
  const verified = await verifyX402Request({
24325
24449
  request: req,
@@ -24518,6 +24642,8 @@ function computeFirstCheckout(opts) {
24518
24642
  { status: 400, headers: { "Content-Type": "application/json" } }
24519
24643
  );
24520
24644
  }
24645
+ const ofacDenial = await enforceWalletSanctions(req, referenceId);
24646
+ if (ofacDenial !== null) return ofacDenial;
24521
24647
  if (hasX402Header(req.headers)) return handleX402Settle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
24522
24648
  return handleMppSettle(req, referenceId, quote2.body, quote2.priceCents, quote2.recipients);
24523
24649
  }