@agent-score/commerce 1.0.3 → 1.1.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 (52) hide show
  1. package/README.md +27 -0
  2. package/dist/challenge/index.js +58 -0
  3. package/dist/challenge/index.js.map +1 -1
  4. package/dist/challenge/index.mjs +65 -0
  5. package/dist/challenge/index.mjs.map +1 -1
  6. package/dist/core.d.mts +28 -1
  7. package/dist/core.d.ts +28 -1
  8. package/dist/core.js +237 -157
  9. package/dist/core.js.map +1 -1
  10. package/dist/core.mjs +246 -157
  11. package/dist/core.mjs.map +1 -1
  12. package/dist/discovery/index.js.map +1 -1
  13. package/dist/discovery/index.mjs.map +1 -1
  14. package/dist/identity/express.d.mts +18 -2
  15. package/dist/identity/express.d.ts +18 -2
  16. package/dist/identity/express.js +227 -164
  17. package/dist/identity/express.js.map +1 -1
  18. package/dist/identity/express.mjs +232 -164
  19. package/dist/identity/express.mjs.map +1 -1
  20. package/dist/identity/fastify.d.mts +17 -2
  21. package/dist/identity/fastify.d.ts +17 -2
  22. package/dist/identity/fastify.js +227 -164
  23. package/dist/identity/fastify.js.map +1 -1
  24. package/dist/identity/fastify.mjs +232 -164
  25. package/dist/identity/fastify.mjs.map +1 -1
  26. package/dist/identity/hono.d.mts +22 -2
  27. package/dist/identity/hono.d.ts +22 -2
  28. package/dist/identity/hono.js +227 -164
  29. package/dist/identity/hono.js.map +1 -1
  30. package/dist/identity/hono.mjs +232 -164
  31. package/dist/identity/hono.mjs.map +1 -1
  32. package/dist/identity/nextjs.d.mts +8 -1
  33. package/dist/identity/nextjs.d.ts +8 -1
  34. package/dist/identity/nextjs.js +213 -166
  35. package/dist/identity/nextjs.js.map +1 -1
  36. package/dist/identity/nextjs.mjs +220 -166
  37. package/dist/identity/nextjs.mjs.map +1 -1
  38. package/dist/identity/web.d.mts +15 -1
  39. package/dist/identity/web.d.ts +15 -1
  40. package/dist/identity/web.js +213 -166
  41. package/dist/identity/web.js.map +1 -1
  42. package/dist/identity/web.mjs +220 -166
  43. package/dist/identity/web.mjs.map +1 -1
  44. package/dist/index.js +120 -101
  45. package/dist/index.js.map +1 -1
  46. package/dist/index.mjs +127 -101
  47. package/dist/index.mjs.map +1 -1
  48. package/dist/payment/index.js.map +1 -1
  49. package/dist/payment/index.mjs.map +1 -1
  50. package/dist/stripe-multichain/index.js.map +1 -1
  51. package/dist/stripe-multichain/index.mjs.map +1 -1
  52. package/package.json +3 -3
@@ -126,10 +126,10 @@ var WALLET_NOT_TRUSTED_INSTRUCTIONS = JSON.stringify({
126
126
  var PAYMENT_REQUIRED_INSTRUCTIONS = JSON.stringify({
127
127
  action: "contact_merchant",
128
128
  steps: [
129
- "The merchant's AgentScore tier does not include the assess feature, so agent identity cannot be evaluated. This is a merchant-side configuration gap \u2014 there is no agent-side recovery.",
130
- "Contact the merchant (their support channel \u2014 typically listed in /llms.txt or the OpenAPI servers metadata) and request they upgrade their AgentScore plan."
129
+ "The merchant's AgentScore account does not have the assess endpoint enabled, so agent identity cannot be evaluated. This is a merchant-side configuration gap \u2014 there is no agent-side recovery.",
130
+ "Contact the merchant (their support channel \u2014 typically listed in /llms.txt or the OpenAPI servers metadata) so they can resolve the configuration on their side."
131
131
  ],
132
- user_message: "This merchant's identity gate is misconfigured (AgentScore tier doesn't support assess). Contact the merchant \u2014 there's nothing to fix on the agent side."
132
+ user_message: "This merchant's identity gate is misconfigured. Contact the merchant \u2014 there's nothing to fix on the agent side."
133
133
  });
134
134
  var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
135
135
  action: "deliver_verify_url_and_poll",
@@ -140,6 +140,24 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
140
140
  ],
141
141
  user_message: "Identity verification is required. Visit verify_url, then poll poll_url for the operator token and retry."
142
142
  });
