@agent-score/commerce 1.0.3 → 1.2.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 (60) hide show
  1. package/README.md +28 -1
  2. package/dist/agent_instructions-d3UWTdam.d.mts +129 -0
  3. package/dist/agent_instructions-d3UWTdam.d.ts +129 -0
  4. package/dist/challenge/index.d.mts +3 -110
  5. package/dist/challenge/index.d.ts +3 -110
  6. package/dist/challenge/index.js +76 -5
  7. package/dist/challenge/index.js.map +1 -1
  8. package/dist/challenge/index.mjs +82 -5
  9. package/dist/challenge/index.mjs.map +1 -1
  10. package/dist/core.d.mts +28 -1
  11. package/dist/core.d.ts +28 -1
  12. package/dist/core.js +237 -157
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +246 -157
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/discovery/index.d.mts +120 -1
  17. package/dist/discovery/index.d.ts +120 -1
  18. package/dist/discovery/index.js +204 -0
  19. package/dist/discovery/index.js.map +1 -1
  20. package/dist/discovery/index.mjs +202 -0
  21. package/dist/discovery/index.mjs.map +1 -1
  22. package/dist/identity/express.d.mts +18 -2
  23. package/dist/identity/express.d.ts +18 -2
  24. package/dist/identity/express.js +227 -164
  25. package/dist/identity/express.js.map +1 -1
  26. package/dist/identity/express.mjs +232 -164
  27. package/dist/identity/express.mjs.map +1 -1
  28. package/dist/identity/fastify.d.mts +17 -2
  29. package/dist/identity/fastify.d.ts +17 -2
  30. package/dist/identity/fastify.js +227 -164
  31. package/dist/identity/fastify.js.map +1 -1
  32. package/dist/identity/fastify.mjs +232 -164
  33. package/dist/identity/fastify.mjs.map +1 -1
  34. package/dist/identity/hono.d.mts +22 -2
  35. package/dist/identity/hono.d.ts +22 -2
  36. package/dist/identity/hono.js +227 -164
  37. package/dist/identity/hono.js.map +1 -1
  38. package/dist/identity/hono.mjs +232 -164
  39. package/dist/identity/hono.mjs.map +1 -1
  40. package/dist/identity/nextjs.d.mts +8 -1
  41. package/dist/identity/nextjs.d.ts +8 -1
  42. package/dist/identity/nextjs.js +213 -166
  43. package/dist/identity/nextjs.js.map +1 -1
  44. package/dist/identity/nextjs.mjs +220 -166
  45. package/dist/identity/nextjs.mjs.map +1 -1
  46. package/dist/identity/web.d.mts +15 -1
  47. package/dist/identity/web.d.ts +15 -1
  48. package/dist/identity/web.js +213 -166
  49. package/dist/identity/web.js.map +1 -1
  50. package/dist/identity/web.mjs +220 -166
  51. package/dist/identity/web.mjs.map +1 -1
  52. package/dist/index.js +120 -101
  53. package/dist/index.js.map +1 -1
  54. package/dist/index.mjs +127 -101
  55. package/dist/index.mjs.map +1 -1
  56. package/dist/payment/index.js.map +1 -1
  57. package/dist/payment/index.mjs.map +1 -1
  58. package/dist/stripe-multichain/index.js.map +1 -1
  59. package/dist/stripe-multichain/index.mjs.map +1 -1
  60. package/package.json +3 -3
@@ -90,10 +90,10 @@ var WALLET_NOT_TRUSTED_INSTRUCTIONS = JSON.stringify({
90
90
  var PAYMENT_REQUIRED_INSTRUCTIONS = JSON.stringify({
91
91
  action: "contact_merchant",
92
92
  steps: [
93
- "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.",
94
- "Contact the merchant (their support channel \u2014 typically listed in /llms.txt or the OpenAPI servers metadata) and request they upgrade their AgentScore plan."
93
+ "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.",
94
+ "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."
95
95
  ],
96
- 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."
96
+ user_message: "This merchant's identity gate is misconfigured. Contact the merchant \u2014 there's nothing to fix on the agent side."
97
97
  });
98
98
  var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
99
99
  action: "deliver_verify_url_and_poll",
@@ -104,6 +104,24 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
104
104
  ],
105
105
  user_message: "Identity verification is required. Visit verify_url, then poll poll_url for the operator token and retry."
106
106
  });
