@agent-score/commerce 2.3.0 → 2.5.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 (80) hide show
  1. package/README.md +6 -6
  2. package/dist/challenge/index.d.mts +9 -5
  3. package/dist/challenge/index.d.ts +9 -5
  4. package/dist/challenge/index.js +11 -4
  5. package/dist/challenge/index.js.map +1 -1
  6. package/dist/challenge/index.mjs +11 -4
  7. package/dist/challenge/index.mjs.map +1 -1
  8. package/dist/{checkout-ChyOi7aU.d.ts → checkout-McfNpZJf.d.ts} +80 -12
  9. package/dist/{checkout-Ceo1_rVJ.d.mts → checkout-o17dIxHi.d.mts} +80 -12
  10. package/dist/core.d.mts +27 -7
  11. package/dist/core.d.ts +27 -7
  12. package/dist/core.js +25 -11
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +25 -11
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/discovery/index.d.mts +26 -10
  17. package/dist/discovery/index.d.ts +26 -10
  18. package/dist/discovery/index.js +58 -10
  19. package/dist/discovery/index.js.map +1 -1
  20. package/dist/discovery/index.mjs +58 -10
  21. package/dist/discovery/index.mjs.map +1 -1
  22. package/dist/gate-CWP10xPQ.d.mts +339 -0
  23. package/dist/gate-CWP10xPQ.d.ts +339 -0
  24. package/dist/identity/express.d.mts +26 -1
  25. package/dist/identity/express.d.ts +26 -1
  26. package/dist/identity/express.js +599 -25
  27. package/dist/identity/express.js.map +1 -1
  28. package/dist/identity/express.mjs +595 -24
  29. package/dist/identity/express.mjs.map +1 -1
  30. package/dist/identity/fastify.d.mts +12 -2
  31. package/dist/identity/fastify.d.ts +12 -2
  32. package/dist/identity/fastify.js +607 -25
  33. package/dist/identity/fastify.js.map +1 -1
  34. package/dist/identity/fastify.mjs +603 -24
  35. package/dist/identity/fastify.mjs.map +1 -1
  36. package/dist/identity/hono.d.mts +26 -1
  37. package/dist/identity/hono.d.ts +26 -1
  38. package/dist/identity/hono.js +588 -25
  39. package/dist/identity/hono.js.map +1 -1
  40. package/dist/identity/hono.mjs +584 -24
  41. package/dist/identity/hono.mjs.map +1 -1
  42. package/dist/identity/nextjs.d.mts +3 -0
  43. package/dist/identity/nextjs.d.ts +3 -0
  44. package/dist/identity/nextjs.js +593 -25
  45. package/dist/identity/nextjs.js.map +1 -1
  46. package/dist/identity/nextjs.mjs +589 -24
  47. package/dist/identity/nextjs.mjs.map +1 -1
  48. package/dist/identity/policy.js.map +1 -1
  49. package/dist/identity/policy.mjs.map +1 -1
  50. package/dist/identity/web.d.mts +24 -1
  51. package/dist/identity/web.d.ts +24 -1
  52. package/dist/identity/web.js +593 -25
  53. package/dist/identity/web.js.map +1 -1
  54. package/dist/identity/web.mjs +589 -24
  55. package/dist/identity/web.mjs.map +1 -1
  56. package/dist/index.d.mts +129 -14
  57. package/dist/index.d.ts +129 -14
  58. package/dist/index.js +978 -99
  59. package/dist/index.js.map +1 -1
  60. package/dist/index.mjs +956 -99
  61. package/dist/index.mjs.map +1 -1
  62. package/dist/{default_rails-DtR_E9N9.d.ts → network_kind-BIJM2peR.d.ts} +22 -8
  63. package/dist/{default_rails-K25PtWrL.d.mts → network_kind-C0EMkdzz.d.mts} +22 -8
  64. package/dist/payment/index.d.mts +16 -26
  65. package/dist/payment/index.d.ts +16 -26
  66. package/dist/payment/index.js +62 -57
  67. package/dist/payment/index.js.map +1 -1
  68. package/dist/payment/index.mjs +62 -57
  69. package/dist/payment/index.mjs.map +1 -1
  70. package/dist/{pricing-B3-aKxSz.d.ts → pricing-CytRwhC2.d.ts} +1 -1
  71. package/dist/{pricing-BReyZiqN.d.mts → pricing-KHDqMLd7.d.mts} +1 -1
  72. package/dist/{rail_spec-B1239jPp.d.mts → rail_spec-BFZmW9RN.d.mts} +3 -4
  73. package/dist/{rail_spec-B1239jPp.d.ts → rail_spec-BFZmW9RN.d.ts} +3 -4
  74. package/dist/stripe-multichain/index.d.mts +2 -9
  75. package/dist/stripe-multichain/index.d.ts +2 -9
  76. package/dist/stripe-multichain/index.js.map +1 -1
  77. package/dist/stripe-multichain/index.mjs.map +1 -1
  78. package/dist/{wwwauthenticate-D_FMnPgU.d.mts → wwwauthenticate-CVaGUMjU.d.mts} +8 -6
  79. package/dist/{wwwauthenticate-D_FMnPgU.d.ts → wwwauthenticate-CVaGUMjU.d.ts} +8 -6
  80. package/package.json +14 -13
package/dist/index.js CHANGED
@@ -331,19 +331,19 @@ function stableStringify(value) {
331
331
  }
332
332
  if (!Number.isInteger(value)) {
333
333
  throw new Error(
334
- `UCP profile canonicalization rejects non-integer Number ${value}. Use a decimal string (e.g. "9.99") for monetary or fractional fields to preserve cross-language byte-parity.`
334
+ `UCP profile canonicalization rejects non-integer Number ${value}. Use a decimal string (e.g. "9.99") for monetary or fractional fields so the signed canonical bytes stay stable for any verifier.`
335
335
  );
336
336
  }
337
337
  if (!Number.isSafeInteger(value)) {
338
338
  throw new Error(
339
- `stableStringify: integer ${value} exceeds Number.MAX_SAFE_INTEGER. For values >2^53, use a decimal string to preserve cross-language byte parity.`
339
+ `stableStringify: integer ${value} exceeds Number.MAX_SAFE_INTEGER. For values >2^53, use a decimal string to keep the signed bytes stable across implementations.`
340
340
  );
341
341
  }
342
342
  }