143
+ var API_ERROR_INSTRUCTIONS = JSON.stringify({
144
+ action: "retry_with_backoff",
145
+ steps: [
146
+ "Verification is temporarily unavailable. Retry the request after 5\u201330 seconds with exponential backoff.",
147
+ "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.",
148
+ "If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
149
+ ],
150
+ user_message: "Verification is temporarily unavailable. Please try again in a moment \u2014 this is a transient issue, not a problem with your account."
151
+ });
152
+ var QUOTA_EXCEEDED_INSTRUCTIONS = JSON.stringify({
153
+ action: "contact_merchant",
154
+ steps: [
155
+ "AgentScore identity verification is unavailable for this merchant. This is a merchant-side issue and is NOT recoverable via retry.",
156
+ "Do not retry: the same 503 will be returned until the merchant resolves the issue on their side.",
157
+ "Surface to the user with the merchant's support contact. The merchant (not the agent) needs to act."
158
+ ],
159
+ user_message: "This merchant's identity verification is temporarily unavailable. Try again later, or contact the merchant directly."
160
+ });
143
161
  var TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
144
162
  action: "deliver_verify_url_and_poll",
145
163
  steps: [
@@ -150,6 +168,7 @@ var TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
150
168
  user_message: "Operator token is expired or revoked. A new verification session has been minted \u2014 visit verify_url to refresh."
151
169
  });