107
+ var API_ERROR_INSTRUCTIONS = JSON.stringify({
108
+ action: "retry_with_backoff",
109
+ steps: [
110
+ "Verification is temporarily unavailable. Retry the request after 5\u201330 seconds with exponential backoff.",
111
+ "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.",
112
+ "If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
113
+ ],
114
+ user_message: "Verification is temporarily unavailable. Please try again in a moment \u2014 this is a transient issue, not a problem with your account."
115
+ });
116
+ var QUOTA_EXCEEDED_INSTRUCTIONS = JSON.stringify({
117
+ action: "contact_merchant",
118
+ steps: [
119
+ "AgentScore identity verification is unavailable for this merchant. This is a merchant-side issue and is NOT recoverable via retry.",
120
+ "Do not retry: the same 503 will be returned until the merchant resolves the issue on their side.",
121
+ "Surface to the user with the merchant's support contact. The merchant (not the agent) needs to act."
122
+ ],
123
+ user_message: "This merchant's identity verification is temporarily unavailable. Try again later, or contact the merchant directly."
124
+ });
107
125
  var TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
108
126
  action: "deliver_verify_url_and_poll",
109
127
  steps: [
@@ -114,6 +132,7 @@ var TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
114
132
  user_message: "Operator token is expired or revoked. A new verification session has been minted \u2014 visit verify_url to refresh."
115
133
  });
