@agent-score/commerce 2.5.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +19 -17
  2. package/dist/challenge/index.d.mts +26 -2
  3. package/dist/challenge/index.d.ts +26 -2
  4. package/dist/challenge/index.js +14 -5
  5. package/dist/challenge/index.js.map +1 -1
  6. package/dist/challenge/index.mjs +14 -5
  7. package/dist/challenge/index.mjs.map +1 -1
  8. package/dist/{checkout-McfNpZJf.d.ts → checkout-C4RD7M0Z.d.ts} +46 -13
  9. package/dist/{checkout-o17dIxHi.d.mts → checkout-CzB9f_jf.d.mts} +46 -13
  10. package/dist/core.d.mts +20 -9
  11. package/dist/core.d.ts +20 -9
  12. package/dist/core.js +35 -24
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +35 -24
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/discovery/index.d.mts +17 -2
  17. package/dist/discovery/index.d.ts +17 -2
  18. package/dist/discovery/index.js +36 -12
  19. package/dist/discovery/index.js.map +1 -1
  20. package/dist/discovery/index.mjs +35 -12
  21. package/dist/discovery/index.mjs.map +1 -1
  22. package/dist/{gate-CWP10xPQ.d.mts → gate-D2RP6bZg.d.ts} +109 -141
  23. package/dist/{gate-CWP10xPQ.d.ts → gate-GCXy4FHI.d.mts} +109 -141
  24. package/dist/identity/express.d.mts +3 -1
  25. package/dist/identity/express.d.ts +3 -1
  26. package/dist/identity/express.js +164 -55
  27. package/dist/identity/express.js.map +1 -1
  28. package/dist/identity/express.mjs +164 -55
  29. package/dist/identity/express.mjs.map +1 -1
  30. package/dist/identity/fastify.d.mts +3 -1
  31. package/dist/identity/fastify.d.ts +3 -1
  32. package/dist/identity/fastify.js +171 -57
  33. package/dist/identity/fastify.js.map +1 -1
  34. package/dist/identity/fastify.mjs +171 -57
  35. package/dist/identity/fastify.mjs.map +1 -1
  36. package/dist/identity/hono.d.mts +3 -1
  37. package/dist/identity/hono.d.ts +3 -1
  38. package/dist/identity/hono.js +159 -59
  39. package/dist/identity/hono.js.map +1 -1
  40. package/dist/identity/hono.mjs +159 -59
  41. package/dist/identity/hono.mjs.map +1 -1
  42. package/dist/identity/nextjs.d.mts +3 -1
  43. package/dist/identity/nextjs.d.ts +3 -1
  44. package/dist/identity/nextjs.js +153 -56
  45. package/dist/identity/nextjs.js.map +1 -1
  46. package/dist/identity/nextjs.mjs +153 -56
  47. package/dist/identity/nextjs.mjs.map +1 -1
  48. package/dist/identity/policy.d.mts +21 -2
  49. package/dist/identity/policy.d.ts +21 -2
  50. package/dist/identity/policy.js +22 -1
  51. package/dist/identity/policy.js.map +1 -1
  52. package/dist/identity/policy.mjs +21 -1
  53. package/dist/identity/policy.mjs.map +1 -1
  54. package/dist/identity/web.d.mts +3 -1
  55. package/dist/identity/web.d.ts +3 -1
  56. package/dist/identity/web.js +153 -56
  57. package/dist/identity/web.js.map +1 -1
  58. package/dist/identity/web.mjs +153 -56
  59. package/dist/identity/web.mjs.map +1 -1
  60. package/dist/index.d.mts +55 -10
  61. package/dist/index.d.ts +55 -10
  62. package/dist/index.js +2227 -501
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +2219 -501
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/payment/index.d.mts +1 -1
  67. package/dist/payment/index.d.ts +1 -1
  68. package/dist/payment/index.js +10 -2
  69. package/dist/payment/index.js.map +1 -1
  70. package/dist/payment/index.mjs +10 -2
  71. package/dist/payment/index.mjs.map +1 -1
  72. package/dist/stripe-multichain/index.js +1621 -266
  73. package/dist/stripe-multichain/index.js.map +1 -1
  74. package/dist/stripe-multichain/index.mjs +1621 -266
  75. package/dist/stripe-multichain/index.mjs.map +1 -1
  76. package/dist/types-D1slMt0H.d.mts +137 -0
  77. package/dist/types-D1slMt0H.d.ts +137 -0
  78. package/dist/{wwwauthenticate-CVaGUMjU.d.mts → wwwauthenticate-Dgm-_af9.d.mts} +11 -1
  79. package/dist/{wwwauthenticate-CVaGUMjU.d.ts → wwwauthenticate-Dgm-_af9.d.ts} +11 -1
  80. package/package.json +23 -18
