@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.
- package/README.md +28 -1
- package/dist/agent_instructions-d3UWTdam.d.mts +129 -0
- package/dist/agent_instructions-d3UWTdam.d.ts +129 -0
- package/dist/challenge/index.d.mts +3 -110
- package/dist/challenge/index.d.ts +3 -110
- package/dist/challenge/index.js +76 -5
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +82 -5
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/core.d.mts +28 -1
- package/dist/core.d.ts +28 -1
- package/dist/core.js +237 -157
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +246 -157
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +120 -1
- package/dist/discovery/index.d.ts +120 -1
- package/dist/discovery/index.js +204 -0
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +202 -0
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/identity/express.d.mts +18 -2
- package/dist/identity/express.d.ts +18 -2
- package/dist/identity/express.js +227 -164
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +232 -164
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +17 -2
- package/dist/identity/fastify.d.ts +17 -2
- package/dist/identity/fastify.js +227 -164
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +232 -164
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +22 -2
- package/dist/identity/hono.d.ts +22 -2
- package/dist/identity/hono.js +227 -164
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +232 -164
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +8 -1
- package/dist/identity/nextjs.d.ts +8 -1
- package/dist/identity/nextjs.js +213 -166
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +220 -166
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/web.d.mts +15 -1
- package/dist/identity/web.d.ts +15 -1
- package/dist/identity/web.js +213 -166
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +220 -166
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.js +120 -101
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +127 -101
- package/dist/index.mjs.map +1 -1
- package/dist/payment/index.js.map +1 -1
- package/dist/payment/index.mjs.map +1 -1
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/identity/hono.mjs
CHANGED
|
@@ -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
|
|
94
|
-
"Contact the merchant (their support channel \u2014 typically listed in /llms.txt or the OpenAPI servers metadata)
|
|
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
|
|
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: "
|
|
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
|
|
335
|
+
const defaultUa = `@agent-score/commerce@${"1.2.0"}`;
|
|
310
336
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
311
|
-
const
|
|
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
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
|
|
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
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if (
|
|
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 (
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
}
|
|
482
|
-
console.warn("[gate] /v1/assess 401 body parse failed:", err instanceof Error ? err.message : err);
|
|
483
|
-
}
|
|
491
|
+
};
|
|
484
492
|
}
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
-
}
|
|
495
|
-
}
|
|
501
|
+
};
|
|
496
502
|
}
|
|
497
|
-
if (
|
|
498
|
-
|
|
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
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
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
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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: "
|
|
514
|
-
|
|
515
|
-
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
|
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
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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,
|