116
134
  var DEFAULT_AGENT_INSTRUCTIONS = {
135
+ api_error: API_ERROR_INSTRUCTIONS,
117
136
  wallet_not_trusted: WALLET_NOT_TRUSTED_INSTRUCTIONS,
118
137
  payment_required: PAYMENT_REQUIRED_INSTRUCTIONS,
119
138
  identity_verification_required: IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS,
@@ -124,7 +143,7 @@ var DEFAULT_MESSAGES = {
124
143
  identity_verification_required: "Identity verification is required to access this resource. Visit verify_url to complete KYC.",
125
144
  wallet_not_trusted: "The wallet does not meet the merchant compliance policy.",
126
145
  api_error: "AgentScore is unreachable. This is transient \u2014 retry in a few seconds.",
127
- payment_required: "AgentScore tier does not support assess. Contact support.",
146
+ payment_required: "Assess endpoint not enabled for this merchant. Contact support.",
128
147
  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.",
129
148
  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).",
130
149
  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.",
@@ -163,9 +182,6 @@ function denialReasonToBody(reason) {
163
182
  if (reason.expected_signer) body.expected_signer = reason.expected_signer;
164
183
  if (reason.actual_signer) body.actual_signer = reason.actual_signer;
165
184
  if (reason.linked_wallets && reason.linked_wallets.length > 0) body.linked_wallets = reason.linked_wallets;
166
- if (reason.code === "api_error" && !(reason.extra && reason.extra.next_steps)) {
167
- body.next_steps = { action: "retry", retry_after_seconds: 5 };
168
- }
169
185
  if (reason.extra) {
170
186
  for (const [key, value] of Object.entries(reason.extra)) {
171
187
  if (RESERVED_FIELDS.has(key)) {
@@ -178,6 +194,16 @@ function denialReasonToBody(reason) {
178
194
  return body;
179
195
  }
180
196
 
197
+ // src/core.ts
198
+ import {
199
+ AgentScore,
200
+ InvalidCredentialError,
201
+ PaymentRequiredError,
202
+ QuotaExceededError,
203
+ TimeoutError as SdkTimeoutError,
204
+ TokenExpiredError
205
+ } from "@agent-score/sdk";
206
+
181
207
  // src/address.ts
182
208
  var SOLANA_BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
183
209
  var isSolanaAddress = (address) => SOLANA_BASE58_RE.test(address) && !address.startsWith("0x");
@@ -306,9 +332,23 @@ function createAgentScoreCore(options) {
306
332
  } = options;
307
333
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
308
334
  const agentMemoryHint = buildAgentMemoryHint();
309
- const defaultUa = `@agent-score/commerce@${"1.0.3"}`;
335
+ const defaultUa = `@agent-score/commerce@${"1.2.0"}`;
310
336
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
311
- const API_TIMEOUT_MS = 1e4;
337
+ const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
338
+ const sessionSdkCache = /* @__PURE__ */ new Map();
339
+ function getSessionSdk(sessionApiKey, sessionBaseUrl) {
340
+ const key = `${sessionApiKey}|${sessionBaseUrl ?? ""}`;
341
+ let s = sessionSdkCache.get(key);
342
+ if (!s) {
343
+ s = new AgentScore({
344
+ apiKey: sessionApiKey,
345
+ baseUrl: sessionBaseUrl ?? baseUrl,
346
+ userAgent: userAgentHeader
347
+ });
348
+ sessionSdkCache.set(key, s);
349
+ }
350
+ return s;
351
+ }
312
352
  const cache = new TTLCache(cacheSeconds * 1e3);
313
353
  async function tryMintSessionDenial(ctx) {
314
354
  if (!createSessionOnMissing) return void 0;
@@ -325,20 +365,11 @@ function createAgentScoreCore(options) {
325
365
  console.warn("[gate] createSessionOnMissing.getSessionOptions hook failed:", err instanceof Error ? err.message : err);
326
366
  }
327
367
  }
328
- const sessionBaseUrl = stripTrailingSlashes(createSessionOnMissing.baseUrl ?? "https://api.agentscore.sh");
329
- const sessionRes = await fetch(`${sessionBaseUrl}/v1/sessions`, {
330
- method: "POST",
331
- headers: {
332
- "X-API-Key": createSessionOnMissing.apiKey,
333
- "Content-Type": "application/json",
334
- Accept: "application/json",
335
- "User-Agent": userAgentHeader
336
- },
337
- body: JSON.stringify(sessionBody),
338
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
368
+ const sessionSdk = getSessionSdk(createSessionOnMissing.apiKey, createSessionOnMissing.baseUrl);
369
+ const data = await sessionSdk.createSession({
370
+ ...sessionBody.context !== void 0 ? { context: sessionBody.context } : {},
371
+ ...sessionBody.product_name !== void 0 ? { product_name: sessionBody.product_name } : {}
339
372
  });
340
- if (!sessionRes.ok) return void 0;
341
- const data = await sessionRes.json();
342
373
  if (typeof data.session_id !== "string" || typeof data.poll_secret !== "string" || typeof data.verify_url !== "string") {
343
374
  console.warn("[gate] /v1/sessions returned 200 without required fields \u2014 falling back to bare denial");
344
375
  return void 0;
@@ -402,7 +433,13 @@ function createAgentScoreCore(options) {
402
433
  const cached = cache.get(cacheKey);
403
434
  if (cached) {
404
435
  if (cached.allow) {
405
- return { kind: "allow", data: cached.raw };
436
+ const cachedRaw = cached.raw;
437
+ const cachedQuota = cachedRaw?.quota;
438
+ return {
439
+ kind: "allow",
440
+ data: cachedRaw,
441
+ ...cachedQuota !== void 0 && { quota: cachedQuota }
442
+ };
406
443
  }
407
444
  if (isFixableDenial(cached.reasons)) {
408
445
  const sessionReason = await tryMintSessionDenial(ctx);
@@ -419,130 +456,119 @@ function createAgentScoreCore(options) {
419
456
  }
420
457
  };
421
458
  }
459
+ const policy = {};
460
+ if (requireKyc != null) policy.require_kyc = requireKyc;
461
+ if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;
462
+ if (minAge != null) policy.min_age = minAge;
463
+ if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;
464
+ if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;
465
+ let data;
422
466
  try {
423
- const body = {};
424
- if (identity.address) body.address = identity.address;
425
- if (identity.operatorToken) body.operator_token = identity.operatorToken;
426
- if (gateChain) body.chain = gateChain;
427
- const policy = {};
428
- if (requireKyc != null) policy.require_kyc = requireKyc;
429
- if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;
430
- if (minAge != null) policy.min_age = minAge;
431
- if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;
432
- if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;
433
- if (Object.keys(policy).length > 0) body.policy = policy;
434
- const response = await fetch(`${baseUrl}/v1/assess`, {
435
- method: "POST",
436
- headers: {
437
- "X-API-Key": apiKey,
438
- "Content-Type": "application/json",
439
- Accept: "application/json",
440
- "User-Agent": userAgentHeader
441
- },
442
- body: JSON.stringify(body),
443
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
444
- });
445
- if (response.status === 402) {
467
+ const opts = {
468
+ chain: gateChain,
469
+ ...Object.keys(policy).length > 0 ? { policy } : {}
470
+ };
471
+ const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
472
+ data = result;
473
+ } catch (err) {
474
+ if (err instanceof PaymentRequiredError) {
446
475
  if (failOpen) return { kind: "allow" };
447
476
  return { kind: "deny", reason: { code: "payment_required" } };
448
477
  }
449
- if (response.status === 401) {
450
- try {
451
- const errData = await response.clone().json();
452
- const code = errData?.error?.code;
453
- if (code === "token_expired") {
454
- return {
455
- kind: "deny",
456
- reason: {
457
- code,
458
- data: errData,
459
- ...typeof errData.verify_url === "string" ? { verify_url: errData.verify_url } : {},
460
- ...typeof errData.session_id === "string" ? { session_id: errData.session_id } : {},
461
- ...typeof errData.poll_secret === "string" ? { poll_secret: errData.poll_secret } : {},
462
- ...typeof errData.poll_url === "string" ? { poll_url: errData.poll_url } : {},
463
- ...errData.next_steps ? { agent_instructions: JSON.stringify(errData.next_steps) } : {},
464
- ...errData.agent_memory ? { agent_memory: errData.agent_memory } : {}
465
- }
466
- };
467
- }
468
- if (code === "invalid_credential") {
469
- return {
470
- kind: "deny",
471
- reason: {
472
- code: "invalid_credential",
473
- agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,
474
- agent_memory: agentMemoryHint
475
- }
476
- };
477
- }
478
- if (code) {
479
- console.warn(`[gate] /v1/assess returned 401 ${code} \u2014 no specific handler, surfacing as api_error.`);
478
+ if (err instanceof TokenExpiredError) {
479
+ return {
480
+ kind: "deny",
481
+ reason: {
482
+ code: "token_expired",
483
+ data: err.details,
484
+ ...err.verifyUrl ? { verify_url: err.verifyUrl } : {},
485
+ ...err.sessionId ? { session_id: err.sessionId } : {},
486
+ ...err.pollSecret ? { poll_secret: err.pollSecret } : {},
487
+ ...err.pollUrl ? { poll_url: err.pollUrl } : {},
488
+ ...err.nextSteps ? { agent_instructions: JSON.stringify(err.nextSteps) } : {},
489
+ ...err.agentMemory ? { agent_memory: err.agentMemory } : {}
480
490
  }
481
- } catch (err) {
482
- console.warn("[gate] /v1/assess 401 body parse failed:", err instanceof Error ? err.message : err);
483
- }
491
+ };
484
492
  }
485
- if (response.status >= 400 && response.status < 500 && response.status !== 402) {
486
- try {
487
- const errData = await response.clone().json();
488
- const code = errData?.error?.code;
489
- if (code && code !== "token_expired" && code !== "invalid_credential") {
490
- console.warn(
491
- `[gate] /v1/assess returned ${response.status} ${code} \u2014 surfacing as api_error. Validate input shape before invoking the gate to avoid this.`
492
- );
493
+ if (err instanceof InvalidCredentialError) {
494
+ return {
495
+ kind: "deny",
496
+ reason: {
497
+ code: "invalid_credential",
498
+ agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,
499
+ agent_memory: agentMemoryHint
493
500
  }
494
- } catch {
495
- }
501
+ };
496
502
  }
497
- if (!response.ok) {
498
- throw new Error(`AgentScore API returned ${response.status}`);
503
+ if (err instanceof QuotaExceededError) {
504
+ console.warn("[gate] /v1/assess returned 429 quota_exceeded");
505
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "quota_exceeded" };
506
+ return {
507
+ kind: "deny",
508
+ reason: { code: "api_error", agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS }
509
+ };
499
510
  }
500
- const data = await response.json();
501
- const decision = data.decision;
502
- const decisionReasons = data.decision_reasons ?? [];
503
- const allow = decision === "allow" || decision == null;
504
- cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
505
- if (allow) {
506
- return { kind: "allow", data };
511
+ if (err instanceof SdkTimeoutError) {
512
+ console.warn("[gate] /v1/assess timed out:", err.message);
513
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "network_timeout" };
514
+ return { kind: "deny", reason: { code: "api_error" } };
507
515
  }
508
- if (isFixableDenial(decisionReasons)) {
509
- const sessionReason = await tryMintSessionDenial(ctx);
510
- if (sessionReason) return { kind: "deny", reason: sessionReason };
516
+ const status = err?.status;
517
+ const errName = err instanceof Error ? err.name : "";
518
+ if (status === 429) {
519
+ console.warn("[gate] /v1/assess returned 429 (untyped \u2014 defensive)");
520
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "quota_exceeded" };
521
+ return {
522
+ kind: "deny",
523
+ reason: { code: "api_error", agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS }
524
+ };
525
+ }
526
+ if (errName === "TimeoutError" || errName === "AbortError") {
527
+ console.warn("[gate] /v1/assess timed out (by Error.name):", err instanceof Error ? err.message : err);
528
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "network_timeout" };
529
+ return { kind: "deny", reason: { code: "api_error" } };
511
530
  }
531
+ const errCode = err?.code;
532
+ const msg = err instanceof Error ? err.message : String(err);
533
+ const detail = errCode ? `${errCode}: ${msg}` : msg;
534
+ console.warn(`[gate] /v1/assess call failed \u2014 surfacing as api_error: ${detail}`);
535
+ if (failOpen) return { kind: "allow", degraded: true, infraReason: "api_error" };
536
+ return { kind: "deny", reason: { code: "api_error" } };
537
+ }
538
+ const decision = data.decision;
539
+ const decisionReasons = data.decision_reasons ?? [];
540
+ const allow = decision === "allow" || decision == null;
541
+ cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
542
+ if (allow) {
543
+ const quota = data.quota;
512
544
  return {
513
- kind: "deny",
514
- reason: {
515
- code: "wallet_not_trusted",
516
- decision: decision ?? void 0,
517
- reasons: decisionReasons,
518
- verify_url: data.verify_url,
519
- data
520
- }
545
+ kind: "allow",
546
+ data,
547
+ ...quota !== void 0 && { quota }
521
548
  };
522
- } catch (err) {
523
- console.warn("[gate] /v1/assess call failed \u2014 surfacing as api_error:", err instanceof Error ? err.message : err);
524
- if (failOpen) return { kind: "allow" };
525
- return { kind: "deny", reason: { code: "api_error" } };
526
549
  }
550
+ if (isFixableDenial(decisionReasons)) {
551
+ const sessionReason = await tryMintSessionDenial(ctx);
552
+ if (sessionReason) return { kind: "deny", reason: sessionReason };
553
+ }
554
+ return {
555
+ kind: "deny",
556
+ reason: {
557
+ code: "wallet_not_trusted",
558
+ decision: decision ?? void 0,
559
+ reasons: decisionReasons,
560
+ verify_url: data.verify_url,
561
+ data
562
+ }
563
+ };
527
564
  }
528
565
  async function captureWallet2(options2) {
529
566
  try {
530
- const body = {
531
- operator_token: options2.operatorToken,
532
- wallet_address: options2.walletAddress,
533
- network: options2.network
534
- };
535
- if (options2.idempotencyKey) body.idempotency_key = options2.idempotencyKey;
536
- await fetch(`${baseUrl}/v1/credentials/wallets`, {
537
- method: "POST",
538
- headers: {
539
- "X-API-Key": apiKey,
540
- "Content-Type": "application/json",
541
- Accept: "application/json",
542
- "User-Agent": userAgentHeader
543
- },
544
- body: JSON.stringify(body),
545
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
567
+ await sdk.associateWallet({
568
+ operatorToken: options2.operatorToken,
569
+ walletAddress: options2.walletAddress,
570
+ network: options2.network,
571
+ ...options2.idempotencyKey ? { idempotencyKey: options2.idempotencyKey } : {}
546
572
  });
547
573
  } catch (err) {
548
574
  console.warn("[agentscore-commerce] captureWallet failed:", err instanceof Error ? err.message : err);
@@ -567,19 +593,7 @@ function createAgentScoreCore(options) {
567
593
  return { ok: true, ...extractFromCached(resolveCached.raw) };
568
594
  }
569
595
  try {
570
- const response = await fetch(`${baseUrl}/v1/assess`, {
571
- method: "POST",
572
- headers: {
573
- "X-API-Key": apiKey,
574
- "Content-Type": "application/json",
575
- Accept: "application/json",
576
- "User-Agent": userAgentHeader
577
- },
578
- body: JSON.stringify({ address: walletAddress }),
579
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
580
- });
581
- if (!response.ok) return { ok: false };
582
- const data = await response.json();
596
+ const data = await sdk.assess(walletAddress);
583
597
  cache.set(`resolve:${wallet}`, { allow: true, raw: data });
584
598
  return { ok: true, ...extractFromCached(data) };
585
599
  } catch (err) {
@@ -588,28 +602,37 @@ function createAgentScoreCore(options) {
588
602
  }
589
603
  }
590
604
  function reportSignerEvent(kind) {
591
- try {
592
- const pending = fetch(`${baseUrl}/v1/telemetry/signer-match`, {
593
- method: "POST",
594
- headers: {
595
- "X-API-Key": apiKey,
596
- "Content-Type": "application/json",
597
- Accept: "application/json",
598
- "User-Agent": userAgentHeader
599
- },
600
- body: JSON.stringify({ kind }),
601
- signal: AbortSignal.timeout(API_TIMEOUT_MS)
602
- });
603
- if (pending && typeof pending.catch === "function") {
604
- pending.catch((err) => {
605
- console.warn("[agentscore-commerce] signer-match telemetry failed:", err instanceof Error ? err.message : err);
606
- });
607
- }
608
- } catch {
605
+ void sdk.telemetrySignerMatch({ kind });
606
+ }
607
+ function projectSignerMatch(sm, claimedNorm, signerNorm) {
608
+ const kind = sm.kind;
609
+ if (kind === "pass") {
610
+ return {
611
+ kind: "pass",
612
+ claimedOperator: sm.claimed_operator ?? null,
613
+ signerOperator: sm.signer_operator ?? null
614
+ };
609
615
  }
616
+ if (kind === "wallet_auth_requires_wallet_signing") {
617
+ return {
618
+ kind: "wallet_auth_requires_wallet_signing",
619
+ claimedWallet: sm.claimed_wallet ?? claimedNorm,
620
+ agentInstructions: sm.agent_instructions ?? WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS
621
+ };
622
+ }
623
+ const linked = sm.linked_wallets;
624
+ return {
625
+ kind: "wallet_signer_mismatch",
626
+ claimedOperator: sm.claimed_operator ?? null,
627
+ actualSignerOperator: sm.signer_operator ?? null,
628
+ expectedSigner: sm.expected_signer ?? claimedNorm,
629
+ actualSigner: sm.actual_signer ?? signerNorm,
630
+ linkedWallets: Array.isArray(linked) ? linked.filter((w) => typeof w === "string") : [],
631
+ agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
632
+ };
610
633
  }
611
634
  async function verifyWalletSignerMatch2(options2) {
612
- const { claimedWallet, signer } = options2;
635
+ const { claimedWallet, signer, network } = options2;
613
636
  if (!signer) {
614
637
  reportSignerEvent("wallet_auth_requires_wallet_signing");
615
638
  return {
@@ -624,6 +647,35 @@ function createAgentScoreCore(options) {
624
647
  reportSignerEvent("pass");
625
648
  return { kind: "pass", claimedOperator: null, signerOperator: null };
626
649
  }
650
+ const cachedEntry = cache.get(claimedNorm);
651
+ const cachedMatch = cachedEntry?.signerMatchBySigner?.get(signerNorm);
652
+ if (cachedMatch) {
653
+ return projectSignerMatch(cachedMatch, claimedNorm, signerNorm);
654
+ }
655
+ const inferredNetwork = network ?? (signerNorm.startsWith("0x") ? "evm" : "solana");
656
+ let assessResponse;
657
+ try {
658
+ assessResponse = await sdk.assess(claimedNorm, {
659
+ resolveSigner: { address: signerNorm, network: inferredNetwork }
660
+ });
661
+ } catch (err) {
662
+ console.warn("[gate] verifyWalletSignerMatch assess failed:", err instanceof Error ? err.message : err);
663
+ reportSignerEvent("api_error");
664
+ return { kind: "api_error", claimedWallet: claimedNorm };
665
+ }
666
+ const signerMatch = assessResponse.signer_match;
667
+ if (signerMatch && typeof signerMatch === "object") {
668
+ if (cachedEntry) {
669
+ const map = cachedEntry.signerMatchBySigner ?? /* @__PURE__ */ new Map();
670
+ map.set(signerNorm, signerMatch);
671
+ cachedEntry.signerMatchBySigner = map;
672
+ } else {
673
+ const entry = { allow: true, raw: assessResponse };
674
+ entry.signerMatchBySigner = /* @__PURE__ */ new Map([[signerNorm, signerMatch]]);
675
+ cache.set(claimedNorm, entry);
676
+ }
677
+ return projectSignerMatch(signerMatch, claimedNorm, signerNorm);
678
+ }
627
679
  const [claimedResolve, signerResolve] = await Promise.all([
628
680
  resolveWalletToOperator(claimedNorm),
629
681
  resolveWalletToOperator(signerNorm)
@@ -645,8 +697,6 @@ function createAgentScoreCore(options) {
645
697
  actualSignerOperator: signerOperator,
646
698
  expectedSigner: claimedNorm,
647
699
  actualSigner: signerNorm,
648
- // Populated from /v1/assess.linked_wallets on the claimed wallet — the full set of
649
- // wallets the agent CAN sign with to satisfy the claim (same-operator rule).
650
700
  linkedWallets: claimedResolve.linkedWallets,
651
701
  agentInstructions: WALLET_SIGNER_MISMATCH_INSTRUCTIONS
652
702
  };
@@ -739,6 +789,14 @@ function agentscoreGate(options) {
739
789
  });
740
790
  const outcome = await core.evaluate(identity, c);
741
791
  if (outcome.kind === "allow") {
792
+ if (outcome.degraded || outcome.quota) {
793
+ const prev = c.get(GATE_STATE_KEY);
794
+ c.set(GATE_STATE_KEY, {
795
+ ...prev,
796
+ ...outcome.degraded && { degraded: true, infraReason: outcome.infraReason },
797
+ ...outcome.quota && { quota: outcome.quota }
798
+ });
799
+ }
742
800
  if (outcome.data) c.set(CONTEXT_KEY, outcome.data);
743
801
  await next();
744
802
  return;
@@ -749,6 +807,14 @@ function agentscoreGate(options) {
749
807
  function getAgentScoreData(c) {
750
808
  return c.get(CONTEXT_KEY);
751
809
  }
810
+ function getGateDegradedState(c) {
811
+ const state = c.get(GATE_STATE_KEY);
812
+ return { degraded: state?.degraded ?? false, infraReason: state?.infraReason };
813
+ }
814
+ function getGateQuotaInfo(c) {
815
+ const state = c.get(GATE_STATE_KEY);
816
+ return state?.quota;
817
+ }
752
818
  async function captureWallet(c, options) {
753
819
  const state = c.get(GATE_STATE_KEY);
754
820
  if (!state?.operatorToken) return;
@@ -781,6 +847,8 @@ export {
781
847
  denialReasonToBody,
782
848
  extractPaymentSignerAddress,
783
849
  getAgentScoreData,
850
+ getGateDegradedState,
851
+ getGateQuotaInfo,
784
852
  isFixableDenial,
785
853
  readX402PaymentHeader,
786
854
  verificationAgentInstructions,