@@ -44,7 +44,7 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
44
44
  var API_ERROR_INSTRUCTIONS = JSON.stringify({
45
45
  action: "retry_with_backoff",
46
46
  steps: [
47
- "Verification is temporarily unavailable. Retry the request after 5\u201330 seconds with exponential backoff.",
47
+ "Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.",
48
48
  "This is NOT a compliance denial \u2014 the user does not need to re-verify their identity. Send the same identity headers (X-Wallet-Address or X-Operator-Token) on retry.",
49
49
  "If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
50
50
  ],
@@ -148,6 +148,7 @@ var b64ToBytes = (b64) => {
148
148
  var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
149
149
  var AIP_SIGNATURE_TAG = "agent-identity";
150
150
  var DEFAULT_MAX_SKEW_SECONDS = 60;
151
+ var MAX_POP_WINDOW_SECONDS = 120;
151
152
  var normalizeAuthority = (authority) => {
152
153
  const lower = authority.trim().toLowerCase();
153
154
  const colon = lower.lastIndexOf(":");
@@ -198,7 +199,7 @@ var serializeParams = (p) => {
198
199
  }
199
200
  return parts.map((s) => `;${s}`).join("");
200
201
  };
201
- var buildSignatureBase = (params, input) => {
202
+ var buildSignatureBase = (params, input, rawSignatureParams) => {
202
203
  const lines = [];
203
204
  for (const name of params.components) {
204
205
  const value = componentValue(name, input);
@@ -207,7 +208,7 @@ var buildSignatureBase = (params, input) => {
207
208
  }
208
209
  lines.push(`"${name}": ${value}`);
209
210
  }
210
- const paramsValue = serializeComponentList(params.components) + serializeParams(params);
211
+ const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);
211
212
  lines.push(`"@signature-params": ${paramsValue}`);
212
213
  return lines.join("\n");
213
214
  };
@@ -226,19 +227,12 @@ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
226
227
  }
227
228
  const parsed = members.map((m) => {
228
229
  const params = parseInnerListMember(m.value);
229
- return params ? { label: m.label, params } : null;
230
+ return params ? { label: m.label, params, rawParams: m.value } : null;
230
231
  }).filter((x) => x !== null);
231
232
  if (parsed.length === 0) {
232
233
  return null;
233
234
  }
234
- const tagged = parsed.find((p) => p.params.tag === tag);
235
- if (tagged) {
236
- return tagged;
237
- }
238
- if (parsed.length === 1 && parsed[0].params.tag === void 0) {
239
- return parsed[0];
240
- }
241
- return null;
235
+ return parsed.find((p) => p.params.tag === tag) ?? null;
242
236
  };
243
237
  var parseSignatureValue = (header, label) => {
244
238
  const members = splitDictionary(header);
@@ -352,7 +346,7 @@ var verifyMessageSignature = async (input) => {
352
346
  if (!selected) {
353
347
  return { ok: false, reason: "no_aip_signature" };
354
348
  }
355
- const { label, params } = selected;
349
+ const { label, params, rawParams } = selected;
356
350
  if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
357
351
  return { ok: false, reason: "unsupported_alg" };
358
352
  }
@@ -361,12 +355,21 @@ var verifyMessageSignature = async (input) => {
361
355
  return { ok: false, reason: "missing_covered_component" };
362
356
  }
363
357
  }
358
+ if (params.created === void 0) {
359
+ return { ok: false, reason: "created_missing" };
360
+ }
361
+ if (params.expires === void 0) {
362
+ return { ok: false, reason: "expires_missing" };
363
+ }
364
+ if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {
365
+ return { ok: false, reason: "pop_window_too_long" };
366
+ }
364
367
  const now = input.now ?? Math.floor(Date.now() / 1e3);
365
368
  const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
366
- if (params.created !== void 0 && params.created > now + skew) {
369
+ if (params.created > now + skew) {
367
370
  return { ok: false, reason: "created_in_future" };
368
371
  }
369
- if (params.expires !== void 0 && params.expires < now - skew) {
372
+ if (params.expires < now - skew) {
370
373
  return { ok: false, reason: "expired" };
371
374
  }
372
375
  if (!params.keyid) {
@@ -397,7 +400,7 @@ var verifyMessageSignature = async (input) => {
397
400
  path: input.path,
398
401
  agentIdentity: input.agentIdentity,
399
402
  extra: input.extraComponents
400
- });
403
+ }, rawParams);
401
404
  } catch (err) {
402
405
  if (err instanceof MissingComponentError) {
403
406
  return { ok: false, reason: "missing_covered_component" };
@@ -470,6 +473,8 @@ var verifyAit = async (ctx, opts) => {
470
473
  if (!ctx.signatureInput || !ctx.signature) {
471
474
  return { ok: false, reason: "pop_signature_missing" };
472
475
  }
476
+ const signatureInput = ctx.signatureInput;
477
+ const signature = ctx.signature;
473
478
  let lastFailure = "malformed_token";
474
479
  for (const raw of ctx.agentIdentityHeaders) {
475
480
  const token = stripBearer(raw);
@@ -508,7 +513,7 @@ var verifyAit = async (ctx, opts) => {
508
513
  // Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
509
514
  // this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
510
515
  // non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
511
- // token that verifies. Matches the server-side allowlist in core/api aip-verify.
516
+ // token that verifies. Matches the server-side allowlist in the AgentScore API verifier.
512
517
  algorithms: AIT_SIGNING_ALGS,
513
518
  clockTolerance: jwtClockTolerance,
514
519
  currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
@@ -522,13 +527,20 @@ var verifyAit = async (ctx, opts) => {
522
527
  lastFailure = "expired_token";
523
528
  continue;
524
529
  }
530
+ if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {
531
+ lastFailure = "expired_token";
532
+ continue;
533
+ }
525
534
  const popResult = await verifyMessageSignature({
526
535
  method: ctx.method,
527
536
  authority: ctx.authority,
528
537
  path: ctx.path,
529
- agentIdentity: raw,
530
- signatureInput: ctx.signatureInput,
531
- signature: ctx.signature,
538
+ // The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is
539
+ // transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and
540
+ // the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.
541
+ agentIdentity: token,
542
+ signatureInput,
543
+ signature,
532
544
  cnfJwk: claims.cnf.jwk,
533
545
  now: opts.now,
534
546
  maxSkewSeconds: opts.maxSkewSeconds
@@ -537,7 +549,22 @@ var verifyAit = async (ctx, opts) => {
537
549
  lastFailure = "pop_signature_invalid";
538
550
  continue;
539
551
  }
540
- return { ok: true, ait: { payload: claims, iss: claims.iss, cnfJwk: claims.cnf.jwk, token } };
552
+ return {
553
+ ok: true,
554
+ ait: {
555
+ payload: claims,
556
+ iss: claims.iss,
557
+ cnfJwk: claims.cnf.jwk,
558
+ token,
559
+ signatureMaterial: {
560
+ method: ctx.method,
561
+ authority: ctx.authority,
562
+ path: ctx.path,
563
+ signature_input: signatureInput,
564
+ signature
565
+ }
566
+ }
567
+ };
541
568
  }
542
569
  return { ok: false, reason: lastFailure };
543
570
  };
@@ -558,11 +585,11 @@ var readAgentIdentityHeaders = (headers) => {
558
585
  return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
559
586
  };
560
587
  var deriveAuthority = (req, url) => req.headers.get("host") ?? url.host;
561
- var buildVerifyContextFromRequest = (req) => {
588
+ var buildVerifyContextFromRequest = (req, authority) => {
562
589
  const url = new URL(req.url);
563
590
  return {
564
591
  method: req.method,
565
- authority: deriveAuthority(req, url),
592
+ authority: authority ?? deriveAuthority(req, url),
566
593
  path: url.pathname,
567
594
  agentIdentityHeaders: readAgentIdentityHeaders(req.headers),
568
595
  signatureInput: req.headers.get("signature-input"),
@@ -572,11 +599,6 @@ var buildVerifyContextFromRequest = (req) => {
572
599
  var hasAgentIdentityHeader = (req) => readAgentIdentityHeaders(req.headers).length > 0;
573
600
 
574
601
  // src/aip/gate.ts
575
- var verifyFromContext = async (ctx, opts) => {
576
- const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
577
- return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };
578
- };
579
- var verifyAitRequest = (req, opts) => verifyFromContext(buildVerifyContextFromRequest(req), opts);
580
602
  var aipErrorCode = (failure) => {
581
603
  switch (failure) {
582
604
  case "no_token":
@@ -633,15 +655,78 @@ var aipErrorDetail = (failure) => {
633
655
  return "Token verification failed.";
634
656
  }
635
657
  };
636
- var buildAipErrorBody = (failure) => {
658
+ var buildAipErrorBody = (failure, requirements) => {
637
659
  const code = aipErrorCode(failure);
638
- return {
660
+ const body = {
639
661
  type: `urn:aip:error:${code}`,
640
662
  title: code.replace(/_/g, " "),
641
663
  status: aipErrorStatus(failure),
642
664
  detail: aipErrorDetail(failure)
643
665
  };
666
+ if (requirements) {
667
+ if (code === "untrusted_issuer" && requirements.trustedIssuers?.length) {
668
+ body.trusted_issuers = requirements.trustedIssuers;
669
+ }
670
+ if (code === "insufficient_claims") {
671
+ if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;
672
+ if (requirements.requiredTrustLevel !== void 0) body.required_trust_level = requirements.requiredTrustLevel;
673
+ if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;
674
+ }
675
+ }
676
+ return body;
644
677
  };
678
+ var TRUST_RANK = { autonomous: 0, human_present: 1, human_confirmed: 2 };
679
+ var checkTrustRequirements = (payload, requiredTrustLevel, requiredAmr) => {
680
+ if (requiredTrustLevel !== void 0) {
681
+ const have = TRUST_RANK[payload.trust_level ?? "autonomous"] ?? 0;
682
+ const need = TRUST_RANK[requiredTrustLevel] ?? 0;
683
+ if (have < need) {
684
+ return `This endpoint requires trust_level '${requiredTrustLevel}'; the token asserts '${payload.trust_level ?? "autonomous"}'. Re-mint an AIT at the required trust level (human confirmation).`;
685
+ }
686
+ }
687
+ if (requiredAmr !== void 0 && requiredAmr.length > 0) {
688
+ const amr = Array.isArray(payload.auth?.amr) ? payload.auth.amr : [];
689
+ if (!amr.some((m) => requiredAmr.includes(m))) {
690
+ return `This endpoint requires an authentication method in [${requiredAmr.join(", ")}]; the token carries [${amr.join(", ") || "none"}].`;
691
+ }
692
+ }
693
+ return null;
694
+ };
695
+ var buildAipWeakAuthBody = (opts) => ({
696
+ type: "urn:aip:error:weak_auth",
697
+ title: "weak auth",
698
+ status: 403,
699
+ detail: opts.detail,
700
+ ...opts.requiredTrustLevel !== void 0 && { required_trust_level: opts.requiredTrustLevel },
701
+ ...opts.requiredAmr !== void 0 && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr },
702
+ ...opts.trustedIssuers !== void 0 && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }
703
+ });
704
+ var requirementsFromOptions = (opts) => ({
705
+ ...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers },
706
+ ...opts.requiredClaims !== void 0 && { requiredClaims: opts.requiredClaims },
707
+ ...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
708
+ ...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr }
709
+ });
710
+ var evaluateFromContext = async (ctx, opts) => {
711
+ const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
712
+ if (!result.ok) {
713
+ return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };
714
+ }
715
+ const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);
716
+ if (weak !== null) {
717
+ return {
718
+ ok: false,
719
+ body: buildAipWeakAuthBody({
720
+ detail: weak,
721
+ ...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
722
+ ...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr },
723
+ ...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers }
724
+ })
725
+ };
726
+ }
727
+ return { ok: true, ait: result.ait };
728
+ };
729
+ var evaluateAipRequest = (req, opts) => evaluateFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);
645
730
 
646
731
  // src/core.ts
647
732
  import { createHash } from "crypto";
@@ -720,7 +805,7 @@ function stripTrailingSlashes(s) {
720
805
  while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
721
806
  return end === s.length ? s : s.slice(0, end);
722
807
  }
723
- var CANONICAL_AGENTSCORE_API = "https://api.agentscore.sh";
808
+ var CANONICAL_AGENTSCORE_API = "https://api.agentscore.com";
724
809
  var WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({
725
810
  action: "resign_or_switch_to_operator_token",
726
811
  steps: [
@@ -752,7 +837,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
752
837
  return {
753
838
  save_for_future_agentscore_gates: true,
754
839
  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.",
755
- quickstart: "https://docs.agentscore.sh/guides/agent-identity",
840
+ quickstart: "https://docs.agentscore.com/guides/agent-identity",
756
841
  identity_check_endpoint: `${api}/v1/credentials`,
757
842
  identity_paths: {
758
843
  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.",
@@ -769,7 +854,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
769
854
  }
770
855
  function createAgentScoreCore(options) {
771
856
  if (!options.apiKey) {
772
- throw new Error("AgentScore API key is required. Get one at https://agentscore.sh/sign-up");
857
+ throw new Error("AgentScore API key is required. Get one at https://www.agentscore.com/sign-up");
773
858
  }
774
859
  const {
775
860
  apiKey,
@@ -780,7 +865,7 @@ function createAgentScoreCore(options) {
780
865
  allowedJurisdictions,
781
866
  failOpen = false,
782
867
  cacheSeconds = 300,
783
- baseUrl: rawBaseUrl = "https://api.agentscore.sh",
868
+ baseUrl: rawBaseUrl = "https://api.agentscore.com",
784
869
  chain: gateChain,
785
870
  userAgent,
786
871
  createSessionOnMissing,
@@ -788,7 +873,7 @@ function createAgentScoreCore(options) {
788
873
  } = options;
789
874
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
790
875
  const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
791
- const defaultUa = `@agent-score/commerce@${"2.5.0"}`;
876
+ const defaultUa = `@agent-score/commerce@${"2.6.1"}`;
792
877
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
793
878
  const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
794
879
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -806,7 +891,6 @@ function createAgentScoreCore(options) {
806
891
  return s;
807
892
  }
808
893
  const cache = new TTLCache(cacheSeconds * 1e3);
809
- const lastSignerRaw = /* @__PURE__ */ new Map();
810
894
  async function tryMintSessionDenial(ctx) {
811
895
  if (!createSessionOnMissing) return void 0;
812
896
  try {
@@ -878,7 +962,7 @@ function createAgentScoreCore(options) {
878
962
  ...aipStep,
879
963
  "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.",
880
964
  "If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
881
- "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."
965
+ "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://www.agentscore.com/sign-up to create an AgentScore identity and mint an operator_token from their dashboard (https://www.agentscore.com/dashboard/verify). The user hands the opc_... to you, and you retry with X-Operator-Token."
882
966
  ],
883
967
  user_message: "Try X-Wallet-Address first if you have a wallet and the merchant accepts Tempo/x402; fall back to a stored X-Operator-Token, then to the session/verify flow described in agent_memory.bootstrap."
884
968
  });
@@ -891,21 +975,26 @@ function createAgentScoreCore(options) {
891
975
  }
892
976
  };
893
977
  }
894
- const cacheKey = identity.aipToken ? `aip:${createHash("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
978
+ const identityKey = identity.aipToken ? `aip:${createHash("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
979
+ const cacheKey = signer ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)]) : JSON.stringify([identityKey]);
895
980
  const cached = cache.get(cacheKey);
896
981
  if (cached) {
982
+ const cachedVerdict = cached.raw ? buildSignerVerdict(identity, cached.raw) : void 0;
897
983
  if (cached.allow) {
898
984
  const cachedRaw = cached.raw;
899
985
  const cachedQuota = cachedRaw?.quota;
900
986
  return {
901
987
  kind: "allow",
902
988
  data: cachedRaw,
903
- ...cachedQuota !== void 0 && { quota: cachedQuota }
989
+ ...cachedQuota !== void 0 && { quota: cachedQuota },
990
+ ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
904
991
  };
905
992
  }
906
993
  if (isFixableDenial(cached.reasons)) {
907
994
  const sessionReason = await tryMintSessionDenial(ctx);
908
- if (sessionReason) return { kind: "deny", reason: sessionReason };
995
+ if (sessionReason) {
996
+ return { kind: "deny", reason: sessionReason, ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict } };
997
+ }
909
998
  }
910
999
  return {
911
1000
  kind: "deny",
@@ -915,7 +1004,8 @@ function createAgentScoreCore(options) {
915
1004
  reasons: cached.reasons,
916
1005
  verify_url: cached.raw?.verify_url,
917
1006
  data: cached.raw
918
- }
1007
+ },
1008
+ ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
919
1009
  };
920
1010
  }
921
1011
  const policy = {};
@@ -936,7 +1026,10 @@ function createAgentScoreCore(options) {
936
1026
  // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
937
1027
  ...signer && { signer: { address: signer.address, network: signer.network } }
938
1028
  };
939
- 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 });
1029
+ if (identity.aipToken !== void 0 && identity.aipSignature === void 0) {
1030
+ throw new Error("AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).");
1031
+ }
1032
+ const result = identity.aipToken !== void 0 && identity.aipSignature !== void 0 ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken, aipSignature: identity.aipSignature }) : identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
940
1033
  data = result;
