@agent-score/commerce 2.4.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 (59) hide show
  1. package/dist/challenge/index.d.mts +5 -1
  2. package/dist/challenge/index.d.ts +5 -1
  3. package/dist/challenge/index.js +11 -4
  4. package/dist/challenge/index.js.map +1 -1
  5. package/dist/challenge/index.mjs +11 -4
  6. package/dist/challenge/index.mjs.map +1 -1
  7. package/dist/{checkout-B-MIzYzW.d.ts → checkout-McfNpZJf.d.ts} +72 -1
  8. package/dist/{checkout-Bn7ZKIBD.d.mts → checkout-o17dIxHi.d.mts} +72 -1
  9. package/dist/core.d.mts +23 -1
  10. package/dist/core.d.ts +23 -1
  11. package/dist/core.js +25 -11
  12. package/dist/core.js.map +1 -1
  13. package/dist/core.mjs +25 -11
  14. package/dist/core.mjs.map +1 -1
  15. package/dist/discovery/index.d.mts +17 -2
  16. package/dist/discovery/index.d.ts +17 -2
  17. package/dist/discovery/index.js +14 -4
  18. package/dist/discovery/index.js.map +1 -1
  19. package/dist/discovery/index.mjs +14 -4
  20. package/dist/discovery/index.mjs.map +1 -1
  21. package/dist/gate-CWP10xPQ.d.mts +339 -0
  22. package/dist/gate-CWP10xPQ.d.ts +339 -0
  23. package/dist/identity/express.d.mts +26 -1
  24. package/dist/identity/express.d.ts +26 -1
  25. package/dist/identity/express.js +587 -13
  26. package/dist/identity/express.js.map +1 -1
  27. package/dist/identity/express.mjs +583 -12
  28. package/dist/identity/express.mjs.map +1 -1
  29. package/dist/identity/fastify.d.mts +12 -2
  30. package/dist/identity/fastify.d.ts +12 -2
  31. package/dist/identity/fastify.js +595 -13
  32. package/dist/identity/fastify.js.map +1 -1
  33. package/dist/identity/fastify.mjs +591 -12
  34. package/dist/identity/fastify.mjs.map +1 -1
  35. package/dist/identity/hono.d.mts +26 -1
  36. package/dist/identity/hono.d.ts +26 -1
  37. package/dist/identity/hono.js +576 -13
  38. package/dist/identity/hono.js.map +1 -1
  39. package/dist/identity/hono.mjs +572 -12
  40. package/dist/identity/hono.mjs.map +1 -1
  41. package/dist/identity/nextjs.d.mts +3 -0
  42. package/dist/identity/nextjs.d.ts +3 -0
  43. package/dist/identity/nextjs.js +581 -13
  44. package/dist/identity/nextjs.js.map +1 -1
  45. package/dist/identity/nextjs.mjs +577 -12
  46. package/dist/identity/nextjs.mjs.map +1 -1
  47. package/dist/identity/web.d.mts +24 -1
  48. package/dist/identity/web.d.ts +24 -1
  49. package/dist/identity/web.js +581 -13
  50. package/dist/identity/web.js.map +1 -1
  51. package/dist/identity/web.mjs +577 -12
  52. package/dist/identity/web.mjs.map +1 -1
  53. package/dist/index.d.mts +119 -3
  54. package/dist/index.d.ts +119 -3
  55. package/dist/index.js +893 -35
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.mjs +873 -35
  58. package/dist/index.mjs.map +1 -1
  59. package/package.json +11 -11
