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