@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.mjs CHANGED
@@ -581,12 +581,12 @@ async function buildEnvSigningKey(opts) {
581
581
  );
582
582
  }
583
583
  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 };
584
- const { importJWK } = await import("jose");
584
+ const { importJWK: importJWK3 } = await import("jose");
585
585
  const { createPublicKey } = await import("crypto");
586
586
  let privateKey;
587
587
  let publicNodeKey;
588
588
  try {
589
- privateKey = await importJWK(
589
+ privateKey = await importJWK3(
590
590
  canonicalPrivateJwk,
591
591
  detectedAlg
592
592
  );
@@ -7949,13 +7949,13 @@ var init_schemas = __esm({
7949
7949
  }
7950
7950
  return propValues;
7951
7951
  });
7952
- const isObject2 = isObject;
7952
+ const isObject3 = isObject;
7953
7953
  const catchall2 = def.catchall;
7954
7954
  let value;
7955
7955
  inst._zod.parse = (payload, ctx) => {
7956
7956
  value ?? (value = _normalized.value);
7957
7957
  const input = payload.value;
7958
- if (!isObject2(input)) {
7958
+ if (!isObject3(input)) {
7959
7959
  payload.issues.push({
7960
7960
  expected: "object",
7961
7961
  code: "invalid_type",
@@ -8082,7 +8082,7 @@ var init_schemas = __esm({
8082
8082
  return (payload, ctx) => fn(shape, payload, ctx);
8083
8083
  };
8084
8084
  let fastpass;
8085
- const isObject2 = isObject;
8085
+ const isObject3 = isObject;
8086
8086
  const jit = !globalConfig.jitless;
8087
8087
  const allowsEval2 = allowsEval;
8088
8088
  const fastEnabled = jit && allowsEval2.value;
@@ -8091,7 +8091,7 @@ var init_schemas = __esm({
8091
8091
  inst._zod.parse = (payload, ctx) => {
8092
8092
  value ?? (value = _normalized.value);
8093
8093
  const input = payload.value;
8094
- if (!isObject2(input)) {
8094
+ if (!isObject3(input)) {
8095
8095
  payload.issues.push({
8096
8096
  expected: "object",
8097
8097
  code: "invalid_type",
@@ -20851,6 +20851,7 @@ var init_well_known = __esm({
20851
20851
  });
20852
20852
 
20853
20853
  // src/core.ts
20854
+ import { createHash } from "crypto";
20854
20855
  import {
20855
20856
  AgentScore,
20856
20857
  InvalidCredentialError,
@@ -21173,8 +21174,9 @@ var INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({
21173
21174
  ],
21174
21175
  user_message: "The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one."
21175
21176
  });
21176
- function buildAgentMemoryHint() {
21177
+ function buildAgentMemoryHint(aipTrustedIssuers) {
21177
21178
  const api = CANONICAL_AGENTSCORE_API;
21179
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
21178
21180
  return {
21179
21181
  save_for_future_agentscore_gates: true,
21180
21182
  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.",
@@ -21182,8 +21184,12 @@ function buildAgentMemoryHint() {
21182
21184
  identity_check_endpoint: `${api}/v1/credentials`,
21183
21185
  identity_paths: {
21184
21186
  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.",
21185
- 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."
21187
+ 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.",
21188
+ ...acceptsAip && {
21189
+ 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.'
21190
+ }
21186
21191
  },
21192
+ ...acceptsAip && { aip_trusted_issuers: aipTrustedIssuers },
21187
21193
  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.",
21188
21194
  do_not_persist_in_memory: ["operator_token", "poll_secret"],
21189
21195
  persist_in_credential_store: ["operator_token"]
@@ -21205,11 +21211,12 @@ function createAgentScoreCore(options) {
21205
21211
  baseUrl: rawBaseUrl = "https://api.agentscore.sh",
21206
21212
  chain: gateChain,
21207
21213
  userAgent,
21208
- createSessionOnMissing
21214
+ createSessionOnMissing,
21215
+ aipTrustedIssuers
21209
21216
  } = options;
21210
21217
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
21211
- const agentMemoryHint = buildAgentMemoryHint();
21212
- const defaultUa = `@agent-score/commerce@${"2.4.0"}`;
21218
+ const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
21219
+ const defaultUa = `@agent-score/commerce@${"2.5.0"}`;
21213
21220
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
21214
21221
  const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
21215
21222
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -21227,6 +21234,7 @@ function createAgentScoreCore(options) {
21227
21234
  return s;
21228
21235
  }
21229
21236
  const cache = new TTLCache(cacheSeconds * 1e3);
21237
+ const lastSignerRaw = /* @__PURE__ */ new Map();
21230
21238
  async function tryMintSessionDenial(ctx) {
21231
21239
  if (!createSessionOnMissing) return void 0;
21232
21240
  try {
@@ -21284,13 +21292,18 @@ function createAgentScoreCore(options) {
21284
21292
  }
21285
21293
  }
21286
21294
  async function evaluate(identity, ctx, signer) {
21287
- if (!identity || !identity.address && !identity.operatorToken) {
21295
+ if (!identity || !identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim()) {
21288
21296
  if (failOpen) return { kind: "allow" };
21289
21297
  const sessionReason = await tryMintSessionDenial(ctx);
21290
21298
  if (sessionReason) return { kind: "deny", reason: sessionReason };
21299
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
21300
+ const aipStep = acceptsAip ? [
21301
+ `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.`
21302
+ ] : [];
21291
21303
  const missingIdentityInstructions = JSON.stringify({
21292
21304
  action: "probe_identity_then_session",
21293
21305
  steps: [
21306
+ ...aipStep,
21294
21307
  "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.",
21295
21308
  "If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
21296
21309
  "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."
@@ -21306,7 +21319,7 @@ function createAgentScoreCore(options) {
21306
21319
  }
21307
21320
  };
21308
21321
  }
21309
- const cacheKey2 = identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
21322
+ const cacheKey2 = identity.aipToken ? `aip:${createHash("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
21310
21323
  const cached2 = cache.get(cacheKey2);
21311
21324
  if (cached2) {
21312
21325
  if (cached2.allow) {
@@ -21351,7 +21364,7 @@ function createAgentScoreCore(options) {
21351
21364
  // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
21352
21365
  ...signer && { signer: { address: signer.address, network: signer.network } }
21353
21366
  };
21354
- const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
21367
+ 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 });
21355
21368
  data = result;
21356
21369
  } catch (err) {
21357
21370
  if (err instanceof PaymentRequiredError) {
@@ -21422,6 +21435,9 @@ function createAgentScoreCore(options) {
21422
21435
  const decisionReasons = data.decision_reasons ?? [];
21423
21436
  const allow = decision === "allow" || decision == null;
21424
21437
  cache.set(cacheKey2, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
21438
+ if (identity.address !== void 0 && identity.operatorToken === void 0 && identity.aipToken === void 0 && (data.signer_match !== void 0 || data.signer_sanctions !== void 0)) {
21439
+ lastSignerRaw.set(normalizeAddress(identity.address), data);
21440
+ }
21425
21441
  if (allow) {
21426
21442
  const quota = data.quota;
21427
21443
  return {
@@ -21486,9 +21502,7 @@ function createAgentScoreCore(options) {
21486
21502
  }
21487
21503
  function getSignerVerdict(claimedAddress) {
21488
21504
  const claimedNorm = normalizeAddress(claimedAddress);
21489
- const cached2 = cache.get(claimedNorm);
21490
- if (!cached2) return void 0;
21491
- const raw = cached2.raw;
21505
+ const raw = lastSignerRaw.get(claimedNorm) ?? cache.get(claimedNorm)?.raw;
21492
21506
  if (!raw) return void 0;
21493
21507
  const rawMatch = raw.signer_match;
21494
21508
  const rawSanctions = raw.signer_sanctions;
@@ -21751,7 +21765,7 @@ function validateShippingAgainstPolicy(opts) {
21751
21765
  }
21752
21766
 
21753
21767
  // src/identity/tokens.ts
21754
- import { createHash } from "crypto";
21768
+ import { createHash as createHash2 } from "crypto";
21755
21769
 
21756
21770
  // src/payment/payment_header.ts
21757
21771
  function toTitleCase(name) {
@@ -21787,7 +21801,7 @@ function hasMppxHeader(input) {
21787
21801
 
21788
21802
  // src/identity/tokens.ts
21789
21803
  function hashOperatorToken(plaintext) {
21790
- return createHash("sha256").update(plaintext, "utf8").digest("hex");
21804
+ return createHash2("sha256").update(plaintext, "utf8").digest("hex");
21791
21805
  }
21792
21806
  function extractOwnerScope(input) {
21793
21807
  const headers = asHeaders(input);
@@ -21840,6 +21854,710 @@ function warnMissingApiKeyOnce(label) {
21840
21854
  );
21841
21855
  }
21842
21856
 
21857
+ // src/aip/verify.ts
21858
+ import { decodeJwt, decodeProtectedHeader, importJWK as importJWK2, jwtVerify } from "jose";
21859
+
21860
+ // src/aip/http-signature.ts
21861
+ import { calculateJwkThumbprint, importJWK } from "jose";
21862
+ var { subtle } = globalThis.crypto;
21863
+ var b64ToBytes = (b64) => {
21864
+ const bin = atob(b64);
21865
+ const out = new Uint8Array(bin.length);
21866
+ for (let i = 0; i < bin.length; i++) {
21867
+ out[i] = bin.charCodeAt(i);
21868
+ }
21869
+ return out;
21870
+ };
21871
+ var bytesToB64 = (bytes) => {
21872
+ let bin = "";
21873
+ for (let i = 0; i < bytes.length; i++) {
21874
+ bin += String.fromCharCode(bytes[i]);
21875
+ }
21876
+ return btoa(bin);
21877
+ };
21878
+ var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
21879
+ var AIP_SIGNATURE_TAG = "agent-identity";
21880
+ var DEFAULT_MAX_SKEW_SECONDS = 60;
21881
+ var normalizeAuthority = (authority) => {
21882
+ const lower = authority.trim().toLowerCase();
21883
+ const colon = lower.lastIndexOf(":");
21884
+ if (colon === -1) {
21885
+ return lower;
21886
+ }
21887
+ if (lower.includes("]") && colon < lower.indexOf("]")) {
21888
+ return lower;
21889
+ }
21890
+ const host = lower.slice(0, colon);
21891
+ const port = lower.slice(colon + 1);
21892
+ if (port === "80" || port === "443") {
21893
+ return host;
21894
+ }
21895
+ return lower;
21896
+ };
21897
+ var componentValue = (name, input) => {
21898
+ switch (name) {
21899
+ case "@method":
21900
+ return input.method.toUpperCase();
21901
+ case "@authority":
21902
+ return normalizeAuthority(input.authority);
21903
+ case "@path":
21904
+ return input.path;
21905
+ case "agent-identity":
21906
+ return input.agentIdentity.trim();
21907
+ default:
21908
+ return input.extra?.[name] ?? null;
21909
+ }
21910
+ };
21911
+ var serializeComponentList = (components) => `(${components.map((c) => `"${c}"`).join(" ")})`;
21912
+ var serializeParams = (p) => {
21913
+ const parts = [];
21914
+ if (p.created !== void 0) {
21915
+ parts.push(`created=${p.created}`);
21916
+ }
21917
+ if (p.expires !== void 0) {
21918
+ parts.push(`expires=${p.expires}`);
21919
+ }
21920
+ if (p.keyid !== void 0) {
21921
+ parts.push(`keyid="${p.keyid}"`);
21922
+ }
21923
+ if (p.alg !== void 0) {
21924
+ parts.push(`alg="${p.alg}"`);
21925
+ }
21926
+ if (p.tag !== void 0) {
21927
+ parts.push(`tag="${p.tag}"`);
21928
+ }
21929
+ return parts.map((s) => `;${s}`).join("");
21930
+ };
21931
+ var buildSignatureBase = (params, input) => {
21932
+ const lines = [];
21933
+ for (const name of params.components) {
21934
+ const value = componentValue(name, input);
21935
+ if (value === null) {
21936
+ throw new MissingComponentError(name);
21937
+ }
21938
+ lines.push(`"${name}": ${value}`);
21939
+ }
21940
+ const paramsValue = serializeComponentList(params.components) + serializeParams(params);
21941
+ lines.push(`"@signature-params": ${paramsValue}`);
21942
+ return lines.join("\n");
21943
+ };
21944
+ var MissingComponentError = class extends Error {
21945
+ constructor(component) {
21946
+ super(`signature base missing covered component: ${component}`);
21947
+ this.component = component;
21948
+ this.name = "MissingComponentError";
21949
+ }
21950
+ component;
21951
+ };
21952
+ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
21953
+ const members = splitDictionary(header);
21954
+ if (members.length === 0) {
21955
+ return null;
21956
+ }
21957
+ const parsed = members.map((m) => {
21958
+ const params = parseInnerListMember(m.value);
21959
+ return params ? { label: m.label, params } : null;
21960
+ }).filter((x) => x !== null);
21961
+ if (parsed.length === 0) {
21962
+ return null;
21963
+ }
21964
+ const tagged = parsed.find((p) => p.params.tag === tag);
21965
+ if (tagged) {
21966
+ return tagged;
21967
+ }
21968
+ if (parsed.length === 1 && parsed[0].params.tag === void 0) {
21969
+ return parsed[0];
21970
+ }
21971
+ return null;
21972
+ };
21973
+ var parseSignatureValue = (header, label) => {
21974
+ const members = splitDictionary(header);
21975
+ const member = members.find((m) => m.label === label);
21976
+ if (!member) {
21977
+ return null;
21978
+ }
21979
+ const v = member.value.trim();
21980
+ if (!v.startsWith(":") || !v.endsWith(":") || v.length < 2) {
21981
+ return null;
21982
+ }
21983
+ const b64 = v.slice(1, -1);
21984
+ try {
21985
+ return b64ToBytes(b64);
21986
+ } catch {
21987
+ return null;
21988
+ }
21989
+ };
21990
+ var splitDictionary = (header) => {
21991
+ const out = [];
21992
+ let depth = 0;
21993
+ let inBytes = false;
21994
+ let inString = false;
21995
+ let current = "";
21996
+ for (let i = 0; i < header.length; i++) {
21997
+ const ch = header[i];
21998
+ if (inString) {
21999
+ current += ch;
22000
+ if (ch === '"' && header[i - 1] !== "\\") {
22001
+ inString = false;
22002
+ }
22003
+ continue;
22004
+ }
22005
+ if (ch === '"') {
22006
+ inString = true;
22007
+ current += ch;
22008
+ continue;
22009
+ }
22010
+ if (ch === ":") {
22011
+ inBytes = !inBytes;
22012
+ current += ch;
22013
+ continue;
22014
+ }
22015
+ if (!inBytes && ch === "(") {
22016
+ depth++;
22017
+ current += ch;
22018
+ continue;
22019
+ }
22020
+ if (!inBytes && ch === ")") {
22021
+ depth = Math.max(0, depth - 1);
22022
+ current += ch;
22023
+ continue;
22024
+ }
22025
+ if (!inBytes && depth === 0 && ch === ",") {
22026
+ pushMember(out, current);
22027
+ current = "";
22028
+ continue;
22029
+ }
22030
+ current += ch;
22031
+ }
22032
+ pushMember(out, current);
22033
+ return out;
22034
+ };
22035
+ var pushMember = (out, raw) => {
22036
+ const trimmed = raw.trim();
22037
+ if (!trimmed) {
22038
+ return;
22039
+ }
22040
+ const eq = trimmed.indexOf("=");
22041
+ if (eq === -1) {
22042
+ return;
22043
+ }
22044
+ const label = trimmed.slice(0, eq).trim();
22045
+ const value = trimmed.slice(eq + 1).trim();
22046
+ if (label) {
22047
+ out.push({ label, value });
22048
+ }
22049
+ };
22050
+ var parseInnerListMember = (value) => {
22051
+ const open = value.indexOf("(");
22052
+ const close = value.indexOf(")", open + 1);
22053
+ if (open === -1 || close === -1) {
22054
+ return null;
22055
+ }
22056
+ const listBody = value.slice(open + 1, close).trim();
22057
+ const components = listBody.length === 0 ? [] : (listBody.match(/"[^"]*"/g) ?? []).map((s) => s.slice(1, -1));
22058
+ const params = { components };
22059
+ const paramStr = value.slice(close + 1);
22060
+ const re = /;\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|-?\d+)/g;
22061
+ let match;
22062
+ while ((match = re.exec(paramStr)) !== null) {
22063
+ const key = match[1];
22064
+ const raw = match[2];
22065
+ const val = raw.startsWith('"') ? raw.slice(1, -1) : Number(raw);
22066
+ if (key === "created") {
22067
+ params.created = val;
22068
+ } else if (key === "expires") {
22069
+ params.expires = val;
22070
+ } else if (key === "keyid") {
22071
+ params.keyid = val;
22072
+ } else if (key === "tag") {
22073
+ params.tag = val;
22074
+ } else if (key === "alg") {
22075
+ params.alg = val;
22076
+ }
22077
+ }
22078
+ return params;
22079
+ };
22080
+ var verifyMessageSignature = async (input) => {
22081
+ const selected = parseSignatureInput(input.signatureInput);
22082
+ if (!selected) {
22083
+ return { ok: false, reason: "no_aip_signature" };
22084
+ }
22085
+ const { label, params } = selected;
22086
+ if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
22087
+ return { ok: false, reason: "unsupported_alg" };
22088
+ }
22089
+ for (const required3 of AIP_COVERED_COMPONENTS) {
22090
+ if (!params.components.includes(required3)) {
22091
+ return { ok: false, reason: "missing_covered_component" };
22092
+ }
22093
+ }
22094
+ const now = input.now ?? Math.floor(Date.now() / 1e3);
22095
+ const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
22096
+ if (params.created !== void 0 && params.created > now + skew) {
22097
+ return { ok: false, reason: "created_in_future" };
22098
+ }
22099
+ if (params.expires !== void 0 && params.expires < now - skew) {
22100
+ return { ok: false, reason: "expired" };
22101
+ }
22102
+ if (!params.keyid) {
22103
+ return { ok: false, reason: "missing_keyid" };
22104
+ }
22105
+ const cnf = input.cnfJwk;
22106
+ if (cnf.kty !== "OKP" || cnf.crv !== "Ed25519" || typeof cnf.x !== "string" || cnf.x.length === 0) {
22107
+ return { ok: false, reason: "unsupported_cnf_key" };
22108
+ }
22109
+ let thumbprint;
22110
+ try {
22111
+ thumbprint = await calculateJwkThumbprint(input.cnfJwk, "sha256");
22112
+ } catch {
22113
+ return { ok: false, reason: "unsupported_cnf_key" };
22114
+ }
22115
+ if (params.keyid !== thumbprint) {
22116
+ return { ok: false, reason: "keyid_mismatch" };
22117
+ }
22118
+ const sig = parseSignatureValue(input.signature, label);
22119
+ if (!sig) {
22120
+ return { ok: false, reason: "malformed_signature" };
22121
+ }
22122
+ let base;
22123
+ try {
22124
+ base = buildSignatureBase(params, {
22125
+ method: input.method,
22126
+ authority: input.authority,
22127
+ path: input.path,
22128
+ agentIdentity: input.agentIdentity,
22129
+ extra: input.extraComponents
22130
+ });
22131
+ } catch (err) {
22132
+ if (err instanceof MissingComponentError) {
22133
+ return { ok: false, reason: "missing_covered_component" };
22134
+ }
22135
+ throw err;
22136
+ }
22137
+ let valid;
22138
+ try {
22139
+ const key = await importJWK(input.cnfJwk, "EdDSA");
22140
+ if (!(key instanceof CryptoKey)) {
22141
+ return { ok: false, reason: "signature_invalid" };
22142
+ }
22143
+ valid = await subtle.verify(
22144
+ { name: "Ed25519" },
22145
+ key,
22146
+ sig,
22147
+ new TextEncoder().encode(base)
22148
+ );
22149
+ } catch {
22150
+ return { ok: false, reason: "signature_invalid" };
22151
+ }
22152
+ return valid ? { ok: true, params } : { ok: false, reason: "signature_invalid" };
22153
+ };
22154
+ var signMessage = async (input) => {
22155
+ const label = input.label ?? "ait";
22156
+ const components = input.components ?? [...AIP_COVERED_COMPONENTS];
22157
+ const created = input.created ?? Math.floor(Date.now() / 1e3);
22158
+ const keyid = await calculateJwkThumbprint(input.publicJwk, "sha256");
22159
+ const params = {
22160
+ components,
22161
+ created,
22162
+ expires: input.expires,
22163
+ keyid,
22164
+ tag: AIP_SIGNATURE_TAG
22165
+ };
22166
+ const base = buildSignatureBase(params, {
22167
+ method: input.method,
22168
+ authority: input.authority,
22169
+ path: input.path,
22170
+ agentIdentity: input.agentIdentity,
22171
+ extra: input.extraComponents
22172
+ });
22173
+ const key = await importJWK(input.privateJwk, "EdDSA");
22174
+ if (!(key instanceof CryptoKey)) {
22175
+ throw new Error("signMessage: expected an Ed25519 private CryptoKey");
22176
+ }
22177
+ const sigBytes = await subtle.sign(
22178
+ "Ed25519",
22179
+ key,
22180
+ new TextEncoder().encode(base)
22181
+ );
22182
+ const b64 = bytesToB64(new Uint8Array(sigBytes));
22183
+ const signatureInput = `${label}=${serializeComponentList(components)}${serializeParams(params)}`;
22184
+ const signature2 = `${label}=:${b64}:`;
22185
+ return { signatureInput, signature: signature2 };
22186
+ };
22187
+
22188
+ // src/aip/types.ts
22189
+ var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
22190
+ var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
22191
+ var isAitShape = (payload) => isObject2(payload) && isObject2(payload.cnf) && isObject2(payload.agent);
22192
+ var validateAitPayload = (payload) => {
22193
+ if (!isObject2(payload)) {
22194
+ return { ok: false, reason: "not_an_object" };
22195
+ }
22196
+ if (!isNonEmptyString(payload.aip_version)) {
22197
+ return { ok: false, reason: "missing_aip_version" };
22198
+ }
22199
+ if (!isNonEmptyString(payload.iss)) {
22200
+ return { ok: false, reason: "missing_iss" };
22201
+ }
22202
+ if (!isNonEmptyString(payload.sub)) {
22203
+ return { ok: false, reason: "missing_sub" };
22204
+ }
22205
+ if (typeof payload.iat !== "number") {
22206
+ return { ok: false, reason: "missing_iat" };
22207
+ }
22208
+ if (typeof payload.exp !== "number") {
22209
+ return { ok: false, reason: "missing_exp" };
22210
+ }
22211
+ if (!isObject2(payload.cnf) || !isObject2(payload.cnf.jwk)) {
22212
+ return { ok: false, reason: "missing_cnf" };
22213
+ }
22214
+ if (!isObject2(payload.agent) || !isNonEmptyString(payload.agent.provider)) {
22215
+ return { ok: false, reason: "missing_agent_provider" };
22216
+ }
22217
+ if (payload.trust_level === "human_confirmed") {
22218
+ const auth = payload.auth;
22219
+ const amr = isObject2(auth) ? auth.amr : void 0;
22220
+ if (!Array.isArray(amr) || amr.length === 0) {
22221
+ return { ok: false, reason: "human_confirmed_without_amr" };
22222
+ }
22223
+ }
22224
+ return { ok: true, payload };
22225
+ };
22226
+
22227
+ // src/aip/verify.ts
22228
+ var AGENT_IDENTITY_HEADER = "agent-identity";
22229
+ var verifyAit = async (ctx, opts) => {
22230
+ if (ctx.agentIdentityHeaders.length === 0) {
22231
+ return { ok: false, reason: "no_token" };
22232
+ }
22233
+ if (!ctx.signatureInput || !ctx.signature) {
22234
+ return { ok: false, reason: "pop_signature_missing" };
22235
+ }
22236
+ let lastFailure = "malformed_token";
22237
+ for (const raw of ctx.agentIdentityHeaders) {
22238
+ const token = stripBearer(raw);
22239
+ let header;
22240
+ let payload;
22241
+ try {
22242
+ header = decodeProtectedHeader(token);
22243
+ payload = decodeJwt(token);
22244
+ } catch {
22245
+ lastFailure = "malformed_token";
22246
+ continue;
22247
+ }
22248
+ if (header.alg === void 0 || header.alg.toLowerCase() === "none") {
22249
+ lastFailure = "malformed_token";
22250
+ continue;
22251
+ }
22252
+ if (!isAitShape(payload)) {
22253
+ lastFailure = "malformed_token";
22254
+ continue;
22255
+ }
22256
+ const validated = validateAitPayload(payload);
22257
+ if (!validated.ok) {
22258
+ lastFailure = "invalid_claims";
22259
+ continue;
22260
+ }
22261
+ const claims = validated.payload;
22262
+ const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);
22263
+ if (!keyLookup.ok) {
22264
+ lastFailure = keyLookup.reason === "untrusted_issuer" || keyLookup.reason === "insecure_issuer" ? "untrusted_issuer" : "key_unavailable";
22265
+ continue;
22266
+ }
22267
+ const jwtClockTolerance = opts.maxSkewSeconds ?? 60;
22268
+ try {
22269
+ const idpKey = await importJWK2(keyLookup.key, normalizeAlg(header.alg));
22270
+ await jwtVerify(token, idpKey, {
22271
+ // Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
22272
+ // this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
22273
+ // non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
22274
+ // token that verifies. Matches the server-side allowlist in core/api aip-verify.
22275
+ algorithms: AIT_SIGNING_ALGS,
22276
+ clockTolerance: jwtClockTolerance,
22277
+ currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
22278
+ });
22279
+ } catch (err) {
22280
+ lastFailure = isExpiry(err) ? "expired_token" : "idp_signature_invalid";
22281
+ continue;
22282
+ }
22283
+ const nowSec = opts.now ?? Math.floor(Date.now() / 1e3);
22284
+ if (claims.iat > nowSec + jwtClockTolerance) {
22285
+ lastFailure = "expired_token";
22286
+ continue;
22287
+ }
22288
+ const popResult = await verifyMessageSignature({
22289
+ method: ctx.method,
22290
+ authority: ctx.authority,
22291
+ path: ctx.path,
22292
+ agentIdentity: raw,
22293
+ signatureInput: ctx.signatureInput,
22294
+ signature: ctx.signature,
22295
+ cnfJwk: claims.cnf.jwk,
22296
+ now: opts.now,
22297
+ maxSkewSeconds: opts.maxSkewSeconds
22298
+ });
22299
+ if (!popResult.ok) {
22300
+ lastFailure = "pop_signature_invalid";
22301
+ continue;
22302
+ }
22303
+ return { ok: true, ait: { payload: claims, iss: claims.iss, cnfJwk: claims.cnf.jwk, token } };
22304
+ }
22305
+ return { ok: false, reason: lastFailure };
22306
+ };
22307
+ var stripBearer = (value) => {
22308
+ const trimmed = value.trim();
22309
+ return /^bearer\s+/i.test(trimmed) ? trimmed.replace(/^bearer\s+/i, "") : trimmed;
22310
+ };
22311
+ var AIT_SIGNING_ALGS = ["EdDSA", "ES256"];
22312
+ var normalizeAlg = (alg) => alg.toLowerCase() === "eddsa" ? "EdDSA" : alg;
22313
+ var isExpiry = (err) => typeof err === "object" && err !== null && err.code === "ERR_JWT_EXPIRED";
22314
+
22315
+ // src/aip/request.ts
22316
+ var readAgentIdentityHeaders = (headers) => {
22317
+ const raw = headers.get(AGENT_IDENTITY_HEADER);
22318
+ if (!raw) {
22319
+ return [];
22320
+ }
22321
+ return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
22322
+ };
22323
+ var deriveAuthority = (req, url2) => req.headers.get("host") ?? url2.host;
22324
+ var buildVerifyContextFromRequest = (req) => {
22325
+ const url2 = new URL(req.url);
22326
+ return {
22327
+ method: req.method,
22328
+ authority: deriveAuthority(req, url2),
22329
+ path: url2.pathname,
22330
+ agentIdentityHeaders: readAgentIdentityHeaders(req.headers),
22331
+ signatureInput: req.headers.get("signature-input"),
22332
+ signature: req.headers.get("signature")
22333
+ };
22334
+ };
22335
+ var hasAgentIdentityHeader = (req) => readAgentIdentityHeaders(req.headers).length > 0;
22336
+ var readNodeHeader = (headers, name) => {
22337
+ const v = headers[name] ?? headers[name.toLowerCase()];
22338
+ if (v === void 0) {
22339
+ return void 0;
22340
+ }
22341
+ return Array.isArray(v) ? v.join(", ") : v;
22342
+ };
22343
+ var hasAgentIdentityHeaderNode = (headers) => {
22344
+ const raw = readNodeHeader(headers, "agent-identity");
22345
+ return raw !== void 0 && raw.split(",").some((s) => s.trim().length > 0);
22346
+ };
22347
+ var buildVerifyContextFromParts = (parts) => {
22348
+ const agentIdentityRaw = readNodeHeader(parts.headers, "agent-identity");
22349
+ const agentIdentityHeaders = agentIdentityRaw ? agentIdentityRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
22350
+ const host = parts.authority ?? readNodeHeader(parts.headers, "host") ?? "";
22351
+ let path;
22352
+ try {
22353
+ path = new URL(parts.url, host ? `http://${host}` : "http://localhost").pathname;
22354
+ } catch {
22355
+ const q = parts.url.indexOf("?");
22356
+ path = q === -1 ? parts.url : parts.url.slice(0, q);
22357
+ }
22358
+ return {
22359
+ method: parts.method,
22360
+ authority: host,
22361
+ path,
22362
+ agentIdentityHeaders,
22363
+ signatureInput: readNodeHeader(parts.headers, "signature-input") ?? null,
22364
+ signature: readNodeHeader(parts.headers, "signature") ?? null
22365
+ };
22366
+ };
22367
+
22368
+ // src/aip/gate.ts
22369
+ var verifyFromContext = async (ctx, opts) => {
22370
+ const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
22371
+ return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };
22372
+ };
22373
+ var verifyAitRequest = (req, opts) => verifyFromContext(buildVerifyContextFromRequest(req), opts);
22374
+ var verifyAitParts = (parts, opts) => verifyFromContext(buildVerifyContextFromParts(parts), opts);
22375
+ var aipErrorCode = (failure) => {
22376
+ switch (failure) {
22377
+ case "no_token":
22378
+ case "pop_signature_missing":
22379
+ return "agent_identity_required";
22380
+ case "untrusted_issuer":
22381
+ return "untrusted_issuer";
22382
+ case "expired_token":
22383
+ return "expired_token";
22384
+ case "invalid_claims":
22385
+ return "insufficient_claims";
22386
+ case "key_unavailable":
22387
+ return "idp_unavailable";
22388
+ case "malformed_token":
22389
+ case "idp_signature_invalid":
22390
+ case "pop_signature_invalid":
22391
+ return "invalid_signature";
22392
+ default:
22393
+ return "invalid_signature";
22394
+ }
22395
+ };
22396
+ var aipErrorStatus = (failure) => {
22397
+ switch (failure) {
22398
+ case "key_unavailable":
22399
+ return 503;
22400
+ case "untrusted_issuer":
22401
+ case "invalid_claims":
22402
+ return 403;
22403
+ default:
22404
+ return 401;
22405
+ }
22406
+ };
22407
+ var aipErrorDetail = (failure) => {
22408
+ switch (failure) {
22409
+ case "no_token":
22410
+ return "No Agent-Identity token was presented.";
22411
+ case "pop_signature_missing":
22412
+ return "The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.";
22413
+ case "untrusted_issuer":
22414
+ return "The token's issuer is not in this service's trusted-issuer list.";
22415
+ case "expired_token":
22416
+ return "The Agent Identity Token has expired.";
22417
+ case "invalid_claims":
22418
+ return "The token is missing required claims for this endpoint.";
22419
+ case "malformed_token":
22420
+ return "The Agent-Identity header could not be parsed as an Agent Identity Token.";
22421
+ case "idp_signature_invalid":
22422
+ return "The identity provider's signature on the token failed verification.";
22423
+ case "pop_signature_invalid":
22424
+ return "The request signature did not match the key bound to the token.";
22425
+ case "key_unavailable":
22426
+ return "The identity provider's signing key could not be resolved.";
22427
+ default:
22428
+ return "Token verification failed.";
22429
+ }
22430
+ };
22431
+ var buildAipErrorBody = (failure) => {
22432
+ const code = aipErrorCode(failure);
22433
+ return {
22434
+ type: `urn:aip:error:${code}`,
22435
+ title: code.replace(/_/g, " "),
22436
+ status: aipErrorStatus(failure),
22437
+ detail: aipErrorDetail(failure)
22438
+ };
22439
+ };
22440
+
22441
+ // src/aip/jwks.ts
22442
+ var JWKS_WELL_KNOWN_PATH = "/.well-known/agent-identity/jwks.json";
22443
+ var HARD_MAX_CACHE_SECONDS = 86400;
22444
+ var DEFAULT_CACHE_SECONDS = 300;
22445
+ var AGENTSCORE_CANONICAL_ISSUER = "https://agentscore.sh";
22446
+ var canonicalizeIssuer = (iss) => {
22447
+ let url2;
22448
+ try {
22449
+ url2 = new URL(iss.trim());
22450
+ } catch {
22451
+ return null;
22452
+ }
22453
+ const scheme = url2.protocol.toLowerCase();
22454
+ const host = url2.hostname.toLowerCase();
22455
+ const isDefaultPort = url2.port === "" || scheme === "https:" && url2.port === "443" || scheme === "http:" && url2.port === "80";
22456
+ const portPart = isDefaultPort ? "" : `:${url2.port}`;
22457
+ const path = url2.pathname === "/" ? "" : url2.pathname.replace(/\/$/, "");
22458
+ return `${scheme}//${host}${portPart}${path}`;
22459
+ };
22460
+ var resolveCacheSeconds = (cacheControl) => {
22461
+ if (!cacheControl) {
22462
+ return DEFAULT_CACHE_SECONDS;
22463
+ }
22464
+ if (/\bno-store\b/i.test(cacheControl) || /\bno-cache\b/i.test(cacheControl)) {
22465
+ return DEFAULT_CACHE_SECONDS;
22466
+ }
22467
+ const m = /\bmax-age\s*=\s*(\d+)/i.exec(cacheControl);
22468
+ if (!m) {
22469
+ return DEFAULT_CACHE_SECONDS;
22470
+ }
22471
+ const advertised = Number(m[1]);
22472
+ if (!Number.isFinite(advertised) || advertised <= 0) {
22473
+ return DEFAULT_CACHE_SECONDS;
22474
+ }
22475
+ return Math.min(advertised, HARD_MAX_CACHE_SECONDS);
22476
+ };
22477
+ var signingKeys = (keys) => keys.filter((k) => k.use === void 0 || k.use === "sig");
22478
+ var JwksCache = class {
22479
+ trusted;
22480
+ fetchImpl;
22481
+ now;
22482
+ userAgent;
22483
+ cache = /* @__PURE__ */ new Map();
22484
+ constructor(opts) {
22485
+ this.trusted = new Set(
22486
+ [AGENTSCORE_CANONICAL_ISSUER, ...opts.trustedIssuers ?? []].map(canonicalizeIssuer).filter((s) => s !== null)
22487
+ );
22488
+ this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;
22489
+ this.now = opts.now ?? Date.now;
22490
+ this.userAgent = opts.userAgent ?? "@agentscore/commerce";
22491
+ }
22492
+ /** Is this issuer on the canonicalized trust list? */
22493
+ isTrusted(iss) {
22494
+ const canon = canonicalizeIssuer(iss);
22495
+ return canon !== null && this.trusted.has(canon);
22496
+ }
22497
+ /**
22498
+ * Resolve the signing key for `(iss, kid)`. Enforces trust + HTTPS, serves from cache when
22499
+ * fresh, and refetches once on a kid-miss before giving up.
22500
+ */
22501
+ async getKey(iss, kid) {
22502
+ const canon = canonicalizeIssuer(iss);
22503
+ if (canon === null || !this.trusted.has(canon)) {
22504
+ return { ok: false, reason: "untrusted_issuer" };
22505
+ }
22506
+ if (!canon.startsWith("https://")) {
22507
+ return { ok: false, reason: "insecure_issuer" };
22508
+ }
22509
+ const cached2 = this.cache.get(canon);
22510
+ if (cached2 && this.now() < cached2.expiresAt) {
22511
+ const hit2 = this.select(cached2.keys, kid);
22512
+ if (hit2) {
22513
+ return { ok: true, key: hit2 };
22514
+ }
22515
+ }
22516
+ const refreshed = await this.refresh(canon);
22517
+ if (!refreshed.ok) {
22518
+ return refreshed;
22519
+ }
22520
+ const hit = this.select(refreshed.keys, kid);
22521
+ return hit ? { ok: true, key: hit } : { ok: false, reason: "key_not_found" };
22522
+ }
22523
+ select(keys, kid) {
22524
+ const candidates = signingKeys(keys);
22525
+ if (kid !== void 0) {
22526
+ const byKid = candidates.find((k) => k.kid === kid);
22527
+ if (byKid) {
22528
+ return byKid;
22529
+ }
22530
+ return void 0;
22531
+ }
22532
+ return candidates.length === 1 ? candidates[0] : void 0;
22533
+ }
22534
+ async refresh(canonIssuer) {
22535
+ const url2 = `${canonIssuer}${JWKS_WELL_KNOWN_PATH}`;
22536
+ let res;
22537
+ try {
22538
+ res = await this.fetchImpl(url2, { headers: { "User-Agent": this.userAgent, Accept: "application/jwk-set+json, application/json" } });
22539
+ } catch {
22540
+ return { ok: false, reason: "fetch_failed" };
22541
+ }
22542
+ if (!res.ok) {
22543
+ return { ok: false, reason: "fetch_failed" };
22544
+ }
22545
+ let body;
22546
+ try {
22547
+ body = await res.json();
22548
+ } catch {
22549
+ return { ok: false, reason: "malformed_jwks" };
22550
+ }
22551
+ if (typeof body !== "object" || body === null || !Array.isArray(body.keys)) {
22552
+ return { ok: false, reason: "malformed_jwks" };
22553
+ }
22554
+ const keys = body.keys;
22555
+ const ttlSeconds = resolveCacheSeconds(res.headers.get("cache-control"));
22556
+ this.cache.set(canonIssuer, { keys, expiresAt: this.now() + ttlSeconds * 1e3 });
22557
+ return { ok: true, keys };
22558
+ }
22559
+ };
22560
+
21843
22561
  // src/payment/rail_spec.ts
21844
22562
  init_usdc();
21845
22563
  async function resolveRecipient(r) {
@@ -21992,10 +22710,11 @@ function buildAgentInstructions({
21992
22710
 
21993
22711
  // src/challenge/agent_memory.ts
21994
22712
  function firstEncounterAgentMemory({
21995
- firstEncounter
22713
+ firstEncounter,
22714
+ aipTrustedIssuers
21996
22715
  }) {
21997
22716
  if (!firstEncounter) return void 0;
21998
- return buildAgentMemoryHint();
22717
+ return buildAgentMemoryHint(aipTrustedIssuers);
21999
22718
  }
22000
22719
 
22001
22720
  // src/challenge/body.ts
@@ -23027,6 +23746,30 @@ function pickRail(rails2, key) {
23027
23746
  const spec = rails2[key];
23028
23747
  return spec === void 0 ? void 0 : spec;
23029
23748
  }
23749
+ function buildAipTrustedIssuers(externalIssuers) {
23750
+ const out = [AGENTSCORE_CANONICAL_ISSUER, ...externalIssuers ?? []];
23751
+ const seen = /* @__PURE__ */ new Set();
23752
+ const deduped = [];
23753
+ for (const iss of out) {
23754
+ const key = canonicalizeIssuer(iss) ?? iss;
23755
+ if (!seen.has(key)) {
23756
+ seen.add(key);
23757
+ deduped.push(iss);
23758
+ }
23759
+ }
23760
+ return deduped;
23761
+ }
23762
+ function aipTrustedIssuerSet(cfg) {
23763
+ return buildAipTrustedIssuers(cfg.trustedIssuers);
23764
+ }
23765
+ function resolveIssuerPolicy(issuerPolicies, iss) {
23766
+ const target = canonicalizeIssuer(iss);
23767
+ if (target === null) return void 0;
23768
+ for (const [key, policy] of Object.entries(issuerPolicies)) {
23769
+ if (canonicalizeIssuer(key) === target) return policy;
23770
+ }
23771
+ return void 0;
23772
+ }
23030
23773
  var Checkout = class {
23031
23774
  rails;
23032
23775
  url;
@@ -23044,6 +23787,15 @@ var Checkout = class {
23044
23787
  discoveryExtensions;
23045
23788
  discoveryProbe;
23046
23789
  _x402ServerGetter;
23790
+ /** Lazily-built JWKS cache for AIP verification, shared across requests so issuer keys
23791
+ * are fetched once and cached (per the verifier's hard 24h cap). Built on first AIT. */
23792
+ aipJwks;
23793
+ getAipJwks(cfg) {
23794
+ if (this.aipJwks === void 0) {
23795
+ this.aipJwks = new JwksCache(cfg.trustedIssuers !== void 0 ? { trustedIssuers: cfg.trustedIssuers } : {});
23796
+ }
23797
+ return this.aipJwks;
23798
+ }
23047
23799
  /**
23048
23800
  * True when the merchant has configured an identity-bearing policy flag —
23049
23801
  * `require_kyc`, `require_sanctions_clear` (name screening on the KYC
@@ -23331,7 +24083,64 @@ var Checkout = class {
23331
24083
  }
23332
24084
  return result;
23333
24085
  }
24086
+ const headers = normalizeHeadersToLowercase(ctx.request.headers);
24087
+ const walletAddress = headers["x-wallet-address"];
24088
+ const operatorToken = headers["x-operator-token"];
24089
+ let aipToken;
24090
+ let aipIssuer;
24091
+ if (gate.aip !== void 0 && hasAgentIdentityHeaderNode(headers)) {
24092
+ const aipResult = await verifyAitParts(
24093
+ {
24094
+ method: ctx.request.method,
24095
+ url: ctx.request.url,
24096
+ headers,
24097
+ ...gate.aip.authority !== void 0 && { authority: gate.aip.authority }
24098
+ },
24099
+ {
24100
+ jwks: this.getAipJwks(gate.aip),
24101
+ ...gate.aip.maxSkewSeconds !== void 0 && { maxSkewSeconds: gate.aip.maxSkewSeconds }
24102
+ }
24103
+ );
24104
+ if (!aipResult.ok) {
24105
+ const body2 = buildAipErrorBody(aipResult.failure);
24106
+ return {
24107
+ status: body2.status,
24108
+ body: body2,
24109
+ headers: {
24110
+ "content-type": "application/problem+json",
24111
+ // 503 = the IdP's JWKS was unreachable (transient infra, not a bad token). Hint a
24112
+ // short backoff so agents retry rather than uselessly re-signing.
24113
+ ...body2.status === 503 && { "retry-after": "5" }
24114
+ }
24115
+ };
24116
+ }
24117
+ aipToken = aipResult.ait.token;
24118
+ aipIssuer = aipResult.ait.iss;
24119
+ }
24120
+ const issuerPolicy = aipIssuer !== void 0 && gate.aip?.issuerPolicies !== void 0 ? resolveIssuerPolicy(gate.aip.issuerPolicies, aipIssuer) : void 0;
24121
+ const effPolicy = issuerPolicy ?? {
24122
+ ...gate.requireKyc !== void 0 && { requireKyc: gate.requireKyc },
24123
+ ...gate.requireSanctionsClear !== void 0 && { requireSanctionsClear: gate.requireSanctionsClear },
24124
+ ...gate.minAge !== void 0 && { minAge: gate.minAge },
24125
+ ...gate.blockedJurisdictions !== void 0 && { blockedJurisdictions: gate.blockedJurisdictions },
24126
+ ...gate.allowedJurisdictions !== void 0 && { allowedJurisdictions: gate.allowedJurisdictions }
24127
+ };
23334
24128
  if (gate.apiKey === void 0) {
24129
+ if (aipToken !== void 0) {
24130
+ const hasPolicy = effPolicy.requireKyc || effPolicy.requireSanctionsClear || effPolicy.minAge != null || effPolicy.blockedJurisdictions !== void 0 || effPolicy.allowedJurisdictions !== void 0;
24131
+ if (hasPolicy) {
24132
+ return {
24133
+ status: 403,
24134
+ body: {
24135
+ error: {
24136
+ code: "aip_policy_requires_api_key",
24137
+ 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."
24138
+ }
24139
+ }
24140
+ };
24141
+ }
24142
+ return null;
24143
+ }
23335
24144
  return this.runWalletSanctionsOnly(ctx);
23336
24145
  }
23337
24146
  let policyOverride;
@@ -23343,14 +24152,21 @@ var Checkout = class {
23343
24152
  apiKey: gate.apiKey,
23344
24153
  ...gate.baseUrl !== void 0 && { baseUrl: gate.baseUrl },
23345
24154
  ...gate.userAgent !== void 0 && { userAgent: gate.userAgent },
23346
- ...gate.requireKyc !== void 0 && { requireKyc: gate.requireKyc },
23347
- ...gate.requireSanctionsClear !== void 0 && { requireSanctionsClear: gate.requireSanctionsClear },
23348
- ...gate.minAge !== void 0 && { minAge: gate.minAge },
23349
- ...gate.blockedJurisdictions !== void 0 && { blockedJurisdictions: gate.blockedJurisdictions },
23350
- ...gate.allowedJurisdictions !== void 0 && { allowedJurisdictions: gate.allowedJurisdictions },
24155
+ // Compliance fields come from effPolicy the per-issuer override for the verified AIT's
24156
+ // issuer when one is configured, else the gate defaults (see effPolicy above). A whole-
24157
+ // policy replacement: an issuer override of `{ requireKyc, minAge }` sends ONLY those,
24158
+ // so sanctions / jurisdiction are not enforced for that issuer.
24159
+ ...effPolicy.requireKyc !== void 0 && { requireKyc: effPolicy.requireKyc },
24160
+ ...effPolicy.requireSanctionsClear !== void 0 && { requireSanctionsClear: effPolicy.requireSanctionsClear },
24161
+ ...effPolicy.minAge !== void 0 && { minAge: effPolicy.minAge },
24162
+ ...effPolicy.blockedJurisdictions !== void 0 && { blockedJurisdictions: effPolicy.blockedJurisdictions },
24163
+ ...effPolicy.allowedJurisdictions !== void 0 && { allowedJurisdictions: effPolicy.allowedJurisdictions },
23351
24164
  ...gate.failOpen !== void 0 && { failOpen: gate.failOpen },
23352
24165
  ...gate.cacheSeconds !== void 0 && { cacheSeconds: gate.cacheSeconds },
23353
24166
  ...gate.chain !== void 0 && { chain: gate.chain },
24167
+ // Surface AIP acceptance in the missing-identity recovery instructions + agent_memory
24168
+ // hint so agents holding an AIT learn they can present it instead of bootstrapping.
24169
+ ...gate.aip !== void 0 && { aipTrustedIssuers: aipTrustedIssuerSet(gate.aip) },
23354
24170
  // Auto-default `createSessionOnMissing` from gate config when the merchant
23355
24171
  // didn't supply one, so every gated route gets the bootstrap session-mint UX
23356
24172
  // out of the box. Merchants who need custom session context or onBeforeSession
@@ -23364,10 +24180,7 @@ var Checkout = class {
23364
24180
  ...policyOverride ?? {}
23365
24181
  };
23366
24182
  const core = createAgentScoreCore(coreOpts);
23367
- const headers = normalizeHeadersToLowercase(ctx.request.headers);
23368
- const walletAddress = headers["x-wallet-address"];
23369
- const operatorToken = headers["x-operator-token"];
23370
- const identity = walletAddress !== void 0 || operatorToken !== void 0 ? {
24183
+ const identity = aipToken !== void 0 ? { aipToken } : walletAddress !== void 0 || operatorToken !== void 0 ? {
23371
24184
  ...walletAddress !== void 0 && { address: walletAddress },
23372
24185
  ...operatorToken !== void 0 && { operatorToken }
23373
24186
  } : void 0;
@@ -23386,7 +24199,7 @@ var Checkout = class {
23386
24199
  });
23387
24200
  };
23388
24201
  }
23389
- if (walletAddress !== void 0) {
24202
+ if (aipToken === void 0 && walletAddress !== void 0) {
23390
24203
  const verdict = core.getSignerVerdict(walletAddress);
23391
24204
  const sm = verdict?.signer_match;
23392
24205
  if (sm && sm.kind !== "pass") {
@@ -23731,8 +24544,13 @@ var Checkout = class {
23731
24544
  retryBody: ctx.request.body,
23732
24545
  // Merchants without an identity-bearing gate get a clean 402: no
23733
24546
  // AgentScore-identity bootstrap describing a verification flow they
23734
- // don't run. Wallet OFAC (the always-on default) doesn't need it.
23735
- agentMemory: firstEncounterAgentMemory({ firstEncounter: this.hasIdentityGate() }),
24547
+ // don't run. Wallet OFAC (the always-on default) doesn't need it. When the
24548
+ // merchant accepts AIP, advertise the agent_identity path too (AgentScore's
24549
+ // own issuer is always trusted, so this fires even with no external issuers).
24550
+ agentMemory: firstEncounterAgentMemory({
24551
+ firstEncounter: this.hasIdentityGate(),
24552
+ ...this.gate?.aip !== void 0 && { aipTrustedIssuers: aipTrustedIssuerSet(this.gate.aip) }
24553
+ }),
23736
24554
  ...ctx.pricing.product ? { product: ctx.pricing.product } : {},
23737
24555
  ...ctx.pricing.bodyExtras ? { extra: ctx.pricing.bodyExtras } : {},
23738
24556
  ...x402Accepts.length > 0 ? {
@@ -24226,7 +25044,7 @@ init_well_known();
24226
25044
  init_amounts();
24227
25045
 
24228
25046
  // src/quote_cache.ts
24229
- import { createHash as createHash2 } from "crypto";
25047
+ import { createHash as createHash3 } from "crypto";
24230
25048
 
24231
25049
  // src/_redis.ts
24232
25050
  async function tryCreateRedis(opts) {
@@ -24279,7 +25097,7 @@ function createQuoteCache(opts = {}) {
24279
25097
  return {
24280
25098
  bodyHashKey(prefix, body) {
24281
25099
  const canonical = JSON.stringify(canonicalize2(body));
24282
- const hash3 = createHash2("sha256").update(`${prefix}::${canonical}`).digest("hex").slice(0, 24);
25100
+ const hash3 = createHash3("sha256").update(`${prefix}::${canonical}`).digest("hex").slice(0, 24);
24283
25101
  return `${prefix}::${hash3}`;
24284
25102
  },
24285
25103
  async read(key) {
@@ -24793,15 +25611,26 @@ function defaultReadOnlyOnDenied(reason) {
24793
25611
  export {
24794
25612
  A2A_DEFAULT_TRANSPORT,
24795
25613
  A2A_PROTOCOL_VERSION,
25614
+ AGENTSCORE_CANONICAL_ISSUER,
24796
25615
  AGENTSCORE_UCP_CAPABILITY,
25616
+ AGENT_IDENTITY_HEADER,
25617
+ AIP_COVERED_COMPONENTS,
25618
+ AIP_SIGNATURE_TAG,
24797
25619
  Checkout,
24798
25620
  CheckoutValidationError,
24799
25621
  FIXABLE_DENIAL_REASONS,
25622
+ HARD_MAX_CACHE_SECONDS,
25623
+ JWKS_WELL_KNOWN_PATH,
25624
+ JwksCache,
24800
25625
  UCPSigningKey,
24801
25626
  UCPVerificationError,
24802
25627
  UCP_A2A_EXTENSION_URI,
25628
+ aipErrorCode,
25629
+ aipErrorStatus,
24803
25630
  buildA2AAgentCard,
24804
25631
  buildAgentMemoryHint,
25632
+ buildAipErrorBody,
25633
+ buildAipTrustedIssuers,
24805
25634
  buildContactSupportNextSteps,
24806
25635
  buildDefaultCheckoutRails,
24807
25636
  buildGateFromPolicy,
@@ -24810,6 +25639,8 @@ export {
24810
25639
  buildSignerMismatchBody,
24811
25640
  buildUCPProfile,
24812
25641
  buildVerificationRequiredBody,
25642
+ buildVerifyContextFromRequest,
25643
+ canonicalizeIssuer,
24813
25644
  computeFirstCheckout,
24814
25645
  createDefaultOnDenied,
24815
25646
  createQuoteCache,
@@ -24823,10 +25654,12 @@ export {
24823
25654
  formatUsdCents,
24824
25655
  generateUCPSigningKey,
24825
25656
  getIdentityStatus,
25657
+ hasAgentIdentityHeader,
24826
25658
  hasMppxHeader,
24827
25659
  hasPaymentHeader,
24828
25660
  hasX402Header,
24829
25661
  hashOperatorToken,
25662
+ isAitShape,
24830
25663
  isEvmNetwork,
24831
25664
  isFixableDenial,
24832
25665
  isSolanaNetwork,
@@ -24839,9 +25672,11 @@ export {
24839
25672
  runGateWithEnforcement,
24840
25673
  shippingCountryAllowed,
24841
25674
  shippingStateAllowed,
25675
+ signMessage,
24842
25676
  signUCPProfile,
24843
25677
  stripeSptPaymentHandler,
24844
25678
  ucpA2AExtension,
25679
+ validateAitPayload,
24845
25680
  validateShippingAgainstPolicy,
24846
25681
  validationEnvelope,
24847
25682
  validationResponseExpress,
@@ -24850,6 +25685,9 @@ export {
24850
25685
  validationResponseNextjs,
24851
25686
  validationResponseWeb,
24852
25687
  verificationAgentInstructions,
25688
+ verifyAit,
25689
+ verifyAitRequest,
25690
+ verifyMessageSignature,
24853
25691
  verifyUCPProfile,
24854
25692
  x402PaymentHandler
24855
25693
  };