package/dist/index.js CHANGED
@@ -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",
@@ -20857,15 +20857,26 @@ var index_exports = {};
20857
20857
  __export(index_exports, {
20858
20858
  A2A_DEFAULT_TRANSPORT: () => A2A_DEFAULT_TRANSPORT,
20859
20859
  A2A_PROTOCOL_VERSION: () => A2A_PROTOCOL_VERSION,
20860
+ AGENTSCORE_CANONICAL_ISSUER: () => AGENTSCORE_CANONICAL_ISSUER,
20860
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,
20861
20865
  Checkout: () => Checkout,
20862
20866
  CheckoutValidationError: () => CheckoutValidationError,
20863
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,
20864
20871
  UCPSigningKey: () => UCPSigningKey,
20865
20872
  UCPVerificationError: () => UCPVerificationError,
20866
20873
  UCP_A2A_EXTENSION_URI: () => UCP_A2A_EXTENSION_URI,
20874
+ aipErrorCode: () => aipErrorCode,
20875
+ aipErrorStatus: () => aipErrorStatus,
20867
20876
  buildA2AAgentCard: () => buildA2AAgentCard,
20868
20877
  buildAgentMemoryHint: () => buildAgentMemoryHint,
20878
+ buildAipErrorBody: () => buildAipErrorBody,
20879
+ buildAipTrustedIssuers: () => buildAipTrustedIssuers,
20869
20880
  buildContactSupportNextSteps: () => buildContactSupportNextSteps,
20870
20881
  buildDefaultCheckoutRails: () => buildDefaultCheckoutRails,
20871
20882
  buildGateFromPolicy: () => buildGateFromPolicy,
@@ -20874,6 +20885,8 @@ __export(index_exports, {
20874
20885
  buildSignerMismatchBody: () => buildSignerMismatchBody,
20875
20886
  buildUCPProfile: () => buildUCPProfile,
20876
20887
  buildVerificationRequiredBody: () => buildVerificationRequiredBody,
20888
+ buildVerifyContextFromRequest: () => buildVerifyContextFromRequest,
20889
+ canonicalizeIssuer: () => canonicalizeIssuer,
20877
20890
  computeFirstCheckout: () => computeFirstCheckout,
20878
20891
  createDefaultOnDenied: () => createDefaultOnDenied,
20879
20892
  createQuoteCache: () => createQuoteCache,
@@ -20887,10 +20900,12 @@ __export(index_exports, {
20887
20900
  formatUsdCents: () => formatUsdCents,
20888
20901
  generateUCPSigningKey: () => generateUCPSigningKey,
20889
20902
  getIdentityStatus: () => getIdentityStatus,
20903
+ hasAgentIdentityHeader: () => hasAgentIdentityHeader,
20890
20904
  hasMppxHeader: () => hasMppxHeader,
20891
20905
  hasPaymentHeader: () => hasPaymentHeader,
20892
20906
  hasX402Header: () => hasX402Header,
20893
20907
  hashOperatorToken: () => hashOperatorToken,
20908
+ isAitShape: () => isAitShape,
20894
20909
  isEvmNetwork: () => isEvmNetwork,
20895
20910
  isFixableDenial: () => isFixableDenial,
20896
20911
  isSolanaNetwork: () => isSolanaNetwork,
@@ -20903,9 +20918,11 @@ __export(index_exports, {
20903
20918
  runGateWithEnforcement: () => runGateWithEnforcement,
20904
20919
  shippingCountryAllowed: () => shippingCountryAllowed,
20905
20920
  shippingStateAllowed: () => shippingStateAllowed,
20921
+ signMessage: () => signMessage,
20906
20922
  signUCPProfile: () => signUCPProfile,
20907
20923
  stripeSptPaymentHandler: () => stripeSptPaymentHandler,
20908
20924
  ucpA2AExtension: () => ucpA2AExtension,
20925
+ validateAitPayload: () => validateAitPayload,
20909
20926
  validateShippingAgainstPolicy: () => validateShippingAgainstPolicy,
20910
20927
  validationEnvelope: () => validationEnvelope,
20911
20928
  validationResponseExpress: () => validationResponseExpress,
@@ -20914,12 +20931,16 @@ __export(index_exports, {
20914
20931
  validationResponseNextjs: () => validationResponseNextjs,
20915
20932
  validationResponseWeb: () => validationResponseWeb,
20916
20933
  verificationAgentInstructions: () => verificationAgentInstructions,
20934
+ verifyAit: () => verifyAit,
20935
+ verifyAitRequest: () => verifyAitRequest,
20936
+ verifyMessageSignature: () => verifyMessageSignature,
20917
20937
  verifyUCPProfile: () => verifyUCPProfile,
20918
20938
  x402PaymentHandler: () => x402PaymentHandler
20919
20939
  });
20920
20940
  module.exports = __toCommonJS(index_exports);
20921
20941
 
20922
20942
  // src/core.ts
20943
+ var import_node_crypto = require("crypto");
20923
20944
  var import_sdk = require("@agent-score/sdk");
20924
20945
 
20925
20946
  // src/_denial.ts
@@ -21235,8 +21256,9 @@ var INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({
21235
21256
  ],
21236
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."
21237
21258
  });
21238
- function buildAgentMemoryHint() {
21259
+ function buildAgentMemoryHint(aipTrustedIssuers) {
21239
21260
  const api = CANONICAL_AGENTSCORE_API;
21261
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
21240
21262
  return {
21241
21263
  save_for_future_agentscore_gates: true,
21242
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.",
@@ -21244,8 +21266,12 @@ function buildAgentMemoryHint() {
21244
21266
  identity_check_endpoint: `${api}/v1/credentials`,
21245
21267
  identity_paths: {
21246
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.",
21247
- 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
+ }
21248
21273
  },
21274
+ ...acceptsAip && { aip_trusted_issuers: aipTrustedIssuers },
21249
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.",
21250
21276
  do_not_persist_in_memory: ["operator_token", "poll_secret"],
21251
21277
  persist_in_credential_store: ["operator_token"]
@@ -21267,11 +21293,12 @@ function createAgentScoreCore(options) {
21267
21293
  baseUrl: rawBaseUrl = "https://api.agentscore.sh",
21268
21294
  chain: gateChain,
21269
21295
  userAgent,
21270
- createSessionOnMissing
21296
+ createSessionOnMissing,
21297
+ aipTrustedIssuers
21271
21298
  } = options;
21272
21299
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21273
- const agentMemoryHint = buildAgentMemoryHint();
21274
- const defaultUa = `@agent-score/commerce@${"2.4.0"}`;
21300
+ const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
21301
+ const defaultUa = `@agent-score/commerce@${"2.5.0"}`;
21275
21302
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21276
21303
  const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21277
21304
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21289,6 +21316,7 @@ function createAgentScoreCore(options) {
21289
21316
  return s;
21290
21317
  }
21291
21318
  const cache = new TTLCache(cacheSeconds * 1e3);
21319
+ const lastSignerRaw = /* @__PURE__ */ new Map();
21292
21320
  async function tryMintSessionDenial(ctx) {
21293
21321
  if (!createSessionOnMissing) return void 0;
21294
21322
  try {
@@ -21346,13 +21374,18 @@ function createAgentScoreCore(options) {
21346
21374
  }
21347
21375
  }
21348
21376
  async function evaluate(identity, ctx, signer) {
21349
- if (!identity || !identity.address && !identity.operatorToken) {
21377
+ if (!identity || !identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim()) {
21350
21378
  if (failOpen) return { kind: "allow" };
21351
21379
  const sessionReason = await tryMintSessionDenial(ctx);
21352
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
+ ] : [];
21353
21385
  const missingIdentityInstructions = JSON.stringify({
21354
21386
  action: "probe_identity_then_session",
21355
21387
  steps: [
21388
+ ...aipStep,
21356
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.",
21357
21390
  "If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
21358
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."
@@ -21368,7 +21401,7 @@ function createAgentScoreCore(options) {
21368
21401
  }
21369
21402
  };
21370
21403
  }
21371
- 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) : "");
21372
21405
  const cached2 = cache.get(cacheKey2);
21373
21406
  if (cached2) {
21374
21407
  if (cached2.allow) {
@@ -21413,7 +21446,7 @@ function createAgentScoreCore(options) {
21413
21446
  // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
21414
21447
  ...signer && { signer: { address: signer.address, network: signer.network } }
21415
21448
  };
21416
- 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 });
21417
21450
  data = result;
21418
21451
  } catch (err) {
21419
21452
  if (err instanceof import_sdk.PaymentRequiredError) {
@@ -21484,6 +21517,9 @@ function createAgentScoreCore(options) {
21484
21517
  const decisionReasons = data.decision_reasons ?? [];
21485
21518
  const allow = decision === "allow" || decision == null;
21486
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
+ }
21487
21523
  if (allow) {
21488
21524
  const quota = data.quota;
21489
21525
  return {
@@ -21548,9 +21584,7 @@ function createAgentScoreCore(options) {
21548
21584
  }
21549
21585
  function getSignerVerdict(claimedAddress) {
21550
21586
  const claimedNorm = normalizeAddress(claimedAddress);
21551
- const cached2 = cache.get(claimedNorm);
21552
- if (!cached2) return void 0;
21553
- const raw = cached2.raw;
21587
+ const raw = lastSignerRaw.get(claimedNorm) ?? cache.get(claimedNorm)?.raw;
21554
21588
  if (!raw) return void 0;
21555
21589
  const rawMatch = raw.signer_match;
21556
21590
  const rawSanctions = raw.signer_sanctions;
@@ -21813,7 +21847,7 @@ function validateShippingAgainstPolicy(opts) {
21813
21847
  }
21814
21848
 
21815
21849
  // src/identity/tokens.ts
21816
- var import_node_crypto = require("crypto");
21850
+ var import_node_crypto2 = require("crypto");
21817
21851
 
21818
21852
  // src/payment/payment_header.ts
21819
21853
  function toTitleCase(name) {
@@ -21849,7 +21883,7 @@ function hasMppxHeader(input) {
21849
21883
 
21850
21884
  // src/identity/tokens.ts
21851
21885
  function hashOperatorToken(plaintext) {
21852
- 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");
21853
21887
  }
21854
21888
  function extractOwnerScope(input) {
21855
21889
  const headers = asHeaders(input);
@@ -21862,7 +21896,7 @@ function extractOwnerScope(input) {
21862
21896
  }
21863
21897
 
21864
21898
  // src/checkout.ts
21865
- var import_node_crypto2 = require("crypto");
21899
+ var import_node_crypto3 = require("crypto");
21866
21900
 
21867
21901
  // src/_mppx_receipt.ts
21868
21902
  function extractMppxReceiptHeaderFromRaw(raw) {
@@ -21902,6 +21936,710 @@ function warnMissingApiKeyOnce(label) {
21902
21936
  );
21903
21937
  }
21904
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
+
21905
22643
  // src/payment/rail_spec.ts
21906
22644
  init_usdc();
21907
22645
  async function resolveRecipient(r) {
@@ -22054,10 +22792,11 @@ function buildAgentInstructions({
22054
22792
 
22055
22793
  // src/challenge/agent_memory.ts
22056
22794
  function firstEncounterAgentMemory({
22057
- firstEncounter
22795
+ firstEncounter,
22796
+ aipTrustedIssuers
22058
22797
  }) {
22059
22798
  if (!firstEncounter) return void 0;
22060
- return buildAgentMemoryHint();
22799
+ return buildAgentMemoryHint(aipTrustedIssuers);
22061
22800
  }
22062
22801
 
22063
22802
  // src/challenge/body.ts
@@ -23089,6 +23828,30 @@ function pickRail(rails2, key) {
23089
23828
  const spec = rails2[key];
23090
23829
  return spec === void 0 ? void 0 : spec;
23091
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
+ }
23092
23855
  var Checkout = class {
23093
23856
  rails;
23094
23857
  url;
@@ -23106,6 +23869,15 @@ var Checkout = class {
23106
23869
  discoveryExtensions;
23107
23870
  discoveryProbe;
23108
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
+ }
23109
23881
  /**
23110
23882
  * True when the merchant has configured an identity-bearing policy flag —
23111
23883
  * `require_kyc`, `require_sanctions_clear` (name screening on the KYC
@@ -23393,7 +24165,64 @@ var Checkout = class {
23393
24165
  }
23394
24166
  return result;
23395
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
+ };
23396
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
+ }
23397
24226
  return this.runWalletSanctionsOnly(ctx);
23398
24227
  }
23399
24228
  let policyOverride;
@@ -23405,14 +24234,21 @@ var Checkout = class {
23405
24234
  apiKey: gate.apiKey,
23406
24235
  ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
23407
24236
  ...gate.userAgent !== void 0 && { userAgent: gate.userAgent },
23408
- ...gate.requireKyc !== void 0 && { requireKyc: gate.requireKyc },
23409
- ...gate.requireSanctionsClear !== void 0 && { requireSanctionsClear: gate.requireSanctionsClear },
23410
- ...gate.minAge !== void 0 && { minAge: gate.minAge },
23411
- ...gate.blockedJurisdictions !== void 0 && { blockedJurisdictions: gate.blockedJurisdictions },
23412
- ...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 },
23413
24246
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23414
24247
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23415
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) },
23416
24252
  // Auto-default `createSessionOnMissing` from gate config when the merchant
23417
24253
  // didn't supply one, so every gated route gets the bootstrap session-mint UX
23418
24254
  // out of the box. Merchants who need custom session context or onBeforeSession
@@ -23426,10 +24262,7 @@ var Checkout = class {
23426
24262
  ...policyOverride ?? {}
23427
24263
  };
23428
24264
  const core = createAgentScoreCore(coreOpts);
23429
- const headers = normalizeHeadersToLowercase(ctx.request.headers);
23430
- const walletAddress = headers["x-wallet-address"];
23431
- const operatorToken = headers["x-operator-token"];
23432
- const identity = walletAddress !== void 0 || operatorToken !== void 0 ? {
24265
+ const identity = aipToken !== void 0 ? { aipToken } : walletAddress !== void 0 || operatorToken !== void 0 ? {
23433
24266
  ...walletAddress !== void 0 && { address: walletAddress },
23434
24267
  ...operatorToken !== void 0 && { operatorToken }
23435
24268
  } : void 0;
@@ -23448,7 +24281,7 @@ var Checkout = class {
23448
24281
  });
23449
24282
  };
23450
24283
  }
23451
- if (walletAddress !== void 0) {
24284
+ if (aipToken === void 0 && walletAddress !== void 0) {
23452
24285
  const verdict = core.getSignerVerdict(walletAddress);
23453
24286
  const sm = verdict?.signer_match;
23454
24287
  if (sm && sm.kind !== "pass") {
@@ -23570,7 +24403,7 @@ var Checkout = class {
23570
24403
  return await this.buildSuccess(ctx, outcome);
23571
24404
  }
23572
24405
  async mintRefId(request) {
23573
- if (this.mintReferenceId === void 0) return (0, import_node_crypto2.randomUUID)();
24406
+ if (this.mintReferenceId === void 0) return (0, import_node_crypto3.randomUUID)();
23574
24407
  const seedCtx = { request, referenceId: "", pricing: null, recipients: {}, state: {} };
23575
24408
  return await this.mintReferenceId(seedCtx);
23576
24409
  }
@@ -23793,8 +24626,13 @@ var Checkout = class {
23793
24626
  retryBody: ctx.request.body,
23794
24627
  // Merchants without an identity-bearing gate get a clean 402: no
23795
24628
  // AgentScore-identity bootstrap describing a verification flow they
23796
- // don't run. Wallet OFAC (the always-on default) doesn't need it.
23797
- 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
+ }),
23798
24636
  ...ctx.pricing.product ? { product: ctx.pricing.product } : {},
23799
24637
  ...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
23800
24638
  ...x402Accepts.length > 0 ? {
@@ -24856,15 +25694,26 @@ function defaultReadOnlyOnDenied(reason) {
24856
25694
  0 && (module.exports = {
24857
25695
  A2A_DEFAULT_TRANSPORT,
24858
25696
  A2A_PROTOCOL_VERSION,
25697
+ AGENTSCORE_CANONICAL_ISSUER,
24859
25698
  AGENTSCORE_UCP_CAPABILITY,
25699
+ AGENT_IDENTITY_HEADER,
25700
+ AIP_COVERED_COMPONENTS,
25701
+ AIP_SIGNATURE_TAG,
24860
25702
  Checkout,
24861
25703
  CheckoutValidationError,
24862
25704
  FIXABLE_DENIAL_REASONS,
25705
+ HARD_MAX_CACHE_SECONDS,
25706
+ JWKS_WELL_KNOWN_PATH,
25707
+ JwksCache,
24863
25708
  UCPSigningKey,
24864
25709
  UCPVerificationError,
24865
25710
  UCP_A2A_EXTENSION_URI,
25711
+ aipErrorCode,
25712
+ aipErrorStatus,
24866
25713
  buildA2AAgentCard,
24867
25714
  buildAgentMemoryHint,
25715
+ buildAipErrorBody,
25716
+ buildAipTrustedIssuers,
24868
25717
  buildContactSupportNextSteps,
24869
25718
  buildDefaultCheckoutRails,
24870
25719
  buildGateFromPolicy,
@@ -24873,6 +25722,8 @@ function defaultReadOnlyOnDenied(reason) {
24873
25722
  buildSignerMismatchBody,
24874
25723
  buildUCPProfile,
24875
25724
  buildVerificationRequiredBody,
25725
+ buildVerifyContextFromRequest,
25726
+ canonicalizeIssuer,
24876
25727
  computeFirstCheckout,
24877
25728
  createDefaultOnDenied,
24878
25729
  createQuoteCache,
@@ -24886,10 +25737,12 @@ function defaultReadOnlyOnDenied(reason) {
24886
25737
  formatUsdCents,
24887
25738
  generateUCPSigningKey,
24888
25739
  getIdentityStatus,
25740
+ hasAgentIdentityHeader,
24889
25741
  hasMppxHeader,
24890
25742
  hasPaymentHeader,
24891
25743
  hasX402Header,
24892
25744
  hashOperatorToken,
25745
+ isAitShape,
24893
25746
  isEvmNetwork,
24894
25747
  isFixableDenial,
24895
25748
  isSolanaNetwork,
@@ -24902,9 +25755,11 @@ function defaultReadOnlyOnDenied(reason) {
24902
25755
  runGateWithEnforcement,
24903
25756
  shippingCountryAllowed,
24904
25757
  shippingStateAllowed,
25758
+ signMessage,
24905
25759
  signUCPProfile,
24906
25760
  stripeSptPaymentHandler,
24907
25761
  ucpA2AExtension,
25762
+ validateAitPayload,
24908
25763
  validateShippingAgainstPolicy,
24909
25764
  validationEnvelope,
24910
25765
  validationResponseExpress,
@@ -24913,6 +25768,9 @@ function defaultReadOnlyOnDenied(reason) {
24913
25768
  validationResponseNextjs,
24914
25769
  validationResponseWeb,
24915
25770
  verificationAgentInstructions,
25771
+ verifyAit,
25772
+ verifyAitRequest,
25773
+ verifyMessageSignature,
24916
25774
  verifyUCPProfile,
24917
25775
  x402PaymentHandler
24918
25776
  });