@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/express.js
CHANGED
|
@@ -29,6 +29,8 @@ __export(express_exports, {
|
|
|
29
29
|
denialReasonToBody: () => denialReasonToBody,
|
|
30
30
|
extractPaymentSignerAddress: () => extractPaymentSignerAddress,
|
|
31
31
|
getAgentScoreData: () => getAgentScoreData,
|
|
32
|
+
getGateDegradedState: () => getGateDegradedState,
|
|
33
|
+
getGateQuotaInfo: () => getGateQuotaInfo,
|
|
32
34
|
isFixableDenial: () => isFixableDenial,
|
|
33
35
|
readX402PaymentHeader: () => readX402PaymentHeader,
|
|
34
36
|
verificationAgentInstructions: () => verificationAgentInstructions,
|
|
@@ -128,10 +130,10 @@ var WALLET_NOT_TRUSTED_INSTRUCTIONS = JSON.stringify({
|
|
|
128
130
|
var PAYMENT_REQUIRED_INSTRUCTIONS = JSON.stringify({
|
|
129
131
|
action: "contact_merchant",
|
|
130
132
|
steps: [
|
|
131
|
-
"The merchant's AgentScore
|
|
132
|
-
"Contact the merchant (their support channel \u2014 typically listed in /llms.txt or the OpenAPI servers metadata)
|
|
133
|
+
"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.",
|
|
134
|
+
"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."
|
|
133
135
|
],
|
|
134
|
-
user_message: "This merchant's identity gate is misconfigured
|
|
136
|
+
user_message: "This merchant's identity gate is misconfigured. Contact the merchant \u2014 there's nothing to fix on the agent side."
|
|
135
137
|
});
|
|
136
138
|
var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
137
139
|
action: "deliver_verify_url_and_poll",
|
|
@@ -142,6 +144,24 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
|
142
144
|
],
|
|
143
145
|
user_message: "Identity verification is required. Visit verify_url, then poll poll_url for the operator token and retry."
|
|
144
146
|
});
|
|
147
|
+
var API_ERROR_INSTRUCTIONS = JSON.stringify({
|
|
148
|
+
action: "retry_with_backoff",
|
|
149
|
+
steps: [
|
|
150
|
+
"Verification is temporarily unavailable. Retry the request after 5\u201330 seconds with exponential backoff.",
|
|
151
|
+
"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.",
|
|
152
|
+
"If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
|
|
153
|
+
],
|
|
154
|
+
user_message: "Verification is temporarily unavailable. Please try again in a moment \u2014 this is a transient issue, not a problem with your account."
|
|
155
|
+
});
|
|
156
|
+
var QUOTA_EXCEEDED_INSTRUCTIONS = JSON.stringify({
|
|
157
|
+
action: "contact_merchant",
|
|
158
|
+
steps: [
|
|
159
|
+
"AgentScore identity verification is unavailable for this merchant. This is a merchant-side issue and is NOT recoverable via retry.",
|
|
160
|
+
"Do not retry: the same 503 will be returned until the merchant resolves the issue on their side.",
|
|
161
|
+
"Surface to the user with the merchant's support contact. The merchant (not the agent) needs to act."
|
|
162
|
+
],
|
|
163
|
+
user_message: "This merchant's identity verification is temporarily unavailable. Try again later, or contact the merchant directly."
|
|
164
|
+
});
|
|
145
165
|
var TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
146
166
|
action: "deliver_verify_url_and_poll",
|
|
147
167
|
steps: [
|
|
@@ -152,6 +172,7 @@ var TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
|
152
172
|
user_message: "Operator token is expired or revoked. A new verification session has been minted \u2014 visit verify_url to refresh."
|
|
153
173
|
});
|
|
154
174
|
var DEFAULT_AGENT_INSTRUCTIONS = {
|
|
175
|
+
api_error: API_ERROR_INSTRUCTIONS,
|
|
155
176
|
wallet_not_trusted: WALLET_NOT_TRUSTED_INSTRUCTIONS,
|
|
156
177
|
payment_required: PAYMENT_REQUIRED_INSTRUCTIONS,
|
|
157
178
|
identity_verification_required: IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS,
|
|
@@ -162,7 +183,7 @@ var DEFAULT_MESSAGES = {
|
|
|
162
183
|
identity_verification_required: "Identity verification is required to access this resource. Visit verify_url to complete KYC.",
|
|
163
184
|
wallet_not_trusted: "The wallet does not meet the merchant compliance policy.",
|
|
164
185
|
api_error: "AgentScore is unreachable. This is transient \u2014 retry in a few seconds.",
|
|
165
|
-
payment_required: "
|
|
186
|
+
payment_required: "Assess endpoint not enabled for this merchant. Contact support.",
|
|
166
187
|
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.",
|
|
167
188
|
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).",
|
|
168
189
|
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.",
|
|
@@ -201,9 +222,6 @@ function denialReasonToBody(reason) {
|
|
|
201
222
|
if (reason.expected_signer) body.expected_signer = reason.expected_signer;
|
|
202
223
|
if (reason.actual_signer) body.actual_signer = reason.actual_signer;
|
|
203
224
|
if (reason.linked_wallets && reason.linked_wallets.length > 0) body.linked_wallets = reason.linked_wallets;
|
|
204
|
-
if (reason.code === "api_error" && !(reason.extra && reason.extra.next_steps)) {
|
|
205
|
-
body.next_steps = { action: "retry", retry_after_seconds: 5 };
|
|
206
|
-
}
|
|
207
225
|
if (reason.extra) {
|
|
208
226
|
for (const [key, value] of Object.entries(reason.extra)) {
|
|
209
227
|
if (RESERVED_FIELDS.has(key)) {
|
|
@@ -216,6 +234,9 @@ function denialReasonToBody(reason) {
|
|
|
216
234
|
return body;
|
|
217
235
|
}
|
|
218
236
|
|
|
237
|
+
// src/core.ts
|
|
238
|
+
var import_sdk = require("@agent-score/sdk");
|
|
239
|
+
|
|
219
240
|
// src/address.ts
|
|
220
241
|
var SOLANA_BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
221
242
|
var isSolanaAddress = (address) => SOLANA_BASE58_RE.test(address) && !address.startsWith("0x");
|
|
@@ -344,9 +365,23 @@ function createAgentScoreCore(options) {
|
|
|
344
365
|
} = options;
|
|
345
366
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
346
367
|
const agentMemoryHint = buildAgentMemoryHint();
|
|
347
|
-
const defaultUa = `@agent-score/commerce@${"1.0
|
|
368
|
+
const defaultUa = `@agent-score/commerce@${"1.2.0"}`;
|
|
348
369
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
349
|
-
const
|
|
370
|
+
const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
371
|
+
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
372
|
+
function getSessionSdk(sessionApiKey, sessionBaseUrl) {
|
|
373
|
+
const key = `${sessionApiKey}|${sessionBaseUrl ?? ""}`;
|
|
374
|
+
let s = sessionSdkCache.get(key);
|
|
375
|
+
if (!s) {
|
|
376
|
+
s = new import_sdk.AgentScore({
|
|
377
|
+
apiKey: sessionApiKey,
|
|
378
|
+
baseUrl: sessionBaseUrl ?? baseUrl,
|
|
379
|
+
userAgent: userAgentHeader
|
|
380
|
+
});
|
|
381
|
+
sessionSdkCache.set(key, s);
|
|
382
|
+
}
|
|
383
|
+
return s;
|
|
384
|
+
}
|
|
350
385
|
const cache = new TTLCache(cacheSeconds * 1e3);
|
|
351
386
|
async function tryMintSessionDenial(ctx) {
|
|
352
387
|
if (!createSessionOnMissing) return void 0;
|
|
@@ -363,20 +398,11 @@ function createAgentScoreCore(options) {
|
|
|
363
398
|
console.warn("[gate] createSessionOnMissing.getSessionOptions hook failed:", err instanceof Error ? err.message : err);
|
|
364
399
|
}
|
|
365
400
|
}
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
"X-API-Key": createSessionOnMissing.apiKey,
|
|
371
|
-
"Content-Type": "application/json",
|
|
372
|
-
Accept: "application/json",
|
|
373
|
-
"User-Agent": userAgentHeader
|
|
374
|
-
},
|
|
375
|
-
body: JSON.stringify(sessionBody),
|
|
376
|
-
signal: AbortSignal.timeout(API_TIMEOUT_MS)
|
|
401
|
+
const sessionSdk = getSessionSdk(createSessionOnMissing.apiKey, createSessionOnMissing.baseUrl);
|
|
402
|
+
const data = await sessionSdk.createSession({
|
|
403
|
+
...sessionBody.context !== void 0 ? { context: sessionBody.context } : {},
|
|
404
|
+
...sessionBody.product_name !== void 0 ? { product_name: sessionBody.product_name } : {}
|
|
377
405
|
});
|
|
378
|
-
if (!sessionRes.ok) return void 0;
|
|
379
|
-
const data = await sessionRes.json();
|
|
380
406
|
if (typeof data.session_id !== "string" || typeof data.poll_secret !== "string" || typeof data.verify_url !== "string") {
|
|
381
407
|
console.warn("[gate] /v1/sessions returned 200 without required fields \u2014 falling back to bare denial");
|
|
382
408
|
return void 0;
|
|
@@ -440,7 +466,13 @@ function createAgentScoreCore(options) {
|
|
|
440
466
|
const cached = cache.get(cacheKey);
|
|
441
467
|
if (cached) {
|
|
442
468
|
if (cached.allow) {
|
|
443
|
-
|
|
469
|
+
const cachedRaw = cached.raw;
|
|
470
|
+
const cachedQuota = cachedRaw?.quota;
|
|
471
|
+
return {
|
|
472
|
+
kind: "allow",
|
|
473
|
+
data: cachedRaw,
|
|
474
|
+
...cachedQuota !== void 0 && { quota: cachedQuota }
|
|
475
|
+
};
|
|
444
476
|
}
|
|
445
477
|
if (isFixableDenial(cached.reasons)) {
|
|
446
478
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
@@ -457,130 +489,119 @@ function createAgentScoreCore(options) {
|
|
|
457
489
|
}
|
|
458
490
|
};
|
|
459
491
|
}
|
|
492
|
+
const policy = {};
|
|
493
|
+
if (requireKyc != null) policy.require_kyc = requireKyc;
|
|
494
|
+
if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;
|
|
495
|
+
if (minAge != null) policy.min_age = minAge;
|
|
496
|
+
if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;
|
|
497
|
+
if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;
|
|
498
|
+
let data;
|
|
460
499
|
try {
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
if (
|
|
469
|
-
if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;
|
|
470
|
-
if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;
|
|
471
|
-
if (Object.keys(policy).length > 0) body.policy = policy;
|
|
472
|
-
const response = await fetch(`${baseUrl}/v1/assess`, {
|
|
473
|
-
method: "POST",
|
|
474
|
-
headers: {
|
|
475
|
-
"X-API-Key": apiKey,
|
|
476
|
-
"Content-Type": "application/json",
|
|
477
|
-
Accept: "application/json",
|
|
478
|
-
"User-Agent": userAgentHeader
|
|
479
|
-
},
|
|
480
|
-
body: JSON.stringify(body),
|
|
481
|
-
signal: AbortSignal.timeout(API_TIMEOUT_MS)
|
|
482
|
-
});
|
|
483
|
-
if (response.status === 402) {
|
|
500
|
+
const opts = {
|
|
501
|
+
chain: gateChain,
|
|
502
|
+
...Object.keys(policy).length > 0 ? { policy } : {}
|
|
503
|
+
};
|
|
504
|
+
const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
|
|
505
|
+
data = result;
|
|
506
|
+
} catch (err) {
|
|
507
|
+
if (err instanceof import_sdk.PaymentRequiredError) {
|
|
484
508
|
if (failOpen) return { kind: "allow" };
|
|
485
509
|
return { kind: "deny", reason: { code: "payment_required" } };
|
|
486
510
|
}
|
|
487
|
-
if (
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
...typeof errData.poll_secret === "string" ? { poll_secret: errData.poll_secret } : {},
|
|
500
|
-
...typeof errData.poll_url === "string" ? { poll_url: errData.poll_url } : {},
|
|
501
|
-
...errData.next_steps ? { agent_instructions: JSON.stringify(errData.next_steps) } : {},
|
|
502
|
-
...errData.agent_memory ? { agent_memory: errData.agent_memory } : {}
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
if (code === "invalid_credential") {
|
|
507
|
-
return {
|
|
508
|
-
kind: "deny",
|
|
509
|
-
reason: {
|
|
510
|
-
code: "invalid_credential",
|
|
511
|
-
agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,
|
|
512
|
-
agent_memory: agentMemoryHint
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
if (code) {
|
|
517
|
-
console.warn(`[gate] /v1/assess returned 401 ${code} \u2014 no specific handler, surfacing as api_error.`);
|
|
511
|
+
if (err instanceof import_sdk.TokenExpiredError) {
|
|
512
|
+
return {
|
|
513
|
+
kind: "deny",
|
|
514
|
+
reason: {
|
|
515
|
+
code: "token_expired",
|
|
516
|
+
data: err.details,
|
|
517
|
+
...err.verifyUrl ? { verify_url: err.verifyUrl } : {},
|
|
518
|
+
...err.sessionId ? { session_id: err.sessionId } : {},
|
|
519
|
+
...err.pollSecret ? { poll_secret: err.pollSecret } : {},
|
|
520
|
+
...err.pollUrl ? { poll_url: err.pollUrl } : {},
|
|
521
|
+
...err.nextSteps ? { agent_instructions: JSON.stringify(err.nextSteps) } : {},
|
|
522
|
+
...err.agentMemory ? { agent_memory: err.agentMemory } : {}
|
|
518
523
|
}
|
|
519
|
-
}
|
|
520
|
-
console.warn("[gate] /v1/assess 401 body parse failed:", err instanceof Error ? err.message : err);
|
|
521
|
-
}
|
|
524
|
+
};
|
|
522
525
|
}
|
|
523
|
-
if (
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
);
|
|
526
|
+
if (err instanceof import_sdk.InvalidCredentialError) {
|
|
527
|
+
return {
|
|
528
|
+
kind: "deny",
|
|
529
|
+
reason: {
|
|
530
|
+
code: "invalid_credential",
|
|
531
|
+
agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,
|
|
532
|
+
agent_memory: agentMemoryHint
|
|
531
533
|
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
+
};
|
|
534
535
|
}
|
|
535
|
-
if (
|
|
536
|
-
|
|
536
|
+
if (err instanceof import_sdk.QuotaExceededError) {
|
|
537
|
+
console.warn("[gate] /v1/assess returned 429 quota_exceeded");
|
|
538
|
+
if (failOpen) return { kind: "allow", degraded: true, infraReason: "quota_exceeded" };
|
|
539
|
+
return {
|
|
540
|
+
kind: "deny",
|
|
541
|
+
reason: { code: "api_error", agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS }
|
|
542
|
+
};
|
|
537
543
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
543
|
-
if (allow) {
|
|
544
|
-
return { kind: "allow", data };
|
|
544
|
+
if (err instanceof import_sdk.TimeoutError) {
|
|
545
|
+
console.warn("[gate] /v1/assess timed out:", err.message);
|
|
546
|
+
if (failOpen) return { kind: "allow", degraded: true, infraReason: "network_timeout" };
|
|
547
|
+
return { kind: "deny", reason: { code: "api_error" } };
|
|
545
548
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
+
const status = err?.status;
|
|
550
|
+
const errName = err instanceof Error ? err.name : "";
|
|
551
|
+
if (status === 429) {
|
|
552
|
+
console.warn("[gate] /v1/assess returned 429 (untyped \u2014 defensive)");
|
|
553
|
+
if (failOpen) return { kind: "allow", degraded: true, infraReason: "quota_exceeded" };
|
|
554
|
+
return {
|
|
555
|
+
kind: "deny",
|
|
556
|
+
reason: { code: "api_error", agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS }
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
if (errName === "TimeoutError" || errName === "AbortError") {
|
|
560
|
+
console.warn("[gate] /v1/assess timed out (by Error.name):", err instanceof Error ? err.message : err);
|
|
561
|
+
if (failOpen) return { kind: "allow", degraded: true, infraReason: "network_timeout" };
|
|
562
|
+
return { kind: "deny", reason: { code: "api_error" } };
|
|
549
563
|
}
|
|
564
|
+
const errCode = err?.code;
|
|
565
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
566
|
+
const detail = errCode ? `${errCode}: ${msg}` : msg;
|
|
567
|
+
console.warn(`[gate] /v1/assess call failed \u2014 surfacing as api_error: ${detail}`);
|
|
568
|
+
if (failOpen) return { kind: "allow", degraded: true, infraReason: "api_error" };
|
|
569
|
+
return { kind: "deny", reason: { code: "api_error" } };
|
|
570
|
+
}
|
|
571
|
+
const decision = data.decision;
|
|
572
|
+
const decisionReasons = data.decision_reasons ?? [];
|
|
573
|
+
const allow = decision === "allow" || decision == null;
|
|
574
|
+
cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
575
|
+
if (allow) {
|
|
576
|
+
const quota = data.quota;
|
|
550
577
|
return {
|
|
551
|
-
kind: "
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
decision: decision ?? void 0,
|
|
555
|
-
reasons: decisionReasons,
|
|
556
|
-
verify_url: data.verify_url,
|
|
557
|
-
data
|
|
558
|
-
}
|
|
578
|
+
kind: "allow",
|
|
579
|
+
data,
|
|
580
|
+
...quota !== void 0 && { quota }
|
|
559
581
|
};
|
|
560
|
-
} catch (err) {
|
|
561
|
-
console.warn("[gate] /v1/assess call failed \u2014 surfacing as api_error:", err instanceof Error ? err.message : err);
|
|
562
|
-
if (failOpen) return { kind: "allow" };
|
|
563
|
-
return { kind: "deny", reason: { code: "api_error" } };
|
|
564
582
|
}
|
|
583
|
+
if (isFixableDenial(decisionReasons)) {
|
|
584
|
+
const sessionReason = await tryMintSessionDenial(ctx);
|
|
585
|
+
if (sessionReason) return { kind: "deny", reason: sessionReason };
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
kind: "deny",
|
|
589
|
+
reason: {
|
|
590
|
+
code: "wallet_not_trusted",
|
|
591
|
+
decision: decision ?? void 0,
|
|
592
|
+
reasons: decisionReasons,
|
|
593
|
+
verify_url: data.verify_url,
|
|
594
|
+
data
|
|
595
|
+
}
|
|
596
|
+
};
|
|
565
597
|
}
|
|
566
598
|
async function captureWallet2(options2) {
|
|
567
599
|
try {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
network: options2.network
|
|
572
|
-
|
|
573
|
-
if (options2.idempotencyKey) body.idempotency_key = options2.idempotencyKey;
|
|
574
|
-
await fetch(`${baseUrl}/v1/credentials/wallets`, {
|
|
575
|
-
method: "POST",
|
|
576
|
-
headers: {
|
|
577
|
-
"X-API-Key": apiKey,
|
|
578
|
-
"Content-Type": "application/json",
|
|
579
|
-
Accept: "application/json",
|
|
580
|
-
"User-Agent": userAgentHeader
|
|
581
|
-
},
|
|
582
|
-
body: JSON.stringify(body),
|
|
583
|
-
signal: AbortSignal.timeout(API_TIMEOUT_MS)
|
|
600
|
+
await sdk.associateWallet({
|
|
601
|
+
operatorToken: options2.operatorToken,
|
|
602
|
+
walletAddress: options2.walletAddress,
|
|
603
|
+
network: options2.network,
|
|
604
|
+
...options2.idempotencyKey ? { idempotencyKey: options2.idempotencyKey } : {}
|
|
584
605
|
});
|
|
585
606
|
} catch (err) {
|
|
586
607
|
console.warn("[agentscore-commerce] captureWallet failed:", err instanceof Error ? err.message : err);
|
|
@@ -605,19 +626,7 @@ function createAgentScoreCore(options) {
|
|
|
605
626
|
return { ok: true, ...extractFromCached(resolveCached.raw) };
|
|
606
627
|
}
|
|
607
628
|
try {
|
|
608
|
-
const
|
|
609
|
-
method: "POST",
|
|
610
|
-
headers: {
|
|
611
|
-
"X-API-Key": apiKey,
|
|
612
|
-
"Content-Type": "application/json",
|
|
613
|
-
Accept: "application/json",
|
|
614
|
-
"User-Agent": userAgentHeader
|
|
615
|
-
},
|
|
616
|
-
body: JSON.stringify({ address: walletAddress }),
|
|
617
|
-
signal: AbortSignal.timeout(API_TIMEOUT_MS)
|
|
618
|
-
});
|
|
619
|
-
if (!response.ok) return { ok: false };
|
|
620
|
-
const data = await response.json();
|
|
629
|
+
const data = await sdk.assess(walletAddress);
|
|
621
630
|
cache.set(`resolve:${wallet}`, { allow: true, raw: data });
|
|
622
631
|
return { ok: true, ...extractFromCached(data) };
|
|
623
632
|
} catch (err) {
|
|
@@ -626,28 +635,37 @@ function createAgentScoreCore(options) {
|
|
|
626
635
|
}
|
|
627
636
|
}
|
|
628
637
|
function reportSignerEvent(kind) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
signal: AbortSignal.timeout(API_TIMEOUT_MS)
|
|
640
|
-
});
|
|
641
|
-
if (pending && typeof pending.catch === "function") {
|
|
642
|
-
pending.catch((err) => {
|
|
643
|
-
console.warn("[agentscore-commerce] signer-match telemetry failed:", err instanceof Error ? err.message : err);
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
} catch {
|
|
638
|
+
void sdk.telemetrySignerMatch({ kind });
|
|
639
|
+
}
|
|
640
|
+
function projectSignerMatch(sm, claimedNorm, signerNorm) {
|
|
641
|
+
const kind = sm.kind;
|
|
642
|
+
if (kind === "pass") {
|
|
643
|
+
return {
|
|
644
|
+
kind: "pass",
|
|
645
|
+
claimedOperator: sm.claimed_operator ?? null,
|
|
646
|
+
signerOperator: sm.signer_operator ?? null
|
|
647
|
+
};
|
|
647
648
|
}
|
|
649
|
+
if (kind === "wallet_auth_requires_wallet_signing") {
|
|
650
|
+
return {
|
|
651
|
+
kind: "wallet_auth_requires_wallet_signing",
|
|
652
|
+
claimedWallet: sm.claimed_wallet ?? claimedNorm,
|
|
653
|
+
agentInstructions: sm.agent_instructions ?? WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
const linked = sm.linked_wallets;
|
|
657
|
+
return {
|
|
658
|
+
kind: "wallet_signer_mismatch",
|
|
659
|
+
claimedOperator: sm.claimed_operator ?? null,
|
|
660
|
+
actualSignerOperator: sm.signer_operator ?? null,
|
|
661
|
+
expectedSigner: sm.expected_signer ?? claimedNorm,
|
|
662
|
+
actualSigner: sm.actual_signer ?? signerNorm,
|
|
663
|
+
linkedWallets: Array.isArray(linked) ? linked.filter((w) => typeof w === "string") : [],
|
|
664
|
+
agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
|
|
665
|
+
};
|
|
648
666
|
}
|
|
649
667
|
async function verifyWalletSignerMatch2(options2) {
|
|
650
|
-
const { claimedWallet, signer } = options2;
|
|
668
|
+
const { claimedWallet, signer, network } = options2;
|
|
651
669
|
if (!signer) {
|
|
652
670
|
reportSignerEvent("wallet_auth_requires_wallet_signing");
|
|
653
671
|
return {
|
|
@@ -662,6 +680,35 @@ function createAgentScoreCore(options) {
|
|
|
662
680
|
reportSignerEvent("pass");
|
|
663
681
|
return { kind: "pass", claimedOperator: null, signerOperator: null };
|
|
664
682
|
}
|
|
683
|
+
const cachedEntry = cache.get(claimedNorm);
|
|
684
|
+
const cachedMatch = cachedEntry?.signerMatchBySigner?.get(signerNorm);
|
|
685
|
+
if (cachedMatch) {
|
|
686
|
+
return projectSignerMatch(cachedMatch, claimedNorm, signerNorm);
|
|
687
|
+
}
|
|
688
|
+
const inferredNetwork = network ?? (signerNorm.startsWith("0x") ? "evm" : "solana");
|
|
689
|
+
let assessResponse;
|
|
690
|
+
try {
|
|
691
|
+
assessResponse = await sdk.assess(claimedNorm, {
|
|
692
|
+
resolveSigner: { address: signerNorm, network: inferredNetwork }
|
|
693
|
+
});
|
|
694
|
+
} catch (err) {
|
|
695
|
+
console.warn("[gate] verifyWalletSignerMatch assess failed:", err instanceof Error ? err.message : err);
|
|
696
|
+
reportSignerEvent("api_error");
|
|
697
|
+
return { kind: "api_error", claimedWallet: claimedNorm };
|
|
698
|
+
}
|
|
699
|
+
const signerMatch = assessResponse.signer_match;
|
|
700
|
+
if (signerMatch && typeof signerMatch === "object") {
|
|
701
|
+
if (cachedEntry) {
|
|
702
|
+
const map = cachedEntry.signerMatchBySigner ?? /* @__PURE__ */ new Map();
|
|
703
|
+
map.set(signerNorm, signerMatch);
|
|
704
|
+
cachedEntry.signerMatchBySigner = map;
|
|
705
|
+
} else {
|
|
706
|
+
const entry = { allow: true, raw: assessResponse };
|
|
707
|
+
entry.signerMatchBySigner = /* @__PURE__ */ new Map([[signerNorm, signerMatch]]);
|
|
708
|
+
cache.set(claimedNorm, entry);
|
|
709
|
+
}
|
|
710
|
+
return projectSignerMatch(signerMatch, claimedNorm, signerNorm);
|
|
711
|
+
}
|
|
665
712
|
const [claimedResolve, signerResolve] = await Promise.all([
|
|
666
713
|
resolveWalletToOperator(claimedNorm),
|
|
667
714
|
resolveWalletToOperator(signerNorm)
|
|
@@ -683,8 +730,6 @@ function createAgentScoreCore(options) {
|
|
|
683
730
|
actualSignerOperator: signerOperator,
|
|
684
731
|
expectedSigner: claimedNorm,
|
|
685
732
|
actualSigner: signerNorm,
|
|
686
|
-
// Populated from /v1/assess.linked_wallets on the claimed wallet — the full set of
|
|
687
|
-
// wallets the agent CAN sign with to satisfy the claim (same-operator rule).
|
|
688
733
|
linkedWallets: claimedResolve.linkedWallets,
|
|
689
734
|
agentInstructions: WALLET_SIGNER_MISMATCH_INSTRUCTIONS
|
|
690
735
|
};
|
|
@@ -776,6 +821,14 @@ function agentscoreGate(options) {
|
|
|
776
821
|
};
|
|
777
822
|
const outcome = await core.evaluate(identity, req);
|
|
778
823
|
if (outcome.kind === "allow") {
|
|
824
|
+
const state = req[GATE_STATE_KEY];
|
|
825
|
+
if (state) {
|
|
826
|
+
if (outcome.degraded) {
|
|
827
|
+
state.degraded = true;
|
|
828
|
+
state.infraReason = outcome.infraReason;
|
|
829
|
+
}
|
|
830
|
+
if (outcome.quota) state.quota = outcome.quota;
|
|
831
|
+
}
|
|
779
832
|
if (outcome.data) req.agentscore = outcome.data;
|
|
780
833
|
next();
|
|
781
834
|
return;
|
|
@@ -783,6 +836,14 @@ function agentscoreGate(options) {
|
|
|
783
836
|
onDenied(req, res, outcome.reason);
|
|
784
837
|
};
|
|
785
838
|
}
|
|
839
|
+
function getGateDegradedState(req) {
|
|
840
|
+
const state = req[GATE_STATE_KEY];
|
|
841
|
+
return { degraded: state?.degraded ?? false, infraReason: state?.infraReason };
|
|
842
|
+
}
|
|
843
|
+
function getGateQuotaInfo(req) {
|
|
844
|
+
const state = req[GATE_STATE_KEY];
|
|
845
|
+
return state?.quota;
|
|
846
|
+
}
|
|
786
847
|
function getAgentScoreData(req) {
|
|
787
848
|
return req.agentscore;
|
|
788
849
|
}
|
|
@@ -818,6 +879,8 @@ async function verifyWalletSignerMatch(req, options) {
|
|
|
818
879
|
denialReasonToBody,
|
|
819
880
|
extractPaymentSignerAddress,
|
|
820
881
|
getAgentScoreData,
|
|
882
|
+
getGateDegradedState,
|
|
883
|
+
getGateQuotaInfo,
|
|
821
884
|
isFixableDenial,
|
|
822
885
|
readX402PaymentHeader,
|
|
823
886
|
verificationAgentInstructions,
|