343
343
  if (typeof value === "string") {
344
344
  if (value.includes("\u2028") || value.includes("\u2029")) {
345
345
  throw new Error(
346
- "stableStringify: strings containing U+2028 (LINE SEPARATOR) or U+2029 (PARAGRAPH SEPARATOR) are not allowed; cross-language byte parity requires neither be present (Node JSON.stringify on older V8 escapes them; Python json.dumps with ensure_ascii=False does not)."
346
+ "stableStringify: strings containing U+2028 (LINE SEPARATOR) or U+2029 (PARAGRAPH SEPARATOR) are not allowed; stable canonical bytes require neither be present (some JSON encoders escape them, others emit them raw)."
347
347
  );
348
348
  }
349
349
  return JSON.stringify(value);
@@ -363,7 +363,7 @@ function stableStringify(value) {
363
363
  for (const k of keys) {
364
364
  if (k.includes("\u2028") || k.includes("\u2029")) {
365
365
  throw new Error(
366
- "stableStringify: object keys containing U+2028 (LINE SEPARATOR) or U+2029 (PARAGRAPH SEPARATOR) are not allowed; cross-language byte parity (Node JSON.stringify on older V8 escapes them; Python json.dumps with ensure_ascii=False does not)."
366
+ "stableStringify: object keys containing U+2028 (LINE SEPARATOR) or U+2029 (PARAGRAPH SEPARATOR) are not allowed; stable canonical bytes require neither be present (some JSON encoders escape them, others emit them raw)."
367
367
  );
368
368
  }
369
369
  }
@@ -583,12 +583,12 @@ async function buildEnvSigningKey(opts) {
583
583
  );
584
584
  }
585
585
  const canonicalPrivateJwk = detectedAlg === "EdDSA" ? { kty: jwkDict.kty, crv: jwkDict.crv, x: jwkDict.x, d: jwkDict.d } : { kty: jwkDict.kty, crv: jwkDict.crv, x: jwkDict.x, y: jwkDict.y, d: jwkDict.d };
586
- const { importJWK } = await import("jose");
586
+ const { importJWK: importJWK3 } = await import("jose");
587
587
  const { createPublicKey } = await import("crypto");
588
588
  let privateKey;
589
589
  let publicNodeKey;
590
590
  try {
591
- privateKey = await importJWK(
591
+ privateKey = await importJWK3(
592
592
  canonicalPrivateJwk,
593
593
  detectedAlg
594
594
  );
@@ -7951,13 +7951,13 @@ var init_schemas = __esm({
7951
7951
  }
7952
7952
  return propValues;
7953
7953
  });
7954
- const isObject2 = isObject;
7954
+ const isObject3 = isObject;
7955
7955
  const catchall2 = def.catchall;
7956
7956
  let value;
7957
7957
  inst._zod.parse = (payload, ctx) => {
7958
7958
  value ?? (value = _normalized.value);
7959
7959
  const input = payload.value;
7960
- if (!isObject2(input)) {
7960
+ if (!isObject3(input)) {
7961
7961
  payload.issues.push({
7962
7962
  expected: "object",
7963
7963
  code: "invalid_type",
@@ -8084,7 +8084,7 @@ var init_schemas = __esm({
8084
8084
  return (payload, ctx) => fn(shape, payload, ctx);
8085
8085
  };
8086
8086
  let fastpass;
8087
- const isObject2 = isObject;
8087
+ const isObject3 = isObject;
8088
8088
  const jit = !globalConfig.jitless;
8089
8089
  const allowsEval2 = allowsEval;
8090
8090
  const fastEnabled = jit && allowsEval2.value;
@@ -8093,7 +8093,7 @@ var init_schemas = __esm({
8093
8093
  inst._zod.parse = (payload, ctx) => {
8094
8094
  value ?? (value = _normalized.value);
8095
8095
  const input = payload.value;
8096
- if (!isObject2(input)) {
8096
+ if (!isObject3(input)) {
8097
8097
  payload.issues.push({
8098
8098
  expected: "object",
8099
8099
  code: "invalid_type",
@@ -20330,6 +20330,53 @@ var init_networks = __esm({
20330
20330
  }
20331
20331
  });
20332
20332
 
20333
+ // src/payment/amounts.ts
20334
+ function usdToAtomic(usd, opts) {
20335
+ const { decimals } = opts;
20336
+ if (!Number.isInteger(decimals) || decimals < 0) {
20337
+ throw new RangeError(`decimals must be a non-negative integer, got ${decimals}`);
20338
+ }
20339
+ if (typeof usd === "number") {
20340
+ if (!Number.isFinite(usd)) {
20341
+ throw new RangeError(`usd must be finite, got ${usd}`);
20342
+ }
20343
+ if (usd < 0) {
20344
+ throw new RangeError(`usd must be non-negative, got ${usd}`);
20345
+ }
20346
+ }
20347
+ const s = (typeof usd === "number" ? usd.toString() : usd).trim();
20348
+ if (s.startsWith("-")) {
20349
+ throw new RangeError(`usd must be non-negative, got ${s}`);
20350
+ }
20351
+ if (s === "NaN" || s === "Infinity") {
20352
+ throw new RangeError(`usd must be finite, got ${s}`);
20353
+ }
20354
+ const match = /^(\d*)(?:\.(\d*))?$/.exec(s);
20355
+ if (!match || match[1] === "" && (match[2] === void 0 || match[2] === "")) {
20356
+ throw new SyntaxError(`invalid usd value: ${JSON.stringify(usd)}`);
20357
+ }
20358
+ const intPart = match[1] || "0";
20359
+ const fracPart = match[2] ?? "";
20360
+ if (fracPart.length <= decimals) {
20361
+ return BigInt(intPart + fracPart.padEnd(decimals, "0"));
20362
+ }
20363
+ const kept = fracPart.slice(0, decimals);
20364
+ const roundDigit = fracPart[decimals];
20365
+ let result = BigInt(intPart + kept);
20366
+ if (roundDigit >= "5") {
20367
+ result += 1n;
20368
+ }
20369
+ return result;
20370
+ }
20371
+ function formatUsdCents(cents, decimals = 2) {
20372
+ return (cents / 100).toFixed(decimals);
20373
+ }
20374
+ var init_amounts = __esm({
20375
+ "src/payment/amounts.ts"() {
20376
+ "use strict";
20377
+ }
20378
+ });
20379
+
20333
20380
  // src/payment/rails.ts
20334
20381
  function lookupRail(name) {
20335
20382
  return rails[name];
@@ -20429,8 +20476,7 @@ function buildPaymentRequestBlob({
20429
20476
  const decimalsResolved = decimals ?? railDef?.decimals ?? 6;
20430
20477
  const currencyResolved = currency ?? railDef?.currency ?? "usd";
20431
20478
  const chainIdResolved = chainId ?? railDef?.chainId;
20432
- const amountNum = typeof amountUsd === "string" ? Number(amountUsd) : amountUsd;
20433
- const amountRaw = BigInt(Math.round(amountNum * 10 ** decimalsResolved)).toString();
20479
+ const amountRaw = usdToAtomic(amountUsd, { decimals: decimalsResolved }).toString();
20434
20480
  const blob = { amount: amountRaw, currency: currencyResolved, decimals: decimalsResolved };
20435
20481
  if (recipient) blob.recipient = recipient;
20436
20482
  const methodDetails = {};
@@ -20457,6 +20503,7 @@ function paymentDirective({
20457
20503
  var init_directive = __esm({
20458
20504
  "src/payment/directive.ts"() {
20459
20505
  "use strict";
20506
+ init_amounts();
20460
20507
  init_rails();
20461
20508
  }
20462
20509
  });
@@ -20810,15 +20857,26 @@ var index_exports = {};
20810
20857
  __export(index_exports, {
20811
20858
  A2A_DEFAULT_TRANSPORT: () => A2A_DEFAULT_TRANSPORT,
20812
20859
  A2A_PROTOCOL_VERSION: () => A2A_PROTOCOL_VERSION,
20860
+ AGENTSCORE_CANONICAL_ISSUER: () => AGENTSCORE_CANONICAL_ISSUER,
20813
20861
  AGENTSCORE_UCP_CAPABILITY: () => AGENTSCORE_UCP_CAPABILITY,
20862
+ AGENT_IDENTITY_HEADER: () => AGENT_IDENTITY_HEADER,
20863
+ AIP_COVERED_COMPONENTS: () => AIP_COVERED_COMPONENTS,
20864
+ AIP_SIGNATURE_TAG: () => AIP_SIGNATURE_TAG,
20814
20865
  Checkout: () => Checkout,
20815
20866
  CheckoutValidationError: () => CheckoutValidationError,
20816
20867
  FIXABLE_DENIAL_REASONS: () => FIXABLE_DENIAL_REASONS,
20868
+ HARD_MAX_CACHE_SECONDS: () => HARD_MAX_CACHE_SECONDS,
20869
+ JWKS_WELL_KNOWN_PATH: () => JWKS_WELL_KNOWN_PATH,
20870
+ JwksCache: () => JwksCache,
20817
20871
  UCPSigningKey: () => UCPSigningKey,
20818
20872
  UCPVerificationError: () => UCPVerificationError,
20819
20873
  UCP_A2A_EXTENSION_URI: () => UCP_A2A_EXTENSION_URI,
20874
+ aipErrorCode: () => aipErrorCode,
20875
+ aipErrorStatus: () => aipErrorStatus,
20820
20876
  buildA2AAgentCard: () => buildA2AAgentCard,
20821
20877
  buildAgentMemoryHint: () => buildAgentMemoryHint,
20878
+ buildAipErrorBody: () => buildAipErrorBody,
20879
+ buildAipTrustedIssuers: () => buildAipTrustedIssuers,
20822
20880
  buildContactSupportNextSteps: () => buildContactSupportNextSteps,
20823
20881
  buildDefaultCheckoutRails: () => buildDefaultCheckoutRails,
20824
20882
  buildGateFromPolicy: () => buildGateFromPolicy,
@@ -20827,6 +20885,8 @@ __export(index_exports, {
20827
20885
  buildSignerMismatchBody: () => buildSignerMismatchBody,
20828
20886
  buildUCPProfile: () => buildUCPProfile,
20829
20887
  buildVerificationRequiredBody: () => buildVerificationRequiredBody,
20888
+ buildVerifyContextFromRequest: () => buildVerifyContextFromRequest,
20889
+ canonicalizeIssuer: () => canonicalizeIssuer,
20830
20890
  computeFirstCheckout: () => computeFirstCheckout,
20831
20891
  createDefaultOnDenied: () => createDefaultOnDenied,
20832
20892
  createQuoteCache: () => createQuoteCache,
@@ -20840,11 +20900,15 @@ __export(index_exports, {
20840
20900
  formatUsdCents: () => formatUsdCents,
20841
20901
  generateUCPSigningKey: () => generateUCPSigningKey,
20842
20902
  getIdentityStatus: () => getIdentityStatus,
20903
+ hasAgentIdentityHeader: () => hasAgentIdentityHeader,
20843
20904
  hasMppxHeader: () => hasMppxHeader,
20844
20905
  hasPaymentHeader: () => hasPaymentHeader,
20845
20906
  hasX402Header: () => hasX402Header,
20846
20907
  hashOperatorToken: () => hashOperatorToken,
20908
+ isAitShape: () => isAitShape,
20909
+ isEvmNetwork: () => isEvmNetwork,
20847
20910
  isFixableDenial: () => isFixableDenial,
20911
+ isSolanaNetwork: () => isSolanaNetwork,
20848
20912
  loadSolanaFeePayer: () => loadSolanaFeePayer,
20849
20913
  loadUCPSigningKeyFromEnv: () => loadUCPSigningKeyFromEnv,
20850
20914
  makeMppxComposeHook: () => makeMppxComposeHook,
@@ -20854,9 +20918,11 @@ __export(index_exports, {
20854
20918
  runGateWithEnforcement: () => runGateWithEnforcement,
20855
20919
  shippingCountryAllowed: () => shippingCountryAllowed,
20856
20920
  shippingStateAllowed: () => shippingStateAllowed,
20921
+ signMessage: () => signMessage,
20857
20922
  signUCPProfile: () => signUCPProfile,
20858
20923
  stripeSptPaymentHandler: () => stripeSptPaymentHandler,
20859
20924
  ucpA2AExtension: () => ucpA2AExtension,
20925
+ validateAitPayload: () => validateAitPayload,
20860
20926
  validateShippingAgainstPolicy: () => validateShippingAgainstPolicy,
20861
20927
  validationEnvelope: () => validationEnvelope,
20862
20928
  validationResponseExpress: () => validationResponseExpress,
@@ -20865,12 +20931,16 @@ __export(index_exports, {
20865
20931
  validationResponseNextjs: () => validationResponseNextjs,
20866
20932
  validationResponseWeb: () => validationResponseWeb,
20867
20933
  verificationAgentInstructions: () => verificationAgentInstructions,
20934
+ verifyAit: () => verifyAit,
20935
+ verifyAitRequest: () => verifyAitRequest,
20936
+ verifyMessageSignature: () => verifyMessageSignature,
20868
20937
  verifyUCPProfile: () => verifyUCPProfile,
20869
20938
  x402PaymentHandler: () => x402PaymentHandler
20870
20939
  });
20871
20940
  module.exports = __toCommonJS(index_exports);
20872
20941
 
20873
20942
  // src/core.ts
20943
+ var import_node_crypto = require("crypto");
20874
20944
  var import_sdk = require("@agent-score/sdk");
20875
20945
 
20876
20946
  // src/_denial.ts
@@ -21186,8 +21256,9 @@ var INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({
21186
21256
  ],
21187
21257
  user_message: "The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one."
21188
21258
  });
21189
- function buildAgentMemoryHint() {
21259
+ function buildAgentMemoryHint(aipTrustedIssuers) {
21190
21260
  const api = CANONICAL_AGENTSCORE_API;
21261
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
21191
21262
  return {
21192
21263
  save_for_future_agentscore_gates: true,
21193
21264
  pattern_summary: "AgentScore is a cross-merchant identity substrate for agent commerce. Any endpoint that returns 403 missing_identity / identity_verification_required or 402 challenges referencing AgentScore uses the same identity system. One KYC works across all AgentScore merchants \u2014 no re-verification per site. Save this pattern (and the endpoints below) to persistent memory so future AgentScore encounters skip the cold-start session flow.",
@@ -21195,8 +21266,12 @@ function buildAgentMemoryHint() {
21195
21266
  identity_check_endpoint: `${api}/v1/credentials`,
21196
21267
  identity_paths: {
21197
21268
  wallet: "If paying from a crypto wallet you have used before on any AgentScore merchant, send `X-Wallet-Address: 0x...`. Shortest path; no token lifecycle to manage.",
21198
- operator_token: "For any rail (Stripe SPT, card, or a wallet you have not linked yet), send `X-Operator-Token: opc_...`. Reusable across merchants until the token expires."
21269
+ operator_token: "For any rail (Stripe SPT, card, or a wallet you have not linked yet), send `X-Operator-Token: opc_...`. Reusable across merchants until the token expires.",
21270
+ ...acceptsAip && {
21271
+ agent_identity: 'If you hold an AIP Agent Identity Token from a trusted issuer (see aip_trusted_issuers), present it: send the JWT in an `Agent-Identity` header plus an RFC 9421 HTTP Message Signature (Signature-Input + Signature over @method @authority @path agent-identity, tag="agent-identity") signed with the token-bound cnf key. The merchant verifies it and applies its policy \u2014 no separate AgentScore credential needed.'
21272
+ }
21199
21273
  },
21274
+ ...acceptsAip && { aip_trusted_issuers: aipTrustedIssuers },
21200
21275
  bootstrap: "If you have neither a linked wallet nor a valid operator_token, follow the session/verify flow in the per-request `agent_instructions` block. This happens at most once per agent identity \u2014 after first verification, the operator_token and any subsequently used wallet are reusable everywhere.",
21201
21276
  do_not_persist_in_memory: ["operator_token", "poll_secret"],
21202
21277
  persist_in_credential_store: ["operator_token"]
@@ -21218,11 +21293,12 @@ function createAgentScoreCore(options) {
21218
21293
  baseUrl: rawBaseUrl = "https://api.agentscore.sh",
21219
21294
  chain: gateChain,
21220
21295
  userAgent,
21221
- createSessionOnMissing
21296
+ createSessionOnMissing,
21297
+ aipTrustedIssuers
21222
21298
  } = options;
21223
21299
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21224
- const agentMemoryHint = buildAgentMemoryHint();
21225
- const defaultUa = `@agent-score/commerce@${"2.3.0"}`;
21300
+ const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
21301
+ const defaultUa = `@agent-score/commerce@${"2.5.0"}`;
21226
21302
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21227
21303
  const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21228
21304
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21240,6 +21316,7 @@ function createAgentScoreCore(options) {
21240
21316
  return s;
21241
21317
  }
21242
21318
  const cache = new TTLCache(cacheSeconds * 1e3);
21319
+ const lastSignerRaw = /* @__PURE__ */ new Map();
21243
21320
  async function tryMintSessionDenial(ctx) {
21244
21321
  if (!createSessionOnMissing) return void 0;
21245
21322
  try {
@@ -21297,13 +21374,18 @@ function createAgentScoreCore(options) {
21297
21374
  }
21298
21375
  }
21299
21376
  async function evaluate(identity, ctx, signer) {
21300
- if (!identity || !identity.address && !identity.operatorToken) {
21377
+ if (!identity || !identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim()) {
21301
21378
  if (failOpen) return { kind: "allow" };
21302
21379
  const sessionReason = await tryMintSessionDenial(ctx);
21303
21380
  if (sessionReason) return { kind: "deny", reason: sessionReason };
21381
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
21382
+ const aipStep = acceptsAip ? [
21383
+ `If you hold an AIP Agent Identity Token from a trusted issuer (${aipTrustedIssuers.join(", ")}): present it \u2014 send the JWT in an Agent-Identity header plus an RFC 9421 HTTP Message Signature (Signature-Input + Signature over @method @authority @path agent-identity, tag="agent-identity") signed with the token-bound cnf key. This satisfies identity in one round trip without an AgentScore credential.`
21384
+ ] : [];
21304
21385
  const missingIdentityInstructions = JSON.stringify({
21305
21386
  action: "probe_identity_then_session",
21306
21387
  steps: [
21388
+ ...aipStep,
21307
21389
  "If you have a wallet AND this merchant accepts a wallet-signing rail (Tempo MPP or x402 \u2014 see openapi.json x-payment-info): send X-Wallet-Address and retry. If the wallet is already linked to an AgentScore operator (via prior SIWE claim or prior captureWallet), this passes in one round trip. If the wallet is unlinked or the account has no KYC, the 403 will include a verify_url \u2014 share it with the user to claim the wallet + complete KYC, then retry.",
21308
21390
  "If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
21309
21391
  "If neither applies: retry with NO identity header. Merchants that auto-create verification sessions (most AgentScore merchants do) return verify_url + session_id + poll_secret in the 403 body \u2014 share verify_url with the user, then poll poll_url every 5s with the X-Poll-Secret header until status=verified (the poll returns a one-time operator_token). If the retry returns the same bare 403, this merchant does not support self-service session bootstrapping \u2014 direct the user to https://agentscore.sh/sign-up to create an AgentScore identity and mint an operator_token from their dashboard (https://agentscore.sh/dashboard/verify). The user hands the opc_... to you, and you retry with X-Operator-Token."
@@ -21319,7 +21401,7 @@ function createAgentScoreCore(options) {
21319
21401
  }
21320
21402
  };
21321
21403
  }
21322
- const cacheKey2 = identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
21404
+ const cacheKey2 = identity.aipToken ? `aip:${(0, import_node_crypto.createHash)("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
21323
21405
  const cached2 = cache.get(cacheKey2);
21324
21406
  if (cached2) {
21325
21407
  if (cached2.allow) {
@@ -21364,7 +21446,7 @@ function createAgentScoreCore(options) {
21364
21446
  // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
21365
21447
  ...signer && { signer: { address: signer.address, network: signer.network } }
21366
21448
  };
21367
- const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
21449
+ const result = identity.aipToken ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken }) : identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
21368
21450
  data = result;
21369
21451
  } catch (err) {
21370
21452
  if (err instanceof import_sdk.PaymentRequiredError) {
@@ -21435,6 +21517,9 @@ function createAgentScoreCore(options) {
21435
21517
  const decisionReasons = data.decision_reasons ?? [];
21436
21518
  const allow = decision === "allow" || decision == null;
21437
21519
  cache.set(cacheKey2, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
21520
+ if (identity.address !== void 0 && identity.operatorToken === void 0 && identity.aipToken === void 0 && (data.signer_match !== void 0 || data.signer_sanctions !== void 0)) {
21521
+ lastSignerRaw.set(normalizeAddress(identity.address), data);
21522
+ }
21438
21523
  if (allow) {
21439
21524
  const quota = data.quota;
21440
21525
  return {
@@ -21499,9 +21584,7 @@ function createAgentScoreCore(options) {
21499
21584
  }
21500
21585
  function getSignerVerdict(claimedAddress) {
21501
21586
  const claimedNorm = normalizeAddress(claimedAddress);
21502
- const cached2 = cache.get(claimedNorm);
21503
- if (!cached2) return void 0;
21504
- const raw = cached2.raw;
21587
+ const raw = lastSignerRaw.get(claimedNorm) ?? cache.get(claimedNorm)?.raw;
21505
21588
  if (!raw) return void 0;
21506
21589
  const rawMatch = raw.signer_match;
21507
21590
  const rawSanctions = raw.signer_sanctions;
@@ -21562,6 +21645,18 @@ async function extractSolanaSignerFromCredential(credential) {
21562
21645
  }
21563
21646
  }
21564
21647
  async function extractPaymentSigner(request, x402PaymentHeader) {
21648
+ if (x402PaymentHeader) {
21649
+ try {
21650
+ const decoded = atob(x402PaymentHeader);
21651
+ const parsed = JSON.parse(decoded);
21652
+ const from9 = parsed?.payload?.authorization?.from;
21653
+ if (typeof from9 === "string" && /^0x[0-9a-fA-F]{40}$/.test(from9)) {
21654
+ return { address: from9.toLowerCase(), network: "evm" };
21655
+ }
21656
+ } catch (err) {
21657
+ console.warn("[gate] x402 signer extraction failed:", err instanceof Error ? err.message : err);
21658
+ }
21659
+ }
21565
21660
  const authHeader = request.headers.get("authorization");
21566
21661
  if (authHeader) {
21567
21662
  try {
@@ -21581,18 +21676,6 @@ async function extractPaymentSigner(request, x402PaymentHeader) {
21581
21676
  console.warn("[gate] MPP signer extraction failed:", err instanceof Error ? err.message : err);
21582
21677
  }
21583
21678
  }
21584
- if (x402PaymentHeader) {
21585
- try {
21586
- const decoded = atob(x402PaymentHeader);
21587
- const parsed = JSON.parse(decoded);
21588
- const from9 = parsed?.payload?.authorization?.from;
21589
- if (typeof from9 === "string" && /^0x[0-9a-fA-F]{40}$/.test(from9)) {
21590
- return { address: from9.toLowerCase(), network: "evm" };
21591
- }
21592
- } catch (err) {
21593
- console.warn("[gate] x402 signer extraction failed:", err instanceof Error ? err.message : err);
21594
- }
21595
- }
21596
21679
  return null;
21597
21680
  }
21598
21681
  async function extractPaymentSignerFromAuth(authHeader, x402PaymentHeader) {
@@ -21764,7 +21847,7 @@ function validateShippingAgainstPolicy(opts) {
21764
21847
  }
21765
21848
 
21766
21849
  // src/identity/tokens.ts
21767
- var import_node_crypto = require("crypto");
21850
+ var import_node_crypto2 = require("crypto");
21768
21851
 
21769
21852
  // src/payment/payment_header.ts
21770
21853
  function toTitleCase(name) {
@@ -21800,7 +21883,7 @@ function hasMppxHeader(input) {
21800
21883
 
21801
21884
  // src/identity/tokens.ts
21802
21885
  function hashOperatorToken(plaintext) {
21803
- return (0, import_node_crypto.createHash)("sha256").update(plaintext, "utf8").digest("hex");
21886
+ return (0, import_node_crypto2.createHash)("sha256").update(plaintext, "utf8").digest("hex");
21804
21887
  }
21805
21888
  function extractOwnerScope(input) {
21806
21889
  const headers = asHeaders(input);
@@ -21813,7 +21896,7 @@ function extractOwnerScope(input) {
21813
21896
  }
21814
21897
 
21815
21898
  // src/checkout.ts
21816
- var import_node_crypto2 = require("crypto");
21899
+ var import_node_crypto3 = require("crypto");
21817
21900
 
21818
21901
  // src/_mppx_receipt.ts
21819
21902
  function extractMppxReceiptHeaderFromRaw(raw) {
@@ -21853,6 +21936,710 @@ function warnMissingApiKeyOnce(label) {
21853
21936
  );
21854
21937
  }
21855
21938
 
21939
+ // src/aip/verify.ts
21940
+ var import_jose2 = require("jose");
21941
+
21942
+ // src/aip/http-signature.ts
21943
+ var import_jose = require("jose");
21944
+ var { subtle } = globalThis.crypto;
21945
+ var b64ToBytes = (b64) => {
21946
+ const bin = atob(b64);
21947
+ const out = new Uint8Array(bin.length);
21948
+ for (let i = 0; i < bin.length; i++) {
21949
+ out[i] = bin.charCodeAt(i);
21950
+ }
21951
+ return out;
21952
+ };
21953
+ var bytesToB64 = (bytes) => {
21954
+ let bin = "";
21955
+ for (let i = 0; i < bytes.length; i++) {
21956
+ bin += String.fromCharCode(bytes[i]);
21957
+ }
21958
+ return btoa(bin);
21959
+ };
21960
+ var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
21961
+ var AIP_SIGNATURE_TAG = "agent-identity";
21962
+ var DEFAULT_MAX_SKEW_SECONDS = 60;
21963
+ var normalizeAuthority = (authority) => {
21964
+ const lower = authority.trim().toLowerCase();
21965
+ const colon = lower.lastIndexOf(":");
21966
+ if (colon === -1) {
21967
+ return lower;
21968
+ }
21969
+ if (lower.includes("]") && colon < lower.indexOf("]")) {
21970
+ return lower;
21971
+ }
21972
+ const host = lower.slice(0, colon);
21973
+ const port = lower.slice(colon + 1);
21974
+ if (port === "80" || port === "443") {
21975
+ return host;
21976
+ }
21977
+ return lower;
21978
+ };
21979
+ var componentValue = (name, input) => {
21980
+ switch (name) {
21981
+ case "@method":
21982
+ return input.method.toUpperCase();
21983
+ case "@authority":
21984
+ return normalizeAuthority(input.authority);
21985
+ case "@path":
21986
+ return input.path;
21987
+ case "agent-identity":
21988
+ return input.agentIdentity.trim();
21989
+ default:
21990
+ return input.extra?.[name] ?? null;
21991
+ }
21992
+ };
21993
+ var serializeComponentList = (components) => `(${components.map((c) => `"${c}"`).join(" ")})`;
21994
+ var serializeParams = (p) => {
21995
+ const parts = [];
21996
+ if (p.created !== void 0) {
21997
+ parts.push(`created=${p.created}`);
21998
+ }
21999
+ if (p.expires !== void 0) {
22000
+ parts.push(`expires=${p.expires}`);
22001
+ }
22002
+ if (p.keyid !== void 0) {
22003
+ parts.push(`keyid="${p.keyid}"`);
22004
+ }
22005
+ if (p.alg !== void 0) {
22006
+ parts.push(`alg="${p.alg}"`);
22007
+ }
22008
+ if (p.tag !== void 0) {
22009
+ parts.push(`tag="${p.tag}"`);
22010
+ }
22011
+ return parts.map((s) => `;${s}`).join("");
22012
+ };
22013
+ var buildSignatureBase = (params, input) => {
22014
+ const lines = [];
22015
+ for (const name of params.components) {
22016
+ const value = componentValue(name, input);
22017
+ if (value === null) {
22018
+ throw new MissingComponentError(name);
22019
+ }
22020
+ lines.push(`"${name}": ${value}`);
22021
+ }
22022
+ const paramsValue = serializeComponentList(params.components) + serializeParams(params);
22023
+ lines.push(`"@signature-params": ${paramsValue}`);
22024
+ return lines.join("\n");
22025
+ };
22026
+ var MissingComponentError = class extends Error {
22027
+ constructor(component) {
22028
+ super(`signature base missing covered component: ${component}`);
22029
+ this.component = component;
22030
+ this.name = "MissingComponentError";
22031
+ }
22032
+ component;
22033
+ };
22034
+ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
22035
+ const members = splitDictionary(header);
22036
+ if (members.length === 0) {
22037
+ return null;
22038
+ }
22039
+ const parsed = members.map((m) => {
22040
+ const params = parseInnerListMember(m.value);
22041
+ return params ? { label: m.label, params } : null;
22042
+ }).filter((x) => x !== null);
22043
+ if (parsed.length === 0) {
22044
+ return null;
22045
+ }
22046
+ const tagged = parsed.find((p) => p.params.tag === tag);
22047
+ if (tagged) {
22048
+ return tagged;
22049
+ }
22050
+ if (parsed.length === 1 && parsed[0].params.tag === void 0) {
22051
+ return parsed[0];
22052
+ }
22053
+ return null;
22054
+ };
22055
+ var parseSignatureValue = (header, label) => {
22056
+ const members = splitDictionary(header);
22057
+ const member = members.find((m) => m.label === label);
22058
+ if (!member) {
22059
+ return null;
22060
+ }
22061
+ const v = member.value.trim();
22062
+ if (!v.startsWith(":") || !v.endsWith(":") || v.length < 2) {
22063
+ return null;
22064
+ }
22065
+ const b64 = v.slice(1, -1);
22066
+ try {
22067
+ return b64ToBytes(b64);
22068
+ } catch {
22069
+ return null;
22070
+ }
22071
+ };
22072
+ var splitDictionary = (header) => {
22073
+ const out = [];
22074
+ let depth = 0;
22075
+ let inBytes = false;
22076
+ let inString = false;
22077
+ let current = "";
22078
+ for (let i = 0; i < header.length; i++) {
22079
+ const ch = header[i];
22080
+ if (inString) {
22081
+ current += ch;
22082
+ if (ch === '"' && header[i - 1] !== "\\") {
22083
+ inString = false;
22084
+ }
22085
+ continue;
22086
+ }
22087
+ if (ch === '"') {
22088
+ inString = true;
22089
+ current += ch;
22090
+ continue;
22091
+ }
22092
+ if (ch === ":") {
22093
+ inBytes = !inBytes;
22094
+ current += ch;
22095
+ continue;
22096
+ }
22097
+ if (!inBytes && ch === "(") {
22098
+ depth++;
22099
+ current += ch;
22100
+ continue;
22101
+ }
22102
+ if (!inBytes && ch === ")") {
22103
+ depth = Math.max(0, depth - 1);
22104
+ current += ch;
22105
+ continue;
22106
+ }
22107
+ if (!inBytes && depth === 0 && ch === ",") {
22108
+ pushMember(out, current);
22109
+ current = "";
22110
+ continue;
22111
+ }
22112
+ current += ch;
22113
+ }
22114
+ pushMember(out, current);
22115
+ return out;
22116
+ };
22117
+ var pushMember = (out, raw) => {
22118
+ const trimmed = raw.trim();
22119
+ if (!trimmed) {
22120
+ return;
22121
+ }
22122
+ const eq = trimmed.indexOf("=");
22123
+ if (eq === -1) {
22124
+ return;
22125
+ }
22126
+ const label = trimmed.slice(0, eq).trim();
22127
+ const value = trimmed.slice(eq + 1).trim();
22128
+ if (label) {
22129
+ out.push({ label, value });
22130
+ }
22131
+ };
22132
+ var parseInnerListMember = (value) => {
22133
+ const open = value.indexOf("(");
22134
+ const close = value.indexOf(")", open + 1);
22135
+ if (open === -1 || close === -1) {
22136
+ return null;
22137
+ }
22138
+ const listBody = value.slice(open + 1, close).trim();
22139
+ const components = listBody.length === 0 ? [] : (listBody.match(/"[^"]*"/g) ?? []).map((s) => s.slice(1, -1));
22140
+ const params = { components };
22141
+ const paramStr = value.slice(close + 1);
22142
+ const re = /;\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|-?\d+)/g;
22143
+ let match;
22144
+ while ((match = re.exec(paramStr)) !== null) {
22145
+ const key = match[1];
22146
+ const raw = match[2];
22147
+ const val = raw.startsWith('"') ? raw.slice(1, -1) : Number(raw);
22148
+ if (key === "created") {
22149
+ params.created = val;
22150
+ } else if (key === "expires") {
22151
+ params.expires = val;
22152
+ } else if (key === "keyid") {
22153
+ params.keyid = val;
22154
+ } else if (key === "tag") {
22155
+ params.tag = val;
22156
+ } else if (key === "alg") {
22157
+ params.alg = val;
22158
+ }
22159
+ }
22160
+ return params;
22161
+ };
22162
+ var verifyMessageSignature = async (input) => {
22163
+ const selected = parseSignatureInput(input.signatureInput);
22164
+ if (!selected) {
22165
+ return { ok: false, reason: "no_aip_signature" };
22166
+ }
22167
+ const { label, params } = selected;
22168
+ if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
22169
+ return { ok: false, reason: "unsupported_alg" };
22170
+ }
22171
+ for (const required3 of AIP_COVERED_COMPONENTS) {
22172
+ if (!params.components.includes(required3)) {
22173
+ return { ok: false, reason: "missing_covered_component" };
22174
+ }
22175
+ }
22176
+ const now = input.now ?? Math.floor(Date.now() / 1e3);
22177
+ const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
22178
+ if (params.created !== void 0 && params.created > now + skew) {
22179
+ return { ok: false, reason: "created_in_future" };
22180
+ }
22181
+ if (params.expires !== void 0 && params.expires < now - skew) {
22182
+ return { ok: false, reason: "expired" };
22183
+ }
22184
+ if (!params.keyid) {
22185
+ return { ok: false, reason: "missing_keyid" };
22186
+ }
22187
+ const cnf = input.cnfJwk;
22188
+ if (cnf.kty !== "OKP" || cnf.crv !== "Ed25519" || typeof cnf.x !== "string" || cnf.x.length === 0) {
22189
+ return { ok: false, reason: "unsupported_cnf_key" };
22190
+ }
22191
+ let thumbprint;
22192
+ try {
22193
+ thumbprint = await (0, import_jose.calculateJwkThumbprint)(input.cnfJwk, "sha256");
22194
+ } catch {
22195
+ return { ok: false, reason: "unsupported_cnf_key" };
22196
+ }
22197
+ if (params.keyid !== thumbprint) {
22198
+ return { ok: false, reason: "keyid_mismatch" };
22199
+ }
22200
+ const sig = parseSignatureValue(input.signature, label);
22201
+ if (!sig) {
22202
+ return { ok: false, reason: "malformed_signature" };
22203
+ }
22204
+ let base;
22205
+ try {
22206
+ base = buildSignatureBase(params, {
22207
+ method: input.method,
22208
+ authority: input.authority,
22209
+ path: input.path,
22210
+ agentIdentity: input.agentIdentity,
22211
+ extra: input.extraComponents
22212
+ });
22213
+ } catch (err) {
22214
+ if (err instanceof MissingComponentError) {
22215
+ return { ok: false, reason: "missing_covered_component" };
22216
+ }
22217
+ throw err;
22218
+ }
22219
+ let valid;
22220
+ try {
22221
+ const key = await (0, import_jose.importJWK)(input.cnfJwk, "EdDSA");
22222
+ if (!(key instanceof CryptoKey)) {
22223
+ return { ok: false, reason: "signature_invalid" };
22224
+ }
22225
+ valid = await subtle.verify(
22226
+ { name: "Ed25519" },
22227
+ key,
22228
+ sig,
22229
+ new TextEncoder().encode(base)
22230
+ );
22231
+ } catch {
22232
+ return { ok: false, reason: "signature_invalid" };
22233
+ }
22234
+ return valid ? { ok: true, params } : { ok: false, reason: "signature_invalid" };
22235
+ };
22236
+ var signMessage = async (input) => {
22237
+ const label = input.label ?? "ait";
22238
+ const components = input.components ?? [...AIP_COVERED_COMPONENTS];
22239
+ const created = input.created ?? Math.floor(Date.now() / 1e3);
22240
+ const keyid = await (0, import_jose.calculateJwkThumbprint)(input.publicJwk, "sha256");
22241
+ const params = {
22242
+ components,
22243
+ created,
22244
+ expires: input.expires,
22245
+ keyid,
22246
+ tag: AIP_SIGNATURE_TAG
22247
+ };
22248
+ const base = buildSignatureBase(params, {
22249
+ method: input.method,
22250
+ authority: input.authority,
22251
+ path: input.path,
22252
+ agentIdentity: input.agentIdentity,
22253
+ extra: input.extraComponents
22254
+ });
22255
+ const key = await (0, import_jose.importJWK)(input.privateJwk, "EdDSA");
22256
+ if (!(key instanceof CryptoKey)) {
22257
+ throw new Error("signMessage: expected an Ed25519 private CryptoKey");
22258
+ }
22259
+ const sigBytes = await subtle.sign(
22260
+ "Ed25519",
22261
+ key,
22262
+ new TextEncoder().encode(base)
22263
+ );
22264
+ const b64 = bytesToB64(new Uint8Array(sigBytes));
22265
+ const signatureInput = `${label}=${serializeComponentList(components)}${serializeParams(params)}`;
22266
+ const signature2 = `${label}=:${b64}:`;
22267
+ return { signatureInput, signature: signature2 };
22268
+ };
22269
+
22270
+ // src/aip/types.ts
22271
+ var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
22272
+ var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
22273
+ var isAitShape = (payload) => isObject2(payload) && isObject2(payload.cnf) && isObject2(payload.agent);
22274
+ var validateAitPayload = (payload) => {
22275
+ if (!isObject2(payload)) {
22276
+ return { ok: false, reason: "not_an_object" };
22277
+ }
22278
+ if (!isNonEmptyString(payload.aip_version)) {
22279
+ return { ok: false, reason: "missing_aip_version" };
22280
+ }
22281
+ if (!isNonEmptyString(payload.iss)) {
22282
+ return { ok: false, reason: "missing_iss" };
22283
+ }
22284
+ if (!isNonEmptyString(payload.sub)) {
22285
+ return { ok: false, reason: "missing_sub" };
22286
+ }
22287
+ if (typeof payload.iat !== "number") {
22288
+ return { ok: false, reason: "missing_iat" };
22289
+ }
22290
+ if (typeof payload.exp !== "number") {
22291
+ return { ok: false, reason: "missing_exp" };
22292
+ }
22293
+ if (!isObject2(payload.cnf) || !isObject2(payload.cnf.jwk)) {
22294
+ return { ok: false, reason: "missing_cnf" };
22295
+ }
22296
+ if (!isObject2(payload.agent) || !isNonEmptyString(payload.agent.provider)) {
22297
+ return { ok: false, reason: "missing_agent_provider" };
22298
+ }
22299
+ if (payload.trust_level === "human_confirmed") {
22300
+ const auth = payload.auth;
22301
+ const amr = isObject2(auth) ? auth.amr : void 0;
22302
+ if (!Array.isArray(amr) || amr.length === 0) {
22303
+ return { ok: false, reason: "human_confirmed_without_amr" };
22304
+ }
22305
+ }
22306
+ return { ok: true, payload };
22307
+ };
22308
+
22309
+ // src/aip/verify.ts
22310
+ var AGENT_IDENTITY_HEADER = "agent-identity";
22311
+ var verifyAit = async (ctx, opts) => {
22312
+ if (ctx.agentIdentityHeaders.length === 0) {
22313
+ return { ok: false, reason: "no_token" };
22314
+ }
22315
+ if (!ctx.signatureInput || !ctx.signature) {
22316
+ return { ok: false, reason: "pop_signature_missing" };
22317
+ }
22318
+ let lastFailure = "malformed_token";
22319
+ for (const raw of ctx.agentIdentityHeaders) {
22320
+ const token = stripBearer(raw);
22321
+ let header;
22322
+ let payload;
22323
+ try {
22324
+ header = (0, import_jose2.decodeProtectedHeader)(token);
22325
+ payload = (0, import_jose2.decodeJwt)(token);
22326
+ } catch {
22327
+ lastFailure = "malformed_token";
22328
+ continue;
22329
+ }
22330
+ if (header.alg === void 0 || header.alg.toLowerCase() === "none") {
22331
+ lastFailure = "malformed_token";
22332
+ continue;
22333
+ }
22334
+ if (!isAitShape(payload)) {
22335
+ lastFailure = "malformed_token";
22336
+ continue;
22337
+ }
22338
+ const validated = validateAitPayload(payload);
22339
+ if (!validated.ok) {
22340
+ lastFailure = "invalid_claims";
22341
+ continue;
22342
+ }
22343
+ const claims = validated.payload;
22344
+ const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);
22345
+ if (!keyLookup.ok) {
22346
+ lastFailure = keyLookup.reason === "untrusted_issuer" || keyLookup.reason === "insecure_issuer" ? "untrusted_issuer" : "key_unavailable";
22347
+ continue;
22348
+ }
22349
+ const jwtClockTolerance = opts.maxSkewSeconds ?? 60;
22350
+ try {
22351
+ const idpKey = await (0, import_jose2.importJWK)(keyLookup.key, normalizeAlg(header.alg));
22352
+ await (0, import_jose2.jwtVerify)(token, idpKey, {
22353
+ // Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
22354
+ // this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
22355
+ // non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
22356
+ // token that verifies. Matches the server-side allowlist in core/api aip-verify.
22357
+ algorithms: AIT_SIGNING_ALGS,
22358
+ clockTolerance: jwtClockTolerance,
22359
+ currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
22360
+ });
22361
+ } catch (err) {
22362
+ lastFailure = isExpiry(err) ? "expired_token" : "idp_signature_invalid";
22363
+ continue;
22364
+ }
22365
+ const nowSec = opts.now ?? Math.floor(Date.now() / 1e3);
22366
+ if (claims.iat > nowSec + jwtClockTolerance) {
22367
+ lastFailure = "expired_token";
22368
+ continue;
22369
+ }
22370
+ const popResult = await verifyMessageSignature({
22371
+ method: ctx.method,
22372
+ authority: ctx.authority,
22373
+ path: ctx.path,
22374
+ agentIdentity: raw,
22375
+ signatureInput: ctx.signatureInput,
22376
+ signature: ctx.signature,
22377
+ cnfJwk: claims.cnf.jwk,
22378
+ now: opts.now,
22379
+ maxSkewSeconds: opts.maxSkewSeconds
22380
+ });
22381
+ if (!popResult.ok) {
22382
+ lastFailure = "pop_signature_invalid";
22383
+ continue;
22384
+ }
22385
+ return { ok: true, ait: { payload: claims, iss: claims.iss, cnfJwk: claims.cnf.jwk, token } };
22386
+ }
22387
+ return { ok: false, reason: lastFailure };
22388
+ };
22389
+ var stripBearer = (value) => {
22390
+ const trimmed = value.trim();
22391
+ return /^bearer\s+/i.test(trimmed) ? trimmed.replace(/^bearer\s+/i, "") : trimmed;
22392
+ };
22393
+ var AIT_SIGNING_ALGS = ["EdDSA", "ES256"];
22394
+ var normalizeAlg = (alg) => alg.toLowerCase() === "eddsa" ? "EdDSA" : alg;
22395
+ var isExpiry = (err) => typeof err === "object" && err !== null && err.code === "ERR_JWT_EXPIRED";
22396
+
22397
+ // src/aip/request.ts
22398
+ var readAgentIdentityHeaders = (headers) => {
22399
+ const raw = headers.get(AGENT_IDENTITY_HEADER);
22400
+ if (!raw) {
22401
+ return [];
22402
+ }
22403
+ return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
22404
+ };
22405
+ var deriveAuthority = (req, url2) => req.headers.get("host") ?? url2.host;
22406
+ var buildVerifyContextFromRequest = (req) => {
22407
+ const url2 = new URL(req.url);
22408
+ return {
22409
+ method: req.method,
22410
+ authority: deriveAuthority(req, url2),
22411
+ path: url2.pathname,
22412
+ agentIdentityHeaders: readAgentIdentityHeaders(req.headers),
22413
+ signatureInput: req.headers.get("signature-input"),
22414
+ signature: req.headers.get("signature")
22415
+ };
22416
+ };
22417
+ var hasAgentIdentityHeader = (req) => readAgentIdentityHeaders(req.headers).length > 0;
22418
+ var readNodeHeader = (headers, name) => {
22419
+ const v = headers[name] ?? headers[name.toLowerCase()];
22420
+ if (v === void 0) {
22421
+ return void 0;
22422
+ }
22423
+ return Array.isArray(v) ? v.join(", ") : v;
22424
+ };
22425
+ var hasAgentIdentityHeaderNode = (headers) => {
22426
+ const raw = readNodeHeader(headers, "agent-identity");
22427
+ return raw !== void 0 && raw.split(",").some((s) => s.trim().length > 0);
22428
+ };
22429
+ var buildVerifyContextFromParts = (parts) => {
22430
+ const agentIdentityRaw = readNodeHeader(parts.headers, "agent-identity");
22431
+ const agentIdentityHeaders = agentIdentityRaw ? agentIdentityRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
22432
+ const host = parts.authority ?? readNodeHeader(parts.headers, "host") ?? "";
22433
+ let path;
22434
+ try {
22435
+ path = new URL(parts.url, host ? `http://${host}` : "http://localhost").pathname;
22436
+ } catch {
22437
+ const q = parts.url.indexOf("?");
22438
+ path = q === -1 ? parts.url : parts.url.slice(0, q);
22439
+ }
22440
+ return {
22441
+ method: parts.method,
22442
+ authority: host,
22443
+ path,
22444
+ agentIdentityHeaders,
22445
+ signatureInput: readNodeHeader(parts.headers, "signature-input") ?? null,
22446
+ signature: readNodeHeader(parts.headers, "signature") ?? null
22447
+ };
22448
+ };
22449
+
22450
+ // src/aip/gate.ts
22451
+ var verifyFromContext = async (ctx, opts) => {
22452
+ const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
22453
+ return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };
22454
+ };
22455
+ var verifyAitRequest = (req, opts) => verifyFromContext(buildVerifyContextFromRequest(req), opts);
22456
+ var verifyAitParts = (parts, opts) => verifyFromContext(buildVerifyContextFromParts(parts), opts);
22457
+ var aipErrorCode = (failure) => {
22458
+ switch (failure) {
22459
+ case "no_token":
22460
+ case "pop_signature_missing":
22461
+ return "agent_identity_required";
22462
+ case "untrusted_issuer":
22463
+ return "untrusted_issuer";
22464
+ case "expired_token":
22465
+ return "expired_token";
22466
+ case "invalid_claims":
22467
+ return "insufficient_claims";
22468
+ case "key_unavailable":
22469
+ return "idp_unavailable";
22470
+ case "malformed_token":
22471
+ case "idp_signature_invalid":
22472
+ case "pop_signature_invalid":
22473
+ return "invalid_signature";
22474
+ default:
22475
+ return "invalid_signature";
22476
+ }
22477
+ };
22478
+ var aipErrorStatus = (failure) => {
22479
+ switch (failure) {
22480
+ case "key_unavailable":
22481
+ return 503;
22482
+ case "untrusted_issuer":
22483
+ case "invalid_claims":
22484
+ return 403;
22485
+ default:
22486
+ return 401;
22487
+ }
22488
+ };
22489
+ var aipErrorDetail = (failure) => {
22490
+ switch (failure) {
22491
+ case "no_token":
22492
+ return "No Agent-Identity token was presented.";
22493
+ case "pop_signature_missing":
22494
+ return "The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.";
22495
+ case "untrusted_issuer":
22496
+ return "The token's issuer is not in this service's trusted-issuer list.";
22497
+ case "expired_token":
22498
+ return "The Agent Identity Token has expired.";
22499
+ case "invalid_claims":
22500
+ return "The token is missing required claims for this endpoint.";
22501
+ case "malformed_token":
22502
+ return "The Agent-Identity header could not be parsed as an Agent Identity Token.";
22503
+ case "idp_signature_invalid":
22504
+ return "The identity provider's signature on the token failed verification.";
22505
+ case "pop_signature_invalid":
22506
+ return "The request signature did not match the key bound to the token.";
22507
+ case "key_unavailable":
22508
+ return "The identity provider's signing key could not be resolved.";
22509
+ default:
22510
+ return "Token verification failed.";
22511
+ }
22512
+ };
22513
+ var buildAipErrorBody = (failure) => {
22514
+ const code = aipErrorCode(failure);
22515
+ return {
22516
+ type: `urn:aip:error:${code}`,
22517
+ title: code.replace(/_/g, " "),
22518
+ status: aipErrorStatus(failure),
22519
+ detail: aipErrorDetail(failure)
22520
+ };
22521
+ };
22522
+
22523
+ // src/aip/jwks.ts
22524
+ var JWKS_WELL_KNOWN_PATH = "/.well-known/agent-identity/jwks.json";
22525
+ var HARD_MAX_CACHE_SECONDS = 86400;
22526
+ var DEFAULT_CACHE_SECONDS = 300;
22527
+ var AGENTSCORE_CANONICAL_ISSUER = "https://agentscore.sh";
22528
+ var canonicalizeIssuer = (iss) => {
22529
+ let url2;
22530
+ try {
22531
+ url2 = new URL(iss.trim());
22532
+ } catch {
22533
+ return null;
22534
+ }
22535
+ const scheme = url2.protocol.toLowerCase();
22536
+ const host = url2.hostname.toLowerCase();
22537
+ const isDefaultPort = url2.port === "" || scheme === "https:" && url2.port === "443" || scheme === "http:" && url2.port === "80";
22538
+ const portPart = isDefaultPort ? "" : `:${url2.port}`;
22539
+ const path = url2.pathname === "/" ? "" : url2.pathname.replace(/\/$/, "");
22540
+ return `${scheme}//${host}${portPart}${path}`;
22541
+ };
22542
+ var resolveCacheSeconds = (cacheControl) => {
22543
+ if (!cacheControl) {
22544
+ return DEFAULT_CACHE_SECONDS;
22545
+ }
22546
+ if (/\bno-store\b/i.test(cacheControl) || /\bno-cache\b/i.test(cacheControl)) {
22547
+ return DEFAULT_CACHE_SECONDS;
22548
+ }
22549
+ const m = /\bmax-age\s*=\s*(\d+)/i.exec(cacheControl);
22550
+ if (!m) {
22551
+ return DEFAULT_CACHE_SECONDS;
22552
+ }
22553
+ const advertised = Number(m[1]);
22554
+ if (!Number.isFinite(advertised) || advertised <= 0) {
22555
+ return DEFAULT_CACHE_SECONDS;
22556
+ }
22557
+ return Math.min(advertised, HARD_MAX_CACHE_SECONDS);
22558
+ };
22559
+ var signingKeys = (keys) => keys.filter((k) => k.use === void 0 || k.use === "sig");
22560
+ var JwksCache = class {
22561
+ trusted;
22562
+ fetchImpl;
22563
+ now;
22564
+ userAgent;
22565
+ cache = /* @__PURE__ */ new Map();
22566
+ constructor(opts) {
22567
+ this.trusted = new Set(
22568
+ [AGENTSCORE_CANONICAL_ISSUER, ...opts.trustedIssuers ?? []].map(canonicalizeIssuer).filter((s) => s !== null)
22569
+ );
22570
+ this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
22571
+ this.now = opts.now ?? Date.now;
22572
+ this.userAgent = opts.userAgent ?? "@agentscore/commerce";
22573
+ }
22574
+ /** Is this issuer on the canonicalized trust list? */
22575
+ isTrusted(iss) {
22576
+ const canon = canonicalizeIssuer(iss);
22577
+ return canon !== null && this.trusted.has(canon);
22578
+ }
22579
+ /**
22580
+ * Resolve the signing key for `(iss, kid)`. Enforces trust + HTTPS, serves from cache when
22581
+ * fresh, and refetches once on a kid-miss before giving up.
22582
+ */
22583
+ async getKey(iss, kid) {
22584
+ const canon = canonicalizeIssuer(iss);
22585
+ if (canon === null || !this.trusted.has(canon)) {
22586
+ return { ok: false, reason: "untrusted_issuer" };
22587
+ }
22588
+ if (!canon.startsWith("https://")) {
22589
+ return { ok: false, reason: "insecure_issuer" };
22590
+ }
22591
+ const cached2 = this.cache.get(canon);
22592
+ if (cached2 && this.now() < cached2.expiresAt) {
22593
+ const hit2 = this.select(cached2.keys, kid);
22594
+ if (hit2) {
22595
+ return { ok: true, key: hit2 };
22596
+ }
22597
+ }
22598
+ const refreshed = await this.refresh(canon);
22599
+ if (!refreshed.ok) {
22600
+ return refreshed;
22601
+ }
22602
+ const hit = this.select(refreshed.keys, kid);
22603
+ return hit ? { ok: true, key: hit } : { ok: false, reason: "key_not_found" };
22604
+ }
22605
+ select(keys, kid) {
22606
+ const candidates = signingKeys(keys);
22607
+ if (kid !== void 0) {
22608
+ const byKid = candidates.find((k) => k.kid === kid);
22609
+ if (byKid) {
22610
+ return byKid;
22611
+ }
22612
+ return void 0;
22613
+ }
22614
+ return candidates.length === 1 ? candidates[0] : void 0;
22615
+ }
22616
+ async refresh(canonIssuer) {
22617
+ const url2 = `${canonIssuer}${JWKS_WELL_KNOWN_PATH}`;
22618
+ let res;
22619
+ try {
22620
+ res = await this.fetchImpl(url2, { headers: { "User-Agent": this.userAgent, Accept: "application/jwk-set+json, application/json" } });
22621
+ } catch {
22622
+ return { ok: false, reason: "fetch_failed" };
22623
+ }
22624
+ if (!res.ok) {
22625
+ return { ok: false, reason: "fetch_failed" };
22626
+ }
22627
+ let body;
22628
+ try {
22629
+ body = await res.json();
22630
+ } catch {
22631
+ return { ok: false, reason: "malformed_jwks" };
22632
+ }
22633
+ if (typeof body !== "object" || body === null || !Array.isArray(body.keys)) {
22634
+ return { ok: false, reason: "malformed_jwks" };
22635
+ }
22636
+ const keys = body.keys;
22637
+ const ttlSeconds = resolveCacheSeconds(res.headers.get("cache-control"));
22638
+ this.cache.set(canonIssuer, { keys, expiresAt: this.now() + ttlSeconds * 1e3 });
22639
+ return { ok: true, keys };
22640
+ }
22641
+ };
22642
+
21856
22643
  // src/payment/rail_spec.ts
21857
22644
  init_usdc();
21858
22645
  async function resolveRecipient(r) {
@@ -22005,10 +22792,11 @@ function buildAgentInstructions({
22005
22792
 
22006
22793
  // src/challenge/agent_memory.ts
22007
22794
  function firstEncounterAgentMemory({
22008
- firstEncounter
22795
+ firstEncounter,
22796
+ aipTrustedIssuers
22009
22797
  }) {
22010
22798
  if (!firstEncounter) return void 0;
22011
- return buildAgentMemoryHint();
22799
+ return buildAgentMemoryHint(aipTrustedIssuers);
22012
22800
  }
22013
22801
 
22014
22802
  // src/challenge/body.ts
@@ -23040,6 +23828,30 @@ function pickRail(rails2, key) {
23040
23828
  const spec = rails2[key];
23041
23829
  return spec === void 0 ? void 0 : spec;
23042
23830
  }
23831
+ function buildAipTrustedIssuers(externalIssuers) {
23832
+ const out = [AGENTSCORE_CANONICAL_ISSUER, ...externalIssuers ?? []];
23833
+ const seen = /* @__PURE__ */ new Set();
23834
+ const deduped = [];
23835
+ for (const iss of out) {
23836
+ const key = canonicalizeIssuer(iss) ?? iss;
23837
+ if (!seen.has(key)) {
23838
+ seen.add(key);
23839
+ deduped.push(iss);
23840
+ }
23841
+ }
23842
+ return deduped;
23843
+ }
23844
+ function aipTrustedIssuerSet(cfg) {
23845
+ return buildAipTrustedIssuers(cfg.trustedIssuers);
23846
+ }
23847
+ function resolveIssuerPolicy(issuerPolicies, iss) {
23848
+ const target = canonicalizeIssuer(iss);
23849
+ if (target === null) return void 0;
23850
+ for (const [key, policy] of Object.entries(issuerPolicies)) {
23851
+ if (canonicalizeIssuer(key) === target) return policy;
23852
+ }
23853
+ return void 0;
23854
+ }
23043
23855
  var Checkout = class {
23044
23856
  rails;
23045
23857
  url;
@@ -23057,6 +23869,15 @@ var Checkout = class {
23057
23869
  discoveryExtensions;
23058
23870
  discoveryProbe;
23059
23871
  _x402ServerGetter;
23872
+ /** Lazily-built JWKS cache for AIP verification, shared across requests so issuer keys
23873
+ * are fetched once and cached (per the verifier's hard 24h cap). Built on first AIT. */
23874
+ aipJwks;
23875
+ getAipJwks(cfg) {
23876
+ if (this.aipJwks === void 0) {
23877
+ this.aipJwks = new JwksCache(cfg.trustedIssuers !== void 0 ? { trustedIssuers: cfg.trustedIssuers } : {});
23878
+ }
23879
+ return this.aipJwks;
23880
+ }
23060
23881
  /**
23061
23882
  * True when the merchant has configured an identity-bearing policy flag —
23062
23883
  * `require_kyc`, `require_sanctions_clear` (name screening on the KYC
@@ -23344,7 +24165,64 @@ var Checkout = class {
23344
24165
  }
23345
24166
  return result;
23346
24167
  }
24168
+ const headers = normalizeHeadersToLowercase(ctx.request.headers);
24169
+ const walletAddress = headers["x-wallet-address"];
24170
+ const operatorToken = headers["x-operator-token"];
24171
+ let aipToken;
24172
+ let aipIssuer;
24173
+ if (gate.aip !== void 0 && hasAgentIdentityHeaderNode(headers)) {
24174
+ const aipResult = await verifyAitParts(
24175
+ {
24176
+ method: ctx.request.method,
24177
+ url: ctx.request.url,
24178
+ headers,
24179
+ ...gate.aip.authority !== void 0 && { authority: gate.aip.authority }
24180
+ },
24181
+ {
24182
+ jwks: this.getAipJwks(gate.aip),
24183
+ ...gate.aip.maxSkewSeconds !== void 0 && { maxSkewSeconds: gate.aip.maxSkewSeconds }
24184
+ }
24185
+ );
24186
+ if (!aipResult.ok) {
24187
+ const body2 = buildAipErrorBody(aipResult.failure);
24188
+ return {
24189
+ status: body2.status,
24190
+ body: body2,
24191
+ headers: {
24192
+ "content-type": "application/problem+json",
24193
+ // 503 = the IdP's JWKS was unreachable (transient infra, not a bad token). Hint a
24194
+ // short backoff so agents retry rather than uselessly re-signing.
24195
+ ...body2.status === 503 && { "retry-after": "5" }
24196
+ }
24197
+ };
24198
+ }
24199
+ aipToken = aipResult.ait.token;
24200
+ aipIssuer = aipResult.ait.iss;
24201
+ }
24202
+ const issuerPolicy = aipIssuer !== void 0 && gate.aip?.issuerPolicies !== void 0 ? resolveIssuerPolicy(gate.aip.issuerPolicies, aipIssuer) : void 0;
24203
+ const effPolicy = issuerPolicy ?? {
24204
+ ...gate.requireKyc !== void 0 && { requireKyc: gate.requireKyc },
24205
+ ...gate.requireSanctionsClear !== void 0 && { requireSanctionsClear: gate.requireSanctionsClear },
24206
+ ...gate.minAge !== void 0 && { minAge: gate.minAge },
24207
+ ...gate.blockedJurisdictions !== void 0 && { blockedJurisdictions: gate.blockedJurisdictions },
24208
+ ...gate.allowedJurisdictions !== void 0 && { allowedJurisdictions: gate.allowedJurisdictions }
24209
+ };
23347
24210
  if (gate.apiKey === void 0) {
24211
+ if (aipToken !== void 0) {
24212
+ const hasPolicy = effPolicy.requireKyc || effPolicy.requireSanctionsClear || effPolicy.minAge != null || effPolicy.blockedJurisdictions !== void 0 || effPolicy.allowedJurisdictions !== void 0;
24213
+ if (hasPolicy) {
24214
+ return {
24215
+ status: 403,
24216
+ body: {
24217
+ error: {
24218
+ code: "aip_policy_requires_api_key",
24219
+ message: "This gate declares compliance policy (KYC / age / sanctions / jurisdiction) but has no AgentScore apiKey, so the Agent Identity Token\u2019s claims cannot be evaluated. Configure gate.apiKey to enable policy enforcement on AITs."
24220
+ }
24221
+ }
24222
+ };
24223
+ }
24224
+ return null;
24225
+ }
23348
24226
  return this.runWalletSanctionsOnly(ctx);
23349
24227
  }
23350
24228
  let policyOverride;
@@ -23356,19 +24234,25 @@ var Checkout = class {
23356
24234
  apiKey: gate.apiKey,
23357
24235
  ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
23358
24236
  ...gate.userAgent !== void 0 && { userAgent: gate.userAgent },
23359
- ...gate.requireKyc !== void 0 && { requireKyc: gate.requireKyc },
23360
- ...gate.requireSanctionsClear !== void 0 && { requireSanctionsClear: gate.requireSanctionsClear },
23361
- ...gate.minAge !== void 0 && { minAge: gate.minAge },
23362
- ...gate.blockedJurisdictions !== void 0 && { blockedJurisdictions: gate.blockedJurisdictions },
23363
- ...gate.allowedJurisdictions !== void 0 && { allowedJurisdictions: gate.allowedJurisdictions },
24237
+ // Compliance fields come from effPolicy the per-issuer override for the verified AIT's
24238
+ // issuer when one is configured, else the gate defaults (see effPolicy above). A whole-
24239
+ // policy replacement: an issuer override of `{ requireKyc, minAge }` sends ONLY those,
24240
+ // so sanctions / jurisdiction are not enforced for that issuer.
24241
+ ...effPolicy.requireKyc !== void 0 && { requireKyc: effPolicy.requireKyc },
24242
+ ...effPolicy.requireSanctionsClear !== void 0 && { requireSanctionsClear: effPolicy.requireSanctionsClear },
24243
+ ...effPolicy.minAge !== void 0 && { minAge: effPolicy.minAge },
24244
+ ...effPolicy.blockedJurisdictions !== void 0 && { blockedJurisdictions: effPolicy.blockedJurisdictions },
24245
+ ...effPolicy.allowedJurisdictions !== void 0 && { allowedJurisdictions: effPolicy.allowedJurisdictions },
23364
24246
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23365
24247
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23366
24248
  ...gate.chain !== void 0 && { chain: gate.chain },
24249
+ // Surface AIP acceptance in the missing-identity recovery instructions + agent_memory
24250
+ // hint so agents holding an AIT learn they can present it instead of bootstrapping.
24251
+ ...gate.aip !== void 0 && { aipTrustedIssuers: aipTrustedIssuerSet(gate.aip) },
23367
24252
  // Auto-default `createSessionOnMissing` from gate config when the merchant
23368
- // didn't supply one. Matches python-commerce's behavior every gated route
23369
- // gets the bootstrap session-mint UX out of the box. Merchants who need
23370
- // custom session context or onBeforeSession side effects (goods merchants
23371
- // pre-minting an order_id) supply their own config instead.
24253
+ // didn't supply one, so every gated route gets the bootstrap session-mint UX
24254
+ // out of the box. Merchants who need custom session context or onBeforeSession
24255
+ // side effects (goods merchants pre-minting an order_id) supply their own config.
23372
24256
  createSessionOnMissing: gate.createSessionOnMissing ?? {
23373
24257
  apiKey: gate.apiKey,
23374
24258
  ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
@@ -23378,10 +24262,7 @@ var Checkout = class {
23378
24262
  ...policyOverride ?? {}
23379
24263
  };
23380
24264
  const core = createAgentScoreCore(coreOpts);
23381
- const headers = normalizeHeadersToLowercase(ctx.request.headers);
23382
- const walletAddress = headers["x-wallet-address"];
23383
- const operatorToken = headers["x-operator-token"];
23384
- const identity = walletAddress !== void 0 || operatorToken !== void 0 ? {
24265
+ const identity = aipToken !== void 0 ? { aipToken } : walletAddress !== void 0 || operatorToken !== void 0 ? {
23385
24266
  ...walletAddress !== void 0 && { address: walletAddress },
23386
24267
  ...operatorToken !== void 0 && { operatorToken }
23387
24268
  } : void 0;
@@ -23400,7 +24281,7 @@ var Checkout = class {
23400
24281
  });
23401
24282
  };
23402
24283
  }
23403
- if (walletAddress !== void 0) {
24284
+ if (aipToken === void 0 && walletAddress !== void 0) {
23404
24285
  const verdict = core.getSignerVerdict(walletAddress);
23405
24286
  const sm = verdict?.signer_match;
23406
24287
  if (sm && sm.kind !== "pass") {
@@ -23522,7 +24403,7 @@ var Checkout = class {
23522
24403
  return await this.buildSuccess(ctx, outcome);
23523
24404
  }
23524
24405
  async mintRefId(request) {
23525
- if (this.mintReferenceId === void 0) return (0, import_node_crypto2.randomUUID)();
24406
+ if (this.mintReferenceId === void 0) return (0, import_node_crypto3.randomUUID)();
23526
24407
  const seedCtx = { request, referenceId: "", pricing: null, recipients: {}, state: {} };
23527
24408
  return await this.mintReferenceId(seedCtx);
23528
24409
  }
@@ -23745,8 +24626,13 @@ var Checkout = class {
23745
24626
  retryBody: ctx.request.body,
23746
24627
  // Merchants without an identity-bearing gate get a clean 402: no
23747
24628
  // AgentScore-identity bootstrap describing a verification flow they
23748
- // don't run. Wallet OFAC (the always-on default) doesn't need it.
23749
- agentMemory: firstEncounterAgentMemory({ firstEncounter: this.hasIdentityGate() }),
24629
+ // don't run. Wallet OFAC (the always-on default) doesn't need it. When the
24630
+ // merchant accepts AIP, advertise the agent_identity path too (AgentScore's
24631
+ // own issuer is always trusted, so this fires even with no external issuers).
24632
+ agentMemory: firstEncounterAgentMemory({
24633
+ firstEncounter: this.hasIdentityGate(),
24634
+ ...this.gate?.aip !== void 0 && { aipTrustedIssuers: aipTrustedIssuerSet(this.gate.aip) }
24635
+ }),
23750
24636
  ...ctx.pricing.product ? { product: ctx.pricing.product } : {},
23751
24637
  ...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
23752
24638
  ...x402Accepts.length > 0 ? {
@@ -24105,47 +24991,8 @@ init_wwwauthenticate();
24105
24991
  init_directive();
24106
24992
  init_wwwauthenticate();
24107
24993
 
24108
- // src/payment/amounts.ts
24109
- function usdToAtomic(usd, opts) {
24110
- const { decimals } = opts;
24111
- if (!Number.isInteger(decimals) || decimals < 0) {
24112
- throw new RangeError(`decimals must be a non-negative integer, got ${decimals}`);
24113
- }
24114
- if (typeof usd === "number") {
24115
- if (!Number.isFinite(usd)) {
24116
- throw new RangeError(`usd must be finite, got ${usd}`);
24117
- }
24118
- if (usd < 0) {
24119
- throw new RangeError(`usd must be non-negative, got ${usd}`);
24120
- }
24121
- }
24122
- const s = (typeof usd === "number" ? usd.toString() : usd).trim();
24123
- if (s.startsWith("-")) {
24124
- throw new RangeError(`usd must be non-negative, got ${s}`);
24125
- }
24126
- if (s === "NaN" || s === "Infinity") {
24127
- throw new RangeError(`usd must be finite, got ${s}`);
24128
- }
24129
- const match = /^(\d*)(?:\.(\d*))?$/.exec(s);
24130
- if (!match || match[1] === "" && (match[2] === void 0 || match[2] === "")) {
24131
- throw new SyntaxError(`invalid usd value: ${JSON.stringify(usd)}`);
24132
- }
24133
- const intPart = match[1] || "0";
24134
- const fracPart = match[2] ?? "";
24135
- if (fracPart.length <= decimals) {
24136
- return BigInt(intPart + fracPart.padEnd(decimals, "0"));
24137
- }
24138
- const kept = fracPart.slice(0, decimals);
24139
- const roundDigit = fracPart[decimals];
24140
- let result = BigInt(intPart + kept);
24141
- if (roundDigit >= "5") {
24142
- result += 1n;
24143
- }
24144
- return result;
24145
- }
24146
- function formatUsdCents(cents, decimals = 2) {
24147
- return (cents / 100).toFixed(decimals);
24148
- }
24994
+ // src/payment/index.ts
24995
+ init_amounts();
24149
24996
 
24150
24997
  // src/payment/solana.ts
24151
24998
  async function loadSolanaFeePayer(opts) {
@@ -24169,6 +25016,7 @@ async function loadSolanaFeePayer(opts) {
24169
25016
  }
24170
25017
 
24171
25018
  // src/payment/compose_rails.ts
25019
+ init_amounts();
24172
25020
  init_usdc();
24173
25021
  var warnedStripeBelowMinimum = false;
24174
25022
  function buildMppxComposeRails(opts) {
@@ -24213,7 +25061,13 @@ init_usdc();
24213
25061
  function buildDefaultCheckoutRails(opts) {
24214
25062
  const out = {};
24215
25063
  if (opts.tempo) {
24216
- out.tempo = { recipient: "", ...RAIL_SPEC_DEFAULTS.tempo, ...opts.tempo };
25064
+ const merged = { recipient: "", ...RAIL_SPEC_DEFAULTS.tempo, ...opts.tempo };
25065
+ if (merged.testnet) {
25066
+ if (opts.tempo.network === void 0) merged.network = "tempo-testnet";
25067
+ if (opts.tempo.chainId === void 0) merged.chainId = 42431;
25068
+ if (opts.tempo.token === void 0) merged.token = USDC.tempo.testnet.address;
25069
+ }
25070
+ out.tempo = merged;
24217
25071
  }
24218
25072
  if (opts.x402Base) {
24219
25073
  const merged = { recipient: "", ...RAIL_SPEC_DEFAULTS.x402Base, ...opts.x402Base };
@@ -24268,6 +25122,9 @@ function buildSuccessNextSteps(opts) {
24268
25122
  // src/discovery/index.ts
24269
25123
  init_well_known();
24270
25124
 
25125
+ // src/checkout_compute_first.ts
25126
+ init_amounts();
25127
+
24271
25128
  // src/quote_cache.ts
24272
25129
  var import_crypto = require("crypto");
24273
25130
 
@@ -24837,15 +25694,26 @@ function defaultReadOnlyOnDenied(reason) {
24837
25694
  0 && (module.exports = {
24838
25695
  A2A_DEFAULT_TRANSPORT,
24839
25696
  A2A_PROTOCOL_VERSION,
25697
+ AGENTSCORE_CANONICAL_ISSUER,
24840
25698
  AGENTSCORE_UCP_CAPABILITY,
25699
+ AGENT_IDENTITY_HEADER,
25700
+ AIP_COVERED_COMPONENTS,
25701
+ AIP_SIGNATURE_TAG,
24841
25702
  Checkout,
24842
25703
  CheckoutValidationError,
24843
25704
  FIXABLE_DENIAL_REASONS,
25705
+ HARD_MAX_CACHE_SECONDS,
25706
+ JWKS_WELL_KNOWN_PATH,
25707
+ JwksCache,
24844
25708
  UCPSigningKey,
24845
25709
  UCPVerificationError,
24846
25710
  UCP_A2A_EXTENSION_URI,
25711
+ aipErrorCode,
25712
+ aipErrorStatus,
24847
25713
  buildA2AAgentCard,
24848
25714
  buildAgentMemoryHint,
25715
+ buildAipErrorBody,
25716
+ buildAipTrustedIssuers,
24849
25717
  buildContactSupportNextSteps,
24850
25718
  buildDefaultCheckoutRails,
24851
25719
  buildGateFromPolicy,
@@ -24854,6 +25722,8 @@ function defaultReadOnlyOnDenied(reason) {
24854
25722
  buildSignerMismatchBody,
24855
25723
  buildUCPProfile,
24856
25724
  buildVerificationRequiredBody,
25725
+ buildVerifyContextFromRequest,
25726
+ canonicalizeIssuer,
24857
25727
  computeFirstCheckout,
24858
25728
  createDefaultOnDenied,
24859
25729
  createQuoteCache,
@@ -24867,11 +25737,15 @@ function defaultReadOnlyOnDenied(reason) {
24867
25737
  formatUsdCents,
24868
25738
  generateUCPSigningKey,
24869
25739
  getIdentityStatus,
25740
+ hasAgentIdentityHeader,
24870
25741
  hasMppxHeader,
24871
25742
  hasPaymentHeader,
24872
25743
  hasX402Header,
24873
25744
  hashOperatorToken,
25745
+ isAitShape,
25746
+ isEvmNetwork,
24874
25747
  isFixableDenial,
25748
+ isSolanaNetwork,
24875
25749
  loadSolanaFeePayer,
24876
25750
  loadUCPSigningKeyFromEnv,
24877
25751
  makeMppxComposeHook,
@@ -24881,9 +25755,11 @@ function defaultReadOnlyOnDenied(reason) {
24881
25755
  runGateWithEnforcement,
24882
25756
  shippingCountryAllowed,
24883
25757
  shippingStateAllowed,
25758
+ signMessage,
24884
25759
  signUCPProfile,
24885
25760
  stripeSptPaymentHandler,
24886
25761
  ucpA2AExtension,
25762
+ validateAitPayload,
24887
25763
  validateShippingAgainstPolicy,
24888
25764
  validationEnvelope,
24889
25765
  validationResponseExpress,
@@ -24892,6 +25768,9 @@ function defaultReadOnlyOnDenied(reason) {
24892
25768
  validationResponseNextjs,
24893
25769
  validationResponseWeb,
24894
25770
  verificationAgentInstructions,
25771
+ verifyAit,
25772
+ verifyAitRequest,
25773
+ verifyMessageSignature,
24895
25774
  verifyUCPProfile,
24896
25775
  x402PaymentHandler
24897
25776
  });