152
170
  var DEFAULT_AGENT_INSTRUCTIONS = {
171
+ api_error: API_ERROR_INSTRUCTIONS,
153
172
  wallet_not_trusted: WALLET_NOT_TRUSTED_INSTRUCTIONS,
154
173
  payment_required: PAYMENT_REQUIRED_INSTRUCTIONS,
155
174
  identity_verification_required: IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS,
@@ -160,7 +179,7 @@ var DEFAULT_MESSAGES = {
160
179
  identity_verification_required: "Identity verification is required to access this resource. Visit verify_url to complete KYC.",
161
180
  wallet_not_trusted: "The wallet does not meet the merchant compliance policy.",
162
181
  api_error: "AgentScore is unreachable. This is transient \u2014 retry in a few seconds.",
163
- payment_required: "AgentScore tier does not support assess. Contact support.",
182
+ payment_required: "Assess endpoint not enabled for this merchant. Contact support.",
164
183
  wallet_signer_mismatch: "Payment signer does not match the wallet claimed via X-Wallet-Address. The signer and the claimed wallet must both resolve to the same AgentScore operator.",
165
184
  wallet_auth_requires_wallet_signing: "X-Wallet-Address was sent with a rail that has no wallet signature (Stripe SPT / card). Switch to X-Operator-Token, or use a wallet-signing rail (Tempo MPP, x402).",
166
185
  token_expired: "The operator token is expired or revoked. A fresh verification session has been minted \u2014 visit verify_url to mint a new token.",
@@ -199,9 +218,6 @@ function denialReasonToBody(reason) {
199
218
  if (reason.expected_signer) body.expected_signer = reason.expected_signer;
200
219
  if (reason.actual_signer) body.actual_signer = reason.actual_signer;
201
220
  if (reason.linked_wallets && reason.linked_wallets.length > 0) body.linked_wallets = reason.linked_wallets;
202
- if (reason.code === "api_error" && !(reason.extra && reason.extra.next_steps)) {
203
- body.next_steps = { action: "retry", retry_after_seconds: 5 };
204
- }
205
221
  if (reason.extra) {
206
222
  for (const [key, value] of Object.entries(reason.extra)) {
207
223
  if (RESERVED_FIELDS.has(key)) {
@@ -214,6 +230,9 @@ function denialReasonToBody(reason) {
214
230
  return body;
215
231
  }
216
232
 
233
+ // src/core.ts
234
+ var import_sdk = require("@agent-score/sdk");
235
+
217
236
  // src/address.ts
218
237
  var SOLANA_BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
219
238
  var isSolanaAddress = (address) => SOLANA_BASE58_RE.test(address) && !address.startsWith("0x");
@@ -342,9 +361,23 @@ function createAgentScoreCore(options) {
342
361
  } = options;
343
362
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
344
363
  const agentMemoryHint = buildAgentMemoryHint();
345
- const defaultUa = `@agent-score/commerce@${"1.0.3"}`;
364
+ const defaultUa = `@agent-score/commerce@${"1.1.0"}`;
346
365
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
347
- const API_TIMEOUT_MS = 1e4;
366
+ const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
367
+ const sessionSdkCache = /* @__PURE__ */ new Map();
368
+ function getSessionSdk(sessionApiKey, sessionBaseUrl) {
369
+ const key = `${sessionApiKey}|${sessionBaseUrl ?? ""}`;
370
+ let s = sessionSdkCache.get(key);
371
+ if (!s) {
372
+ s = new import_sdk.AgentScore({
373
+ apiKey: sessionApiKey,
374
+ baseUrl: sessionBaseUrl ?? baseUrl,
375
+ userAgent: userAgentHeader
376
+ });
377
+ sessionSdkCache.set(key, s);
378
+ }
379
+ return s;
380
+ }
348
381
  const cache = new TTLCache(cacheSeconds * 1e3);
349
382
  async function tryMintSessionDenial(ctx) {
350
383
  if (!createSessionOnMissing) return void 0;
@@ -361,20 +394,11 @@ function createAgentScoreCore(options) {
361
394
  console.warn("[gate] createSessionOnMissing.getSessionOptions hook failed:", err instanceof Error ? err.message : err);
362
395
  }
363
396
  }
364
- const sessionBaseUrl = stripTrailingSlashes(createSessionOnMissing.baseUrl ?? "https://api.agentscore.sh");
365
- const sessionRes = await fetch(`${sessionBaseUrl}/v1/sessions`, {
366
- method: "POST",
367
- headers: {
368
- "X-API-Key": createSessionOnMissing.apiKey,
369
- "Content-Type": "application/json",
370
- Accept: "application/json",
371
- "User-Agent": userAgentHeader
372
- },
373
- body: JSON.stringify(sessionBody),
374
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
397
+ const sessionSdk = getSessionSdk(createSessionOnMissing.apiKey, createSessionOnMissing.baseUrl);
398
+ const data = await sessionSdk.createSession({
399
+ ...sessionBody.context !== void 0 ? { context: sessionBody.context } : {},
400
+ ...sessionBody.product_name !== void 0 ? { product_name: sessionBody.product_name } : {}
375
401
  });
376
- if (!sessionRes.ok) return void 0;
377
- const data = await sessionRes.json();
378
402
  if (typeof data.session_id !== "string" || typeof data.poll_secret !== "string" || typeof data.verify_url !== "string") {
379
403
  console.warn("[gate] /v1/sessions returned 200 without required fields \u2014 falling back to bare denial");
380
404
  return void 0;
@@ -438,7 +462,13 @@ function createAgentScoreCore(options) {
438
462
  const cached = cache.get(cacheKey);
439
463
  if (cached) {
440
464
  if (cached.allow) {
441
- return { kind: "allow", data: cached.raw };
465
+ const cachedRaw = cached.raw;
466
+ const cachedQuota = cachedRaw?.quota;
467
+ return {
468
+ kind: "allow",
469
+ data: cachedRaw,
470
+ ...cachedQuota !== void 0 && { quota: cachedQuota }
471
+ };
442
472
  }
443
473
  if (isFixableDenial(cached.reasons)) {
444
474
  const sessionReason = await tryMintSessionDenial(ctx);
@@ -455,130 +485,119 @@ function createAgentScoreCore(options) {
455
485
  }
456
486
  };
457
487
  }
488
+ const policy = {};
489
+ if (requireKyc != null) policy.require_kyc = requireKyc;
490
+ if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;
491
+ if (minAge != null) policy.min_age = minAge;
492
+ if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;
493
+ if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;
494
+ let data;
458
495
  try {
459
- const body = {};
460
- if (identity.address) body.address = identity.address;
461
- if (identity.operatorToken) body.operator_token = identity.operatorToken;
462
- if (gateChain) body.chain = gateChain;
463
- const policy = {};
464
- if (requireKyc != null) policy.require_kyc = requireKyc;
465
- if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;
466
- if (minAge != null) policy.min_age = minAge;
467
- if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;
468
- if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;
469
- if (Object.keys(policy).length > 0) body.policy = policy;
470
- const response = await fetch(`${baseUrl}/v1/assess`, {
471
- method: "POST",
472
- headers: {
473
- "X-API-Key": apiKey,
474
- "Content-Type": "application/json",
475
- Accept: "application/json",
476
- "User-Agent": userAgentHeader
477
- },
478
- body: JSON.stringify(body),
479
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
480
- });
481
- if (response.status === 402) {
496
+ const opts = {
497
+ chain: gateChain,
498
+ ...Object.keys(policy).length > 0 ? { policy } : {}
499
+ };
500
+ const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
501
+ data = result;
502
+ } catch (err) {
503
+ if (err instanceof import_sdk.PaymentRequiredError) {
482
504
  if (failOpen) return { kind: "allow" };
483
505
  return { kind: "deny", reason: { code: "payment_required" } };
484
506
  }
485
- if (response.status === 401) {
486
- try {
487
- const errData = await response.clone().json();
488
- const code = errData?.error?.code;
489
- if (code === "token_expired") {
490
- return {
491
- kind: "deny",
492
- reason: {
493
- code,
494
- data: errData,
495
- ...typeof errData.verify_url === "string" ? { verify_url: errData.verify_url } : {},
496
- ...typeof errData.session_id === "string" ? { session_id: errData.session_id } : {},
497
- ...typeof errData.poll_secret === "string" ? { poll_secret: errData.poll_secret } : {},
498
- ...typeof errData.poll_url === "string" ? { poll_url: errData.poll_url } : {},
499
- ...errData.next_steps ? { agent_instructions: JSON.stringify(errData.next_steps) } : {},
500
- ...errData.agent_memory ? { agent_memory: errData.agent_memory } : {}
501
- }
502
- };
507
+ if (err instanceof import_sdk.TokenExpiredError) {
508
+ return {
509
+ kind: "deny",
510
+ reason: {
511
+ code: "token_expired",
512
+ data: err.details,
513
+ ...err.verifyUrl ? { verify_url: err.verifyUrl } : {},
514
+ ...err.sessionId ? { session_id: err.sessionId } : {},
515
+ ...err.pollSecret ? { poll_secret: err.pollSecret } : {},
516
+ ...err.pollUrl ? { poll_url: err.pollUrl } : {},
517
+ ...err.nextSteps ? { agent_instructions: JSON.stringify(err.nextSteps) } : {},
518
+ ...err.agentMemory ? { agent_memory: err.agentMemory } : {}
503
519
  }
504
- if (code === "invalid_credential") {
505
- return {
506
- kind: "deny",
507
- reason: {
508
- code: "invalid_credential",
509
- agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,
510
- agent_memory: agentMemoryHint
511
- }
512
- };
513
- }
514
- if (code) {
515
- console.warn(`[gate] /v1/assess returned 401 ${code} \u2014 no specific handler, surfacing as api_error.`);
516
- }
517
- } catch (err) {
518
- console.warn("[gate] /v1/assess 401 body parse failed:", err instanceof Error ? err.message : err);
519
- }
520
+ };
520
521
  }
521
- if (response.status >= 400 && response.status < 500 && response.status !== 402) {
522
- try {
523
- const errData = await response.clone().json();
524
- const code = errData?.error?.code;
525
- if (code && code !== "token_expired" && code !== "invalid_credential") {
526
- console.warn(
527
- `[gate] /v1/assess returned ${response.status} ${code} \u2014 surfacing as api_error. Validate input shape before invoking the gate to avoid this.`
528
- );
522
+ if (err instanceof import_sdk.InvalidCredentialError) {
523
+ return {
524
+ kind: "deny",
525
+ reason: {
526
+ code: "invalid_credential",
527
+ agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,
528
+ agent_memory: agentMemoryHint
529
529
  }
530
- } catch {
531
- }
530
+ };
532
531
  }
533
- if (!response.ok) {
534
- throw new Error(`AgentScore API returned ${response.status}`);
532
+ if (err instanceof import_sdk.QuotaExceededError) {
533
+ console.warn("[gate] /v1/assess returned 429 quota_exceeded");
534
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "quota_exceeded" };
535
+ return {
536
+ kind: "deny",
537
+ reason: { code: "api_error", agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS }
538
+ };
535
539
  }
536
- const data = await response.json();
537
- const decision = data.decision;
538
- const decisionReasons = data.decision_reasons ?? [];
539
- const allow = decision === "allow" || decision == null;
540
- cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
541
- if (allow) {
542
- return { kind: "allow", data };
540
+ if (err instanceof import_sdk.TimeoutError) {
541
+ console.warn("[gate] /v1/assess timed out:", err.message);
542
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "network_timeout" };
543
+ return { kind: "deny", reason: { code: "api_error" } };
543
544
  }
544
- if (isFixableDenial(decisionReasons)) {
545
- const sessionReason = await tryMintSessionDenial(ctx);
546
- if (sessionReason) return { kind: "deny", reason: sessionReason };
545
+ const status = err?.status;
546
+ const errName = err instanceof Error ? err.name : "";
547
+ if (status === 429) {
548
+ console.warn("[gate] /v1/assess returned 429 (untyped \u2014 defensive)");
549
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "quota_exceeded" };
550
+ return {
551
+ kind: "deny",
552
+ reason: { code: "api_error", agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS }
553
+ };
554
+ }
555
+ if (errName === "TimeoutError" || errName === "AbortError") {
556
+ console.warn("[gate] /v1/assess timed out (by Error.name):", err instanceof Error ? err.message : err);
557
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "network_timeout" };
558
+ return { kind: "deny", reason: { code: "api_error" } };
547
559
  }
560
+ const errCode = err?.code;
561
+ const msg = err instanceof Error ? err.message : String(err);
562
+ const detail = errCode ? `${errCode}: ${msg}` : msg;
563
+ console.warn(`[gate] /v1/assess call failed \u2014 surfacing as api_error: ${detail}`);
564
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "api_error" };
565
+ return { kind: "deny", reason: { code: "api_error" } };
566
+ }
567
+ const decision = data.decision;
568
+ const decisionReasons = data.decision_reasons ?? [];
569
+ const allow = decision === "allow" || decision == null;
570
+ cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
571
+ if (allow) {
572
+ const quota = data.quota;
548
573
  return {
549
- kind: "deny",
550
- reason: {
551
- code: "wallet_not_trusted",
552
- decision: decision ?? void 0,
553
- reasons: decisionReasons,
554
- verify_url: data.verify_url,
555
- data
556
- }
574
+ kind: "allow",
575
+ data,
576
+ ...quota !== void 0 && { quota }
557
577
  };
558
- } catch (err) {
559
- console.warn("[gate] /v1/assess call failed \u2014 surfacing as api_error:", err instanceof Error ? err.message : err);
560
- if (failOpen) return { kind: "allow" };
561
- return { kind: "deny", reason: { code: "api_error" } };
562
578
  }
579
+ if (isFixableDenial(decisionReasons)) {
580
+ const sessionReason = await tryMintSessionDenial(ctx);
581
+ if (sessionReason) return { kind: "deny", reason: sessionReason };
582
+ }
583
+ return {
584
+ kind: "deny",
585
+ reason: {
586
+ code: "wallet_not_trusted",
587
+ decision: decision ?? void 0,
588
+ reasons: decisionReasons,
589
+ verify_url: data.verify_url,
590
+ data
591
+ }
592
+ };
563
593
  }
564
594
  async function captureWallet(options2) {
565
595
  try {
566
- const body = {
567
- operator_token: options2.operatorToken,
568
- wallet_address: options2.walletAddress,
569
- network: options2.network
570
- };
571
- if (options2.idempotencyKey) body.idempotency_key = options2.idempotencyKey;
572
- await fetch(`${baseUrl}/v1/credentials/wallets`, {
573
- method: "POST",
574
- headers: {
575
- "X-API-Key": apiKey,
576
- "Content-Type": "application/json",
577
- Accept: "application/json",
578
- "User-Agent": userAgentHeader
579
- },
580
- body: JSON.stringify(body),
581
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
596
+ await sdk.associateWallet({
597
+ operatorToken: options2.operatorToken,
598
+ walletAddress: options2.walletAddress,
599
+ network: options2.network,
600
+ ...options2.idempotencyKey ? { idempotencyKey: options2.idempotencyKey } : {}
582
601
  });
583
602
  } catch (err) {
584
603
  console.warn("[agentscore-commerce] captureWallet failed:", err instanceof Error ? err.message : err);
@@ -603,19 +622,7 @@ function createAgentScoreCore(options) {
603
622
  return { ok: true, ...extractFromCached(resolveCached.raw) };
604
623
  }
605
624
  try {
606
- const response = await fetch(`${baseUrl}/v1/assess`, {
607
- method: "POST",
608
- headers: {
609
- "X-API-Key": apiKey,
610
- "Content-Type": "application/json",
611
- Accept: "application/json",
612
- "User-Agent": userAgentHeader
613
- },
614
- body: JSON.stringify({ address: walletAddress }),
615
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
616
- });
617
- if (!response.ok) return { ok: false };
618
- const data = await response.json();
625
+ const data = await sdk.assess(walletAddress);
619
626
  cache.set(`resolve:${wallet}`, { allow: true, raw: data });
620
627
  return { ok: true, ...extractFromCached(data) };
621
628
  } catch (err) {
@@ -624,28 +631,37 @@ function createAgentScoreCore(options) {
624
631
  }
625
632
  }
626
633
  function reportSignerEvent(kind) {
627
- try {
628
- const pending = fetch(`${baseUrl}/v1/telemetry/signer-match`, {
629
- method: "POST",
630
- headers: {
631
- "X-API-Key": apiKey,
632
- "Content-Type": "application/json",
633
- Accept: "application/json",
634
- "User-Agent": userAgentHeader
635
- },
636
- body: JSON.stringify({ kind }),
637
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
638
- });
639
- if (pending && typeof pending.catch === "function") {
640
- pending.catch((err) => {
641
- console.warn("[agentscore-commerce] signer-match telemetry failed:", err instanceof Error ? err.message : err);
642
- });
643
- }
644
- } catch {
634
+ void sdk.telemetrySignerMatch({ kind });
635
+ }
636
+ function projectSignerMatch(sm, claimedNorm, signerNorm) {
637
+ const kind = sm.kind;
638
+ if (kind === "pass") {
639
+ return {
640
+ kind: "pass",
641
+ claimedOperator: sm.claimed_operator ?? null,
642
+ signerOperator: sm.signer_operator ?? null
643
+ };
645
644
  }
645
+ if (kind === "wallet_auth_requires_wallet_signing") {
646
+ return {
647
+ kind: "wallet_auth_requires_wallet_signing",
648
+ claimedWallet: sm.claimed_wallet ?? claimedNorm,
649
+ agentInstructions: sm.agent_instructions ?? WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS
650
+ };
651
+ }
652
+ const linked = sm.linked_wallets;
653
+ return {
654
+ kind: "wallet_signer_mismatch",
655
+ claimedOperator: sm.claimed_operator ?? null,
656
+ actualSignerOperator: sm.signer_operator ?? null,
657
+ expectedSigner: sm.expected_signer ?? claimedNorm,
658
+ actualSigner: sm.actual_signer ?? signerNorm,
659
+ linkedWallets: Array.isArray(linked) ? linked.filter((w) => typeof w === "string") : [],
660
+ agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
661
+ };
646
662
  }
647
663
  async function verifyWalletSignerMatch(options2) {
648
- const { claimedWallet, signer } = options2;
664
+ const { claimedWallet, signer, network } = options2;
649
665
  if (!signer) {
650
666
  reportSignerEvent("wallet_auth_requires_wallet_signing");
651
667
  return {
@@ -660,6 +676,35 @@ function createAgentScoreCore(options) {
660
676
  reportSignerEvent("pass");
661
677
  return { kind: "pass", claimedOperator: null, signerOperator: null };
662
678
  }
679
+ const cachedEntry = cache.get(claimedNorm);
680
+ const cachedMatch = cachedEntry?.signerMatchBySigner?.get(signerNorm);
681
+ if (cachedMatch) {
682
+ return projectSignerMatch(cachedMatch, claimedNorm, signerNorm);
683
+ }
684
+ const inferredNetwork = network ?? (signerNorm.startsWith("0x") ? "evm" : "solana");
685
+ let assessResponse;
686
+ try {
687
+ assessResponse = await sdk.assess(claimedNorm, {
688
+ resolveSigner: { address: signerNorm, network: inferredNetwork }
689
+ });
690
+ } catch (err) {
691
+ console.warn("[gate] verifyWalletSignerMatch assess failed:", err instanceof Error ? err.message : err);
692
+ reportSignerEvent("api_error");
693
+ return { kind: "api_error", claimedWallet: claimedNorm };
694
+ }
695
+ const signerMatch = assessResponse.signer_match;
696
+ if (signerMatch && typeof signerMatch === "object") {
697
+ if (cachedEntry) {
698
+ const map = cachedEntry.signerMatchBySigner ?? /* @__PURE__ */ new Map();
699
+ map.set(signerNorm, signerMatch);
700
+ cachedEntry.signerMatchBySigner = map;
701
+ } else {
702
+ const entry = { allow: true, raw: assessResponse };
703
+ entry.signerMatchBySigner = /* @__PURE__ */ new Map([[signerNorm, signerMatch]]);
704
+ cache.set(claimedNorm, entry);
705
+ }
706
+ return projectSignerMatch(signerMatch, claimedNorm, signerNorm);
707
+ }
663
708
  const [claimedResolve, signerResolve] = await Promise.all([
664
709
  resolveWalletToOperator(claimedNorm),
665
710
  resolveWalletToOperator(signerNorm)
@@ -681,8 +726,6 @@ function createAgentScoreCore(options) {
681
726
  actualSignerOperator: signerOperator,
682
727
  expectedSigner: claimedNorm,
683
728
  actualSigner: signerNorm,
684
- // Populated from /v1/assess.linked_wallets on the claimed wallet — the full set of
685
- // wallets the agent CAN sign with to satisfy the claim (same-operator rule).
686
729
  linkedWallets: claimedResolve.linkedWallets,
687
730
  agentInstructions: WALLET_SIGNER_MISMATCH_INSTRUCTIONS
688
731
  };
@@ -784,7 +827,9 @@ function createAgentScoreGate(options) {
784
827
  allowed: true,
785
828
  data: outcome.data,
786
829
  captureWallet,
787
- verifyWalletSignerMatch: verifyWalletSignerMatchBound
830
+ verifyWalletSignerMatch: verifyWalletSignerMatchBound,
831
+ ...outcome.degraded ? { degraded: true, infraReason: outcome.infraReason } : {},
832
+ ...outcome.quota ? { quota: outcome.quota } : {}
788
833
  };
789
834
  }
790
835
  const response = await onDenied(req, outcome.reason);
@@ -803,7 +848,9 @@ function withAgentScoreGate(options, handler) {
803
848
  {
804
849
  data: result.data,
805
850
  captureWallet: result.captureWallet,
806
- verifyWalletSignerMatch: result.verifyWalletSignerMatch
851
+ verifyWalletSignerMatch: result.verifyWalletSignerMatch,
852
+ ...result.degraded ? { degraded: true, infraReason: result.infraReason } : {},
853
+ ...result.quota ? { quota: result.quota } : {}
807
854
  },
808
855
  ctx
809
856
  );