941
1034
  } catch (err) {
942
1035
  if (err instanceof PaymentRequiredError) {
@@ -1007,20 +1100,21 @@ function createAgentScoreCore(options) {
1007
1100
  const decisionReasons = data.decision_reasons ?? [];
1008
1101
  const allow = decision === "allow" || decision == null;
1009
1102
  cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
1010
- if (identity.address !== void 0 && identity.operatorToken === void 0 && identity.aipToken === void 0 && (data.signer_match !== void 0 || data.signer_sanctions !== void 0)) {
1011
- lastSignerRaw.set(normalizeAddress(identity.address), data);
1012
- }
1103
+ const signerVerdict = buildSignerVerdict(identity, data);
1013
1104
  if (allow) {
1014
1105
  const quota = data.quota;
1015
1106
  return {
1016
1107
  kind: "allow",
1017
1108
  data,
1018
- ...quota !== void 0 && { quota }
1109
+ ...quota !== void 0 && { quota },
1110
+ ...signerVerdict !== void 0 && { signerVerdict }
1019
1111
  };
1020
1112
  }
1021
1113
  if (isFixableDenial(decisionReasons)) {
1022
1114
  const sessionReason = await tryMintSessionDenial(ctx);
1023
- if (sessionReason) return { kind: "deny", reason: sessionReason };
1115
+ if (sessionReason) {
1116
+ return { kind: "deny", reason: sessionReason, ...signerVerdict !== void 0 && { signerVerdict } };
1117
+ }
1024
1118
  }
1025
1119
  return {
1026
1120
  kind: "deny",
@@ -1030,7 +1124,8 @@ function createAgentScoreCore(options) {
1030
1124
  reasons: decisionReasons,
1031
1125
  verify_url: data.verify_url,
1032
1126
  data
1033
- }
1127
+ },
1128
+ ...signerVerdict !== void 0 && { signerVerdict }
1034
1129
  };
1035
1130
  }
1036
1131
  async function captureWallet2(options2) {
@@ -1072,20 +1167,21 @@ function createAgentScoreCore(options) {
1072
1167
  agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
1073
1168
  };
1074
1169
  }
1075
- function getSignerVerdict2(claimedAddress) {
1076
- const claimedNorm = normalizeAddress(claimedAddress);
1077
- const raw = lastSignerRaw.get(claimedNorm) ?? cache.get(claimedNorm)?.raw;
1078
- if (!raw) return void 0;
1170
+ function buildSignerVerdict(identity, raw) {
1171
+ if (identity.address === void 0 || identity.operatorToken !== void 0 || identity.aipToken !== void 0) {
1172
+ return void 0;
1173
+ }
1079
1174
  const rawMatch = raw.signer_match;
1080
1175
  const rawSanctions = raw.signer_sanctions;
1081
1176
  if (!rawMatch && !rawSanctions) return void 0;
1177
+ const claimedNorm = normalizeAddress(identity.address);
1082
1178
  const signerNorm = rawMatch?.actual_signer ?? claimedNorm;
1083
1179
  return {
1084
1180
  signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,
1085
1181
  signer_sanctions: rawSanctions ?? null
1086
1182
  };
1087
1183
  }
1088
- return { evaluate, captureWallet: captureWallet2, getSignerVerdict: getSignerVerdict2 };
1184
+ return { evaluate, captureWallet: captureWallet2 };
1089
1185
  }
1090
1186
 
1091
1187
  // src/payment/payment_header.ts
@@ -1217,18 +1313,23 @@ function agentscoreGate(options) {
1217
1313
  const signer = await extractPaymentSigner(c.req.raw, readX402PaymentHeader(c.req.raw));
1218
1314
  const outcome = await core.evaluate(identity, c, signer);
1219
1315
  if (outcome.kind === "allow") {
1220
- if (outcome.degraded || outcome.quota) {
1316
+ if (outcome.degraded || outcome.quota || outcome.signerVerdict) {
1221
1317
  const prev = c.get(GATE_STATE_KEY);
1222
1318
  c.set(GATE_STATE_KEY, {
1223
1319
  ...prev,
1224
1320
  ...outcome.degraded && { degraded: true, infraReason: outcome.infraReason },
1225
- ...outcome.quota && { quota: outcome.quota }
1321
+ ...outcome.quota && { quota: outcome.quota },
1322
+ ...outcome.signerVerdict && { signerVerdict: outcome.signerVerdict }
1226
1323
  });
1227
1324
  }
1228
1325
  if (outcome.data) c.set(CONTEXT_KEY, outcome.data);
1229
1326
  await next();
1230
1327
  return;
1231
1328
  }
1329
+ if (outcome.signerVerdict) {
1330
+ const prev = c.get(GATE_STATE_KEY);
1331
+ c.set(GATE_STATE_KEY, { ...prev, signerVerdict: outcome.signerVerdict });
1332
+ }
1232
1333
  return onDenied(c, outcome.reason);
1233
1334
  };
1234
1335
  }
@@ -1255,8 +1356,7 @@ async function captureWallet(c, options) {
1255
1356
  }
1256
1357
  function getSignerVerdict(c) {
1257
1358
  const state = c.get(GATE_STATE_KEY);
1258
- if (!state?.walletAddress) return void 0;
1259
- return state.core.getSignerVerdict(state.walletAddress);
1359
+ return state?.signerVerdict;
1260
1360
  }
1261
1361
  function conditionalAgentscoreGate(options) {
1262
1362
  const gate = agentscoreGate(options);
@@ -1278,9 +1378,9 @@ function defaultAipOnDenied(_c, body) {
1278
1378
  function aipGate(options) {
1279
1379
  const { onDenied = defaultAipOnDenied, ...gateOpts } = options;
1280
1380
  return async (c, next) => {
1281
- const result = await verifyAitRequest(c.req.raw, gateOpts);
1381
+ const result = await evaluateAipRequest(c.req.raw, gateOpts);
1282
1382
  if (!result.ok) {
1283
- return onDenied(c, buildAipErrorBody(result.failure));
1383
+ return onDenied(c, result.body);
1284
1384
  }
1285
1385
  c.set(AIT_CONTEXT_KEY, result.ait);
1286
1386
  await next();