@agent-score/commerce 2.5.0 → 2.6.1
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 +19 -17
- package/dist/challenge/index.d.mts +26 -2
- package/dist/challenge/index.d.ts +26 -2
- package/dist/challenge/index.js +14 -5
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +14 -5
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/{checkout-McfNpZJf.d.ts → checkout-C4RD7M0Z.d.ts} +46 -13
- package/dist/{checkout-o17dIxHi.d.mts → checkout-CzB9f_jf.d.mts} +46 -13
- package/dist/core.d.mts +20 -9
- package/dist/core.d.ts +20 -9
- package/dist/core.js +35 -24
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +35 -24
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +17 -2
- package/dist/discovery/index.d.ts +17 -2
- package/dist/discovery/index.js +36 -12
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +35 -12
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/{gate-CWP10xPQ.d.mts → gate-D2RP6bZg.d.ts} +109 -141
- package/dist/{gate-CWP10xPQ.d.ts → gate-GCXy4FHI.d.mts} +109 -141
- package/dist/identity/express.d.mts +3 -1
- package/dist/identity/express.d.ts +3 -1
- package/dist/identity/express.js +164 -55
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +164 -55
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +3 -1
- package/dist/identity/fastify.d.ts +3 -1
- package/dist/identity/fastify.js +171 -57
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +171 -57
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +3 -1
- package/dist/identity/hono.d.ts +3 -1
- package/dist/identity/hono.js +159 -59
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +159 -59
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +3 -1
- package/dist/identity/nextjs.d.ts +3 -1
- package/dist/identity/nextjs.js +153 -56
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +153 -56
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/policy.d.mts +21 -2
- package/dist/identity/policy.d.ts +21 -2
- package/dist/identity/policy.js +22 -1
- package/dist/identity/policy.js.map +1 -1
- package/dist/identity/policy.mjs +21 -1
- package/dist/identity/policy.mjs.map +1 -1
- package/dist/identity/web.d.mts +3 -1
- package/dist/identity/web.d.ts +3 -1
- package/dist/identity/web.js +153 -56
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +153 -56
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +55 -10
- package/dist/index.d.ts +55 -10
- package/dist/index.js +2227 -501
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2219 -501
- package/dist/index.mjs.map +1 -1
- package/dist/payment/index.d.mts +1 -1
- package/dist/payment/index.d.ts +1 -1
- package/dist/payment/index.js +10 -2
- package/dist/payment/index.js.map +1 -1
- package/dist/payment/index.mjs +10 -2
- package/dist/payment/index.mjs.map +1 -1
- package/dist/stripe-multichain/index.js +1621 -266
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs +1621 -266
- package/dist/stripe-multichain/index.mjs.map +1 -1
- package/dist/types-D1slMt0H.d.mts +137 -0
- package/dist/types-D1slMt0H.d.ts +137 -0
- package/dist/{wwwauthenticate-CVaGUMjU.d.mts → wwwauthenticate-Dgm-_af9.d.mts} +11 -1
- package/dist/{wwwauthenticate-CVaGUMjU.d.ts → wwwauthenticate-Dgm-_af9.d.ts} +11 -1
- package/package.json +23 -18
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as AipGateOptions, o as buildAipErrorBody, V as VerifiedAit } from '../gate-GCXy4FHI.mjs';
|
|
2
2
|
import { AgentScoreCoreOptions, AgentIdentity, DenialReason, CreateSessionOnMissing, AssessResult, FailOpenInfraReason, GateQuotaInfo, SignerVerdict } from '../core.mjs';
|
|
3
3
|
import { FastifyRequest, FastifyReply, FastifyPluginAsync } from 'fastify';
|
|
4
|
+
import '../types-D1slMt0H.mjs';
|
|
4
5
|
import 'jose';
|
|
6
|
+
import '@agent-score/sdk';
|
|
5
7
|
import '../signer-3FAit11j.mjs';
|
|
6
8
|
|
|
7
9
|
interface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as AipGateOptions, o as buildAipErrorBody, V as VerifiedAit } from '../gate-D2RP6bZg.js';
|
|
2
2
|
import { AgentScoreCoreOptions, AgentIdentity, DenialReason, CreateSessionOnMissing, AssessResult, FailOpenInfraReason, GateQuotaInfo, SignerVerdict } from '../core.js';
|
|
3
3
|
import { FastifyRequest, FastifyReply, FastifyPluginAsync } from 'fastify';
|
|
4
|
+
import '../types-D1slMt0H.js';
|
|
4
5
|
import 'jose';
|
|
6
|
+
import '@agent-score/sdk';
|
|
5
7
|
import '../signer-3FAit11j.js';
|
|
6
8
|
|
|
7
9
|
interface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {
|
package/dist/identity/fastify.js
CHANGED
|
@@ -80,7 +80,7 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
|
80
80
|
var API_ERROR_INSTRUCTIONS = JSON.stringify({
|
|
81
81
|
action: "retry_with_backoff",
|
|
82
82
|
steps: [
|
|
83
|
-
"Verification is temporarily unavailable. Retry the request after 5
|
|
83
|
+
"Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.",
|
|
84
84
|
"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.",
|
|
85
85
|
"If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
|
|
86
86
|
],
|
|
@@ -184,6 +184,7 @@ var b64ToBytes = (b64) => {
|
|
|
184
184
|
var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
|
|
185
185
|
var AIP_SIGNATURE_TAG = "agent-identity";
|
|
186
186
|
var DEFAULT_MAX_SKEW_SECONDS = 60;
|
|
187
|
+
var MAX_POP_WINDOW_SECONDS = 120;
|
|
187
188
|
var normalizeAuthority = (authority) => {
|
|
188
189
|
const lower = authority.trim().toLowerCase();
|
|
189
190
|
const colon = lower.lastIndexOf(":");
|
|
@@ -234,7 +235,7 @@ var serializeParams = (p) => {
|
|
|
234
235
|
}
|
|
235
236
|
return parts.map((s) => `;${s}`).join("");
|
|
236
237
|
};
|
|
237
|
-
var buildSignatureBase = (params, input) => {
|
|
238
|
+
var buildSignatureBase = (params, input, rawSignatureParams) => {
|
|
238
239
|
const lines = [];
|
|
239
240
|
for (const name of params.components) {
|
|
240
241
|
const value = componentValue(name, input);
|
|
@@ -243,7 +244,7 @@ var buildSignatureBase = (params, input) => {
|
|
|
243
244
|
}
|
|
244
245
|
lines.push(`"${name}": ${value}`);
|
|
245
246
|
}
|
|
246
|
-
const paramsValue = serializeComponentList(params.components) + serializeParams(params);
|
|
247
|
+
const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);
|
|
247
248
|
lines.push(`"@signature-params": ${paramsValue}`);
|
|
248
249
|
return lines.join("\n");
|
|
249
250
|
};
|
|
@@ -262,19 +263,12 @@ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
|
|
|
262
263
|
}
|
|
263
264
|
const parsed = members.map((m) => {
|
|
264
265
|
const params = parseInnerListMember(m.value);
|
|
265
|
-
return params ? { label: m.label, params } : null;
|
|
266
|
+
return params ? { label: m.label, params, rawParams: m.value } : null;
|
|
266
267
|
}).filter((x) => x !== null);
|
|
267
268
|
if (parsed.length === 0) {
|
|
268
269
|
return null;
|
|
269
270
|
}
|
|
270
|
-
|
|
271
|
-
if (tagged) {
|
|
272
|
-
return tagged;
|
|
273
|
-
}
|
|
274
|
-
if (parsed.length === 1 && parsed[0].params.tag === void 0) {
|
|
275
|
-
return parsed[0];
|
|
276
|
-
}
|
|
277
|
-
return null;
|
|
271
|
+
return parsed.find((p) => p.params.tag === tag) ?? null;
|
|
278
272
|
};
|
|
279
273
|
var parseSignatureValue = (header, label) => {
|
|
280
274
|
const members = splitDictionary(header);
|
|
@@ -388,7 +382,7 @@ var verifyMessageSignature = async (input) => {
|
|
|
388
382
|
if (!selected) {
|
|
389
383
|
return { ok: false, reason: "no_aip_signature" };
|
|
390
384
|
}
|
|
391
|
-
const { label, params } = selected;
|
|
385
|
+
const { label, params, rawParams } = selected;
|
|
392
386
|
if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
|
|
393
387
|
return { ok: false, reason: "unsupported_alg" };
|
|
394
388
|
}
|
|
@@ -397,12 +391,21 @@ var verifyMessageSignature = async (input) => {
|
|
|
397
391
|
return { ok: false, reason: "missing_covered_component" };
|
|
398
392
|
}
|
|
399
393
|
}
|
|
394
|
+
if (params.created === void 0) {
|
|
395
|
+
return { ok: false, reason: "created_missing" };
|
|
396
|
+
}
|
|
397
|
+
if (params.expires === void 0) {
|
|
398
|
+
return { ok: false, reason: "expires_missing" };
|
|
399
|
+
}
|
|
400
|
+
if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {
|
|
401
|
+
return { ok: false, reason: "pop_window_too_long" };
|
|
402
|
+
}
|
|
400
403
|
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
401
404
|
const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
|
|
402
|
-
if (params.created
|
|
405
|
+
if (params.created > now + skew) {
|
|
403
406
|
return { ok: false, reason: "created_in_future" };
|
|
404
407
|
}
|
|
405
|
-
if (params.expires
|
|
408
|
+
if (params.expires < now - skew) {
|
|
406
409
|
return { ok: false, reason: "expired" };
|
|
407
410
|
}
|
|
408
411
|
if (!params.keyid) {
|
|
@@ -433,7 +436,7 @@ var verifyMessageSignature = async (input) => {
|
|
|
433
436
|
path: input.path,
|
|
434
437
|
agentIdentity: input.agentIdentity,
|
|
435
438
|
extra: input.extraComponents
|
|
436
|
-
});
|
|
439
|
+
}, rawParams);
|
|
437
440
|
} catch (err) {
|
|
438
441
|
if (err instanceof MissingComponentError) {
|
|
439
442
|
return { ok: false, reason: "missing_covered_component" };
|
|
@@ -505,6 +508,8 @@ var verifyAit = async (ctx, opts) => {
|
|
|
505
508
|
if (!ctx.signatureInput || !ctx.signature) {
|
|
506
509
|
return { ok: false, reason: "pop_signature_missing" };
|
|
507
510
|
}
|
|
511
|
+
const signatureInput = ctx.signatureInput;
|
|
512
|
+
const signature = ctx.signature;
|
|
508
513
|
let lastFailure = "malformed_token";
|
|
509
514
|
for (const raw of ctx.agentIdentityHeaders) {
|
|
510
515
|
const token = stripBearer(raw);
|
|
@@ -543,7 +548,7 @@ var verifyAit = async (ctx, opts) => {
|
|
|
543
548
|
// Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
|
|
544
549
|
// this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
|
|
545
550
|
// non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
|
|
546
|
-
// token that verifies. Matches the server-side allowlist in
|
|
551
|
+
// token that verifies. Matches the server-side allowlist in the AgentScore API verifier.
|
|
547
552
|
algorithms: AIT_SIGNING_ALGS,
|
|
548
553
|
clockTolerance: jwtClockTolerance,
|
|
549
554
|
currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
|
|
@@ -557,13 +562,20 @@ var verifyAit = async (ctx, opts) => {
|
|
|
557
562
|
lastFailure = "expired_token";
|
|
558
563
|
continue;
|
|
559
564
|
}
|
|
565
|
+
if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {
|
|
566
|
+
lastFailure = "expired_token";
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
560
569
|
const popResult = await verifyMessageSignature({
|
|
561
570
|
method: ctx.method,
|
|
562
571
|
authority: ctx.authority,
|
|
563
572
|
path: ctx.path,
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
573
|
+
// The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is
|
|
574
|
+
// transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and
|
|
575
|
+
// the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.
|
|
576
|
+
agentIdentity: token,
|
|
577
|
+
signatureInput,
|
|
578
|
+
signature,
|
|
567
579
|
cnfJwk: claims.cnf.jwk,
|
|
568
580
|
now: opts.now,
|
|
569
581
|
maxSkewSeconds: opts.maxSkewSeconds
|
|
@@ -572,7 +584,22 @@ var verifyAit = async (ctx, opts) => {
|
|
|
572
584
|
lastFailure = "pop_signature_invalid";
|
|
573
585
|
continue;
|
|
574
586
|
}
|
|
575
|
-
return {
|
|
587
|
+
return {
|
|
588
|
+
ok: true,
|
|
589
|
+
ait: {
|
|
590
|
+
payload: claims,
|
|
591
|
+
iss: claims.iss,
|
|
592
|
+
cnfJwk: claims.cnf.jwk,
|
|
593
|
+
token,
|
|
594
|
+
signatureMaterial: {
|
|
595
|
+
method: ctx.method,
|
|
596
|
+
authority: ctx.authority,
|
|
597
|
+
path: ctx.path,
|
|
598
|
+
signature_input: signatureInput,
|
|
599
|
+
signature
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
};
|
|
576
603
|
}
|
|
577
604
|
return { ok: false, reason: lastFailure };
|
|
578
605
|
};
|
|
@@ -602,7 +629,12 @@ var buildVerifyContextFromParts = (parts) => {
|
|
|
602
629
|
const host = parts.authority ?? readNodeHeader(parts.headers, "host") ?? "";
|
|
603
630
|
let path;
|
|
604
631
|
try {
|
|
605
|
-
|
|
632
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(parts.url)) {
|
|
633
|
+
path = new URL(parts.url).pathname;
|
|
634
|
+
} else {
|
|
635
|
+
const target = parts.url.startsWith("/") ? parts.url : `/${parts.url}`;
|
|
636
|
+
path = new URL(`http://${host || "localhost"}${target}`).pathname;
|
|
637
|
+
}
|
|
606
638
|
} catch {
|
|
607
639
|
const q = parts.url.indexOf("?");
|
|
608
640
|
path = q === -1 ? parts.url : parts.url.slice(0, q);
|
|
@@ -618,11 +650,10 @@ var buildVerifyContextFromParts = (parts) => {
|
|
|
618
650
|
};
|
|
619
651
|
|
|
620
652
|
// src/aip/gate.ts
|
|
621
|
-
var
|
|
622
|
-
const
|
|
623
|
-
return
|
|
653
|
+
var partsWithAuthority = (parts, opts) => {
|
|
654
|
+
const authority = parts.authority ?? opts.authority;
|
|
655
|
+
return authority !== void 0 ? { ...parts, authority } : parts;
|
|
624
656
|
};
|
|
625
|
-
var verifyAitParts = (parts, opts) => verifyFromContext(buildVerifyContextFromParts(parts), opts);
|
|
626
657
|
var aipErrorCode = (failure) => {
|
|
627
658
|
switch (failure) {
|
|
628
659
|
case "no_token":
|
|
@@ -679,15 +710,78 @@ var aipErrorDetail = (failure) => {
|
|
|
679
710
|
return "Token verification failed.";
|
|
680
711
|
}
|
|
681
712
|
};
|
|
682
|
-
var buildAipErrorBody = (failure) => {
|
|
713
|
+
var buildAipErrorBody = (failure, requirements) => {
|
|
683
714
|
const code = aipErrorCode(failure);
|
|
684
|
-
|
|
715
|
+
const body = {
|
|
685
716
|
type: `urn:aip:error:${code}`,
|
|
686
717
|
title: code.replace(/_/g, " "),
|
|
687
718
|
status: aipErrorStatus(failure),
|
|
688
719
|
detail: aipErrorDetail(failure)
|
|
689
720
|
};
|
|
721
|
+
if (requirements) {
|
|
722
|
+
if (code === "untrusted_issuer" && requirements.trustedIssuers?.length) {
|
|
723
|
+
body.trusted_issuers = requirements.trustedIssuers;
|
|
724
|
+
}
|
|
725
|
+
if (code === "insufficient_claims") {
|
|
726
|
+
if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;
|
|
727
|
+
if (requirements.requiredTrustLevel !== void 0) body.required_trust_level = requirements.requiredTrustLevel;
|
|
728
|
+
if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return body;
|
|
732
|
+
};
|
|
733
|
+
var TRUST_RANK = { autonomous: 0, human_present: 1, human_confirmed: 2 };
|
|
734
|
+
var checkTrustRequirements = (payload, requiredTrustLevel, requiredAmr) => {
|
|
735
|
+
if (requiredTrustLevel !== void 0) {
|
|
736
|
+
const have = TRUST_RANK[payload.trust_level ?? "autonomous"] ?? 0;
|
|
737
|
+
const need = TRUST_RANK[requiredTrustLevel] ?? 0;
|
|
738
|
+
if (have < need) {
|
|
739
|
+
return `This endpoint requires trust_level '${requiredTrustLevel}'; the token asserts '${payload.trust_level ?? "autonomous"}'. Re-mint an AIT at the required trust level (human confirmation).`;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (requiredAmr !== void 0 && requiredAmr.length > 0) {
|
|
743
|
+
const amr = Array.isArray(payload.auth?.amr) ? payload.auth.amr : [];
|
|
744
|
+
if (!amr.some((m) => requiredAmr.includes(m))) {
|
|
745
|
+
return `This endpoint requires an authentication method in [${requiredAmr.join(", ")}]; the token carries [${amr.join(", ") || "none"}].`;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return null;
|
|
749
|
+
};
|
|
750
|
+
var buildAipWeakAuthBody = (opts) => ({
|
|
751
|
+
type: "urn:aip:error:weak_auth",
|
|
752
|
+
title: "weak auth",
|
|
753
|
+
status: 403,
|
|
754
|
+
detail: opts.detail,
|
|
755
|
+
...opts.requiredTrustLevel !== void 0 && { required_trust_level: opts.requiredTrustLevel },
|
|
756
|
+
...opts.requiredAmr !== void 0 && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr },
|
|
757
|
+
...opts.trustedIssuers !== void 0 && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }
|
|
758
|
+
});
|
|
759
|
+
var requirementsFromOptions = (opts) => ({
|
|
760
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers },
|
|
761
|
+
...opts.requiredClaims !== void 0 && { requiredClaims: opts.requiredClaims },
|
|
762
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
763
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr }
|
|
764
|
+
});
|
|
765
|
+
var evaluateFromContext = async (ctx, opts) => {
|
|
766
|
+
const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
|
|
767
|
+
if (!result.ok) {
|
|
768
|
+
return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };
|
|
769
|
+
}
|
|
770
|
+
const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);
|
|
771
|
+
if (weak !== null) {
|
|
772
|
+
return {
|
|
773
|
+
ok: false,
|
|
774
|
+
body: buildAipWeakAuthBody({
|
|
775
|
+
detail: weak,
|
|
776
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
777
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr },
|
|
778
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers }
|
|
779
|
+
})
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return { ok: true, ait: result.ait };
|
|
690
783
|
};
|
|
784
|
+
var evaluateAipParts = (parts, opts) => evaluateFromContext(buildVerifyContextFromParts(partsWithAuthority(parts, opts)), opts);
|
|
691
785
|
|
|
692
786
|
// src/core.ts
|
|
693
787
|
var import_node_crypto = require("crypto");
|
|
@@ -759,7 +853,7 @@ function stripTrailingSlashes(s) {
|
|
|
759
853
|
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
760
854
|
return end === s.length ? s : s.slice(0, end);
|
|
761
855
|
}
|
|
762
|
-
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.
|
|
856
|
+
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.com";
|
|
763
857
|
var WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({
|
|
764
858
|
action: "resign_or_switch_to_operator_token",
|
|
765
859
|
steps: [
|
|
@@ -791,7 +885,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
|
791
885
|
return {
|
|
792
886
|
save_for_future_agentscore_gates: true,
|
|
793
887
|
pattern_summary: "AgentScore is a cross-merchant identity substrate for agent commerce. Any endpoint that returns 403 missing_identity / identity_verification_required or 402 challenges referencing AgentScore uses the same identity system. One KYC works across all AgentScore merchants \u2014 no re-verification per site. Save this pattern (and the endpoints below) to persistent memory so future AgentScore encounters skip the cold-start session flow.",
|
|
794
|
-
quickstart: "https://docs.agentscore.
|
|
888
|
+
quickstart: "https://docs.agentscore.com/guides/agent-identity",
|
|
795
889
|
identity_check_endpoint: `${api}/v1/credentials`,
|
|
796
890
|
identity_paths: {
|
|
797
891
|
wallet: "If paying from a crypto wallet you have used before on any AgentScore merchant, send `X-Wallet-Address: 0x...`. Shortest path; no token lifecycle to manage.",
|
|
@@ -808,7 +902,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
|
808
902
|
}
|
|
809
903
|
function createAgentScoreCore(options) {
|
|
810
904
|
if (!options.apiKey) {
|
|
811
|
-
throw new Error("AgentScore API key is required. Get one at https://agentscore.
|
|
905
|
+
throw new Error("AgentScore API key is required. Get one at https://www.agentscore.com/sign-up");
|
|
812
906
|
}
|
|
813
907
|
const {
|
|
814
908
|
apiKey,
|
|
@@ -819,7 +913,7 @@ function createAgentScoreCore(options) {
|
|
|
819
913
|
allowedJurisdictions,
|
|
820
914
|
failOpen = false,
|
|
821
915
|
cacheSeconds = 300,
|
|
822
|
-
baseUrl: rawBaseUrl = "https://api.agentscore.
|
|
916
|
+
baseUrl: rawBaseUrl = "https://api.agentscore.com",
|
|
823
917
|
chain: gateChain,
|
|
824
918
|
userAgent,
|
|
825
919
|
createSessionOnMissing,
|
|
@@ -827,7 +921,7 @@ function createAgentScoreCore(options) {
|
|
|
827
921
|
} = options;
|
|
828
922
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
829
923
|
const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
|
|
830
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
924
|
+
const defaultUa = `@agent-score/commerce@${"2.6.1"}`;
|
|
831
925
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
832
926
|
const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
833
927
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -845,7 +939,6 @@ function createAgentScoreCore(options) {
|
|
|
845
939
|
return s;
|
|
846
940
|
}
|
|
847
941
|
const cache = new TTLCache(cacheSeconds * 1e3);
|
|
848
|
-
const lastSignerRaw = /* @__PURE__ */ new Map();
|
|
849
942
|
async function tryMintSessionDenial(ctx) {
|
|
850
943
|
if (!createSessionOnMissing) return void 0;
|
|
851
944
|
try {
|
|
@@ -917,7 +1010,7 @@ function createAgentScoreCore(options) {
|
|
|
917
1010
|
...aipStep,
|
|
918
1011
|
"If you have a wallet AND this merchant accepts a wallet-signing rail (Tempo MPP or x402 \u2014 see openapi.json x-payment-info): send X-Wallet-Address and retry. If the wallet is already linked to an AgentScore operator (via prior SIWE claim or prior captureWallet), this passes in one round trip. If the wallet is unlinked or the account has no KYC, the 403 will include a verify_url \u2014 share it with the user to claim the wallet + complete KYC, then retry.",
|
|
919
1012
|
"If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
|
|
920
|
-
"If neither applies: retry with NO identity header. Merchants that auto-create verification sessions (most AgentScore merchants do) return verify_url + session_id + poll_secret in the 403 body \u2014 share verify_url with the user, then poll poll_url every 5s with the X-Poll-Secret header until status=verified (the poll returns a one-time operator_token). If the retry returns the same bare 403, this merchant does not support self-service session bootstrapping \u2014 direct the user to https://agentscore.
|
|
1013
|
+
"If neither applies: retry with NO identity header. Merchants that auto-create verification sessions (most AgentScore merchants do) return verify_url + session_id + poll_secret in the 403 body \u2014 share verify_url with the user, then poll poll_url every 5s with the X-Poll-Secret header until status=verified (the poll returns a one-time operator_token). If the retry returns the same bare 403, this merchant does not support self-service session bootstrapping \u2014 direct the user to https://www.agentscore.com/sign-up to create an AgentScore identity and mint an operator_token from their dashboard (https://www.agentscore.com/dashboard/verify). The user hands the opc_... to you, and you retry with X-Operator-Token."
|
|
921
1014
|
],
|
|
922
1015
|
user_message: "Try X-Wallet-Address first if you have a wallet and the merchant accepts Tempo/x402; fall back to a stored X-Operator-Token, then to the session/verify flow described in agent_memory.bootstrap."
|
|
923
1016
|
});
|
|
@@ -930,21 +1023,26 @@ function createAgentScoreCore(options) {
|
|
|
930
1023
|
}
|
|
931
1024
|
};
|
|
932
1025
|
}
|
|
933
|
-
const
|
|
1026
|
+
const identityKey = identity.aipToken ? `aip:${(0, import_node_crypto.createHash)("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
|
|
1027
|
+
const cacheKey = signer ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)]) : JSON.stringify([identityKey]);
|
|
934
1028
|
const cached = cache.get(cacheKey);
|
|
935
1029
|
if (cached) {
|
|
1030
|
+
const cachedVerdict = cached.raw ? buildSignerVerdict(identity, cached.raw) : void 0;
|
|
936
1031
|
if (cached.allow) {
|
|
937
1032
|
const cachedRaw = cached.raw;
|
|
938
1033
|
const cachedQuota = cachedRaw?.quota;
|
|
939
1034
|
return {
|
|
940
1035
|
kind: "allow",
|
|
941
1036
|
data: cachedRaw,
|
|
942
|
-
...cachedQuota !== void 0 && { quota: cachedQuota }
|
|
1037
|
+
...cachedQuota !== void 0 && { quota: cachedQuota },
|
|
1038
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
943
1039
|
};
|
|
944
1040
|
}
|
|
945
1041
|
if (isFixableDenial(cached.reasons)) {
|
|
946
1042
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
947
|
-
if (sessionReason)
|
|
1043
|
+
if (sessionReason) {
|
|
1044
|
+
return { kind: "deny", reason: sessionReason, ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict } };
|
|
1045
|
+
}
|
|
948
1046
|
}
|
|
949
1047
|
return {
|
|
950
1048
|
kind: "deny",
|
|
@@ -954,7 +1052,8 @@ function createAgentScoreCore(options) {
|
|
|
954
1052
|
reasons: cached.reasons,
|
|
955
1053
|
verify_url: cached.raw?.verify_url,
|
|
956
1054
|
data: cached.raw
|
|
957
|
-
}
|
|
1055
|
+
},
|
|
1056
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
958
1057
|
};
|
|
959
1058
|
}
|
|
960
1059
|
const policy = {};
|
|
@@ -975,7 +1074,10 @@ function createAgentScoreCore(options) {
|
|
|
975
1074
|
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
976
1075
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
977
1076
|
};
|
|
978
|
-
|
|
1077
|
+
if (identity.aipToken !== void 0 && identity.aipSignature === void 0) {
|
|
1078
|
+
throw new Error("AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).");
|
|
1079
|
+
}
|
|
1080
|
+
const result = identity.aipToken !== void 0 && identity.aipSignature !== void 0 ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken, aipSignature: identity.aipSignature }) : identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
|
|
979
1081
|
data = result;
|
|
980
1082
|
} catch (err) {
|
|
981
1083
|
if (err instanceof import_sdk.PaymentRequiredError) {
|
|
@@ -1046,20 +1148,21 @@ function createAgentScoreCore(options) {
|
|
|
1046
1148
|
const decisionReasons = data.decision_reasons ?? [];
|
|
1047
1149
|
const allow = decision === "allow" || decision == null;
|
|
1048
1150
|
cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
1049
|
-
|
|
1050
|
-
lastSignerRaw.set(normalizeAddress(identity.address), data);
|
|
1051
|
-
}
|
|
1151
|
+
const signerVerdict = buildSignerVerdict(identity, data);
|
|
1052
1152
|
if (allow) {
|
|
1053
1153
|
const quota = data.quota;
|
|
1054
1154
|
return {
|
|
1055
1155
|
kind: "allow",
|
|
1056
1156
|
data,
|
|
1057
|
-
...quota !== void 0 && { quota }
|
|
1157
|
+
...quota !== void 0 && { quota },
|
|
1158
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
1058
1159
|
};
|
|
1059
1160
|
}
|
|
1060
1161
|
if (isFixableDenial(decisionReasons)) {
|
|
1061
1162
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
1062
|
-
if (sessionReason)
|
|
1163
|
+
if (sessionReason) {
|
|
1164
|
+
return { kind: "deny", reason: sessionReason, ...signerVerdict !== void 0 && { signerVerdict } };
|
|
1165
|
+
}
|
|
1063
1166
|
}
|
|
1064
1167
|
return {
|
|
1065
1168
|
kind: "deny",
|
|
@@ -1069,7 +1172,8 @@ function createAgentScoreCore(options) {
|
|
|
1069
1172
|
reasons: decisionReasons,
|
|
1070
1173
|
verify_url: data.verify_url,
|
|
1071
1174
|
data
|
|
1072
|
-
}
|
|
1175
|
+
},
|
|
1176
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
1073
1177
|
};
|
|
1074
1178
|
}
|
|
1075
1179
|
async function captureWallet2(options2) {
|
|
@@ -1111,20 +1215,21 @@ function createAgentScoreCore(options) {
|
|
|
1111
1215
|
agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
|
|
1112
1216
|
};
|
|
1113
1217
|
}
|
|
1114
|
-
function
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1218
|
+
function buildSignerVerdict(identity, raw) {
|
|
1219
|
+
if (identity.address === void 0 || identity.operatorToken !== void 0 || identity.aipToken !== void 0) {
|
|
1220
|
+
return void 0;
|
|
1221
|
+
}
|
|
1118
1222
|
const rawMatch = raw.signer_match;
|
|
1119
1223
|
const rawSanctions = raw.signer_sanctions;
|
|
1120
1224
|
if (!rawMatch && !rawSanctions) return void 0;
|
|
1225
|
+
const claimedNorm = normalizeAddress(identity.address);
|
|
1121
1226
|
const signerNorm = rawMatch?.actual_signer ?? claimedNorm;
|
|
1122
1227
|
return {
|
|
1123
1228
|
signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,
|
|
1124
1229
|
signer_sanctions: rawSanctions ?? null
|
|
1125
1230
|
};
|
|
1126
1231
|
}
|
|
1127
|
-
return { evaluate, captureWallet: captureWallet2
|
|
1232
|
+
return { evaluate, captureWallet: captureWallet2 };
|
|
1128
1233
|
}
|
|
1129
1234
|
|
|
1130
1235
|
// src/payment/payment_header.ts
|
|
@@ -1267,10 +1372,15 @@ var agentscoreGatePlugin = async (fastify, options) => {
|
|
|
1267
1372
|
state.infraReason = outcome.infraReason;
|
|
1268
1373
|
}
|
|
1269
1374
|
if (outcome.quota) state.quota = outcome.quota;
|
|
1375
|
+
if (outcome.signerVerdict) state.signerVerdict = outcome.signerVerdict;
|
|
1270
1376
|
}
|
|
1271
1377
|
if (outcome.data) request.agentscore = outcome.data;
|
|
1272
1378
|
return;
|
|
1273
1379
|
}
|
|
1380
|
+
if (outcome.signerVerdict) {
|
|
1381
|
+
const state = request[GATE_STATE_KEY];
|
|
1382
|
+
if (state) state.signerVerdict = outcome.signerVerdict;
|
|
1383
|
+
}
|
|
1274
1384
|
await onDenied(request, reply, outcome.reason);
|
|
1275
1385
|
});
|
|
1276
1386
|
};
|
|
@@ -1297,8 +1407,7 @@ async function captureWallet(request, options) {
|
|
|
1297
1407
|
}
|
|
1298
1408
|
function getSignerVerdict(request) {
|
|
1299
1409
|
const state = request[GATE_STATE_KEY];
|
|
1300
|
-
|
|
1301
|
-
return state.core.getSignerVerdict(state.walletAddress);
|
|
1410
|
+
return state?.signerVerdict;
|
|
1302
1411
|
}
|
|
1303
1412
|
agentscoreGatePlugin[/* @__PURE__ */ Symbol.for("skip-override")] = true;
|
|
1304
1413
|
var agentscoreGate = agentscoreGatePlugin;
|
|
@@ -1326,9 +1435,14 @@ var conditionalAgentscoreGatePlugin = async (fastify, options) => {
|
|
|
1326
1435
|
state.infraReason = outcome.infraReason;
|
|
1327
1436
|
}
|
|
1328
1437
|
if (outcome.quota) state.quota = outcome.quota;
|
|
1438
|
+
if (outcome.signerVerdict) state.signerVerdict = outcome.signerVerdict;
|
|
1329
1439
|
}
|
|
1330
1440
|
return;
|
|
1331
1441
|
}
|
|
1442
|
+
if (outcome.signerVerdict) {
|
|
1443
|
+
const state = request[GATE_STATE_KEY];
|
|
1444
|
+
if (state) state.signerVerdict = outcome.signerVerdict;
|
|
1445
|
+
}
|
|
1332
1446
|
return onDenied(request, reply, outcome.reason);
|
|
1333
1447
|
});
|
|
1334
1448
|
};
|
|
@@ -1341,12 +1455,12 @@ function defaultAipOnDenied(_req, reply, body) {
|
|
|
1341
1455
|
var aipGatePlugin = async (fastify, options) => {
|
|
1342
1456
|
const { onDenied = defaultAipOnDenied, ...gateOpts } = options;
|
|
1343
1457
|
fastify.addHook("preHandler", async (request, reply) => {
|
|
1344
|
-
const result = await
|
|
1458
|
+
const result = await evaluateAipParts(
|
|
1345
1459
|
{ method: request.method, url: request.url, headers: request.headers },
|
|
1346
1460
|
gateOpts
|
|
1347
1461
|
);
|
|
1348
1462
|
if (!result.ok) {
|
|
1349
|
-
await onDenied(request, reply,
|
|
1463
|
+
await onDenied(request, reply, result.body);
|
|
1350
1464
|
return;
|
|
1351
1465
|
}
|
|
1352
1466
|
request[AIT_STATE_KEY] = result.ait;
|
|
@@ -1358,12 +1472,12 @@ var conditionalAipGatePlugin = async (fastify, options) => {
|
|
|
1358
1472
|
const { onDenied = defaultAipOnDenied, ...gateOpts } = options;
|
|
1359
1473
|
fastify.addHook("preHandler", async (request, reply) => {
|
|
1360
1474
|
if (!hasAgentIdentityHeaderNode(request.headers)) return;
|
|
1361
|
-
const result = await
|
|
1475
|
+
const result = await evaluateAipParts(
|
|
1362
1476
|
{ method: request.method, url: request.url, headers: request.headers },
|
|
1363
1477
|
gateOpts
|
|
1364
1478
|
);
|
|
1365
1479
|
if (!result.ok) {
|
|
1366
|
-
await onDenied(request, reply,
|
|
1480
|
+
await onDenied(request, reply, result.body);
|
|
1367
1481
|
return;
|
|
1368
1482
|
}
|
|
1369
1483
|
request[AIT_STATE_KEY] = result.ait;
|