@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
package/dist/identity/express.js
CHANGED
|
@@ -79,7 +79,7 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
|
79
79
|
var API_ERROR_INSTRUCTIONS = JSON.stringify({
|
|
80
80
|
action: "retry_with_backoff",
|
|
81
81
|
steps: [
|
|
82
|
-
"Verification is temporarily unavailable. Retry the request after 5
|
|
82
|
+
"Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.",
|
|
83
83
|
"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.",
|
|
84
84
|
"If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
|
|
85
85
|
],
|
|
@@ -183,6 +183,7 @@ var b64ToBytes = (b64) => {
|
|
|
183
183
|
var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
|
|
184
184
|
var AIP_SIGNATURE_TAG = "agent-identity";
|
|
185
185
|
var DEFAULT_MAX_SKEW_SECONDS = 60;
|
|
186
|
+
var MAX_POP_WINDOW_SECONDS = 120;
|
|
186
187
|
var normalizeAuthority = (authority) => {
|
|
187
188
|
const lower = authority.trim().toLowerCase();
|
|
188
189
|
const colon = lower.lastIndexOf(":");
|
|
@@ -233,7 +234,7 @@ var serializeParams = (p) => {
|
|
|
233
234
|
}
|
|
234
235
|
return parts.map((s) => `;${s}`).join("");
|
|
235
236
|
};
|
|
236
|
-
var buildSignatureBase = (params, input) => {
|
|
237
|
+
var buildSignatureBase = (params, input, rawSignatureParams) => {
|
|
237
238
|
const lines = [];
|
|
238
239
|
for (const name of params.components) {
|
|
239
240
|
const value = componentValue(name, input);
|
|
@@ -242,7 +243,7 @@ var buildSignatureBase = (params, input) => {
|
|
|
242
243
|
}
|
|
243
244
|
lines.push(`"${name}": ${value}`);
|
|
244
245
|
}
|
|
245
|
-
const paramsValue = serializeComponentList(params.components) + serializeParams(params);
|
|
246
|
+
const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);
|
|
246
247
|
lines.push(`"@signature-params": ${paramsValue}`);
|
|
247
248
|
return lines.join("\n");
|
|
248
249
|
};
|
|
@@ -261,19 +262,12 @@ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
|
|
|
261
262
|
}
|
|
262
263
|
const parsed = members.map((m) => {
|
|
263
264
|
const params = parseInnerListMember(m.value);
|
|
264
|
-
return params ? { label: m.label, params } : null;
|
|
265
|
+
return params ? { label: m.label, params, rawParams: m.value } : null;
|
|
265
266
|
}).filter((x) => x !== null);
|
|
266
267
|
if (parsed.length === 0) {
|
|
267
268
|
return null;
|
|
268
269
|
}
|
|
269
|
-
|
|
270
|
-
if (tagged) {
|
|
271
|
-
return tagged;
|
|
272
|
-
}
|
|
273
|
-
if (parsed.length === 1 && parsed[0].params.tag === void 0) {
|
|
274
|
-
return parsed[0];
|
|
275
|
-
}
|
|
276
|
-
return null;
|
|
270
|
+
return parsed.find((p) => p.params.tag === tag) ?? null;
|
|
277
271
|
};
|
|
278
272
|
var parseSignatureValue = (header, label) => {
|
|
279
273
|
const members = splitDictionary(header);
|
|
@@ -387,7 +381,7 @@ var verifyMessageSignature = async (input) => {
|
|
|
387
381
|
if (!selected) {
|
|
388
382
|
return { ok: false, reason: "no_aip_signature" };
|
|
389
383
|
}
|
|
390
|
-
const { label, params } = selected;
|
|
384
|
+
const { label, params, rawParams } = selected;
|
|
391
385
|
if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
|
|
392
386
|
return { ok: false, reason: "unsupported_alg" };
|
|
393
387
|
}
|
|
@@ -396,12 +390,21 @@ var verifyMessageSignature = async (input) => {
|
|
|
396
390
|
return { ok: false, reason: "missing_covered_component" };
|
|
397
391
|
}
|
|
398
392
|
}
|
|
393
|
+
if (params.created === void 0) {
|
|
394
|
+
return { ok: false, reason: "created_missing" };
|
|
395
|
+
}
|
|
396
|
+
if (params.expires === void 0) {
|
|
397
|
+
return { ok: false, reason: "expires_missing" };
|
|
398
|
+
}
|
|
399
|
+
if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {
|
|
400
|
+
return { ok: false, reason: "pop_window_too_long" };
|
|
401
|
+
}
|
|
399
402
|
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
400
403
|
const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
|
|
401
|
-
if (params.created
|
|
404
|
+
if (params.created > now + skew) {
|
|
402
405
|
return { ok: false, reason: "created_in_future" };
|
|
403
406
|
}
|
|
404
|
-
if (params.expires
|
|
407
|
+
if (params.expires < now - skew) {
|
|
405
408
|
return { ok: false, reason: "expired" };
|
|
406
409
|
}
|
|
407
410
|
if (!params.keyid) {
|
|
@@ -432,7 +435,7 @@ var verifyMessageSignature = async (input) => {
|
|
|
432
435
|
path: input.path,
|
|
433
436
|
agentIdentity: input.agentIdentity,
|
|
434
437
|
extra: input.extraComponents
|
|
435
|
-
});
|
|
438
|
+
}, rawParams);
|
|
436
439
|
} catch (err) {
|
|
437
440
|
if (err instanceof MissingComponentError) {
|
|
438
441
|
return { ok: false, reason: "missing_covered_component" };
|
|
@@ -504,6 +507,8 @@ var verifyAit = async (ctx, opts) => {
|
|
|
504
507
|
if (!ctx.signatureInput || !ctx.signature) {
|
|
505
508
|
return { ok: false, reason: "pop_signature_missing" };
|
|
506
509
|
}
|
|
510
|
+
const signatureInput = ctx.signatureInput;
|
|
511
|
+
const signature = ctx.signature;
|
|
507
512
|
let lastFailure = "malformed_token";
|
|
508
513
|
for (const raw of ctx.agentIdentityHeaders) {
|
|
509
514
|
const token = stripBearer(raw);
|
|
@@ -542,7 +547,7 @@ var verifyAit = async (ctx, opts) => {
|
|
|
542
547
|
// Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
|
|
543
548
|
// this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
|
|
544
549
|
// non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
|
|
545
|
-
// token that verifies. Matches the server-side allowlist in
|
|
550
|
+
// token that verifies. Matches the server-side allowlist in the AgentScore API verifier.
|
|
546
551
|
algorithms: AIT_SIGNING_ALGS,
|
|
547
552
|
clockTolerance: jwtClockTolerance,
|
|
548
553
|
currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
|
|
@@ -556,13 +561,20 @@ var verifyAit = async (ctx, opts) => {
|
|
|
556
561
|
lastFailure = "expired_token";
|
|
557
562
|
continue;
|
|
558
563
|
}
|
|
564
|
+
if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {
|
|
565
|
+
lastFailure = "expired_token";
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
559
568
|
const popResult = await verifyMessageSignature({
|
|
560
569
|
method: ctx.method,
|
|
561
570
|
authority: ctx.authority,
|
|
562
571
|
path: ctx.path,
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
572
|
+
// The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is
|
|
573
|
+
// transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and
|
|
574
|
+
// the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.
|
|
575
|
+
agentIdentity: token,
|
|
576
|
+
signatureInput,
|
|
577
|
+
signature,
|
|
566
578
|
cnfJwk: claims.cnf.jwk,
|
|
567
579
|
now: opts.now,
|
|
568
580
|
maxSkewSeconds: opts.maxSkewSeconds
|
|
@@ -571,7 +583,22 @@ var verifyAit = async (ctx, opts) => {
|
|
|
571
583
|
lastFailure = "pop_signature_invalid";
|
|
572
584
|
continue;
|
|
573
585
|
}
|
|
574
|
-
return {
|
|
586
|
+
return {
|
|
587
|
+
ok: true,
|
|
588
|
+
ait: {
|
|
589
|
+
payload: claims,
|
|
590
|
+
iss: claims.iss,
|
|
591
|
+
cnfJwk: claims.cnf.jwk,
|
|
592
|
+
token,
|
|
593
|
+
signatureMaterial: {
|
|
594
|
+
method: ctx.method,
|
|
595
|
+
authority: ctx.authority,
|
|
596
|
+
path: ctx.path,
|
|
597
|
+
signature_input: signatureInput,
|
|
598
|
+
signature
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
};
|
|
575
602
|
}
|
|
576
603
|
return { ok: false, reason: lastFailure };
|
|
577
604
|
};
|
|
@@ -601,7 +628,12 @@ var buildVerifyContextFromParts = (parts) => {
|
|
|
601
628
|
const host = parts.authority ?? readNodeHeader(parts.headers, "host") ?? "";
|
|
602
629
|
let path;
|
|
603
630
|
try {
|
|
604
|
-
|
|
631
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(parts.url)) {
|
|
632
|
+
path = new URL(parts.url).pathname;
|
|
633
|
+
} else {
|
|
634
|
+
const target = parts.url.startsWith("/") ? parts.url : `/${parts.url}`;
|
|
635
|
+
path = new URL(`http://${host || "localhost"}${target}`).pathname;
|
|
636
|
+
}
|
|
605
637
|
} catch {
|
|
606
638
|
const q = parts.url.indexOf("?");
|
|
607
639
|
path = q === -1 ? parts.url : parts.url.slice(0, q);
|
|
@@ -617,11 +649,10 @@ var buildVerifyContextFromParts = (parts) => {
|
|
|
617
649
|
};
|
|
618
650
|
|
|
619
651
|
// src/aip/gate.ts
|
|
620
|
-
var
|
|
621
|
-
const
|
|
622
|
-
return
|
|
652
|
+
var partsWithAuthority = (parts, opts) => {
|
|
653
|
+
const authority = parts.authority ?? opts.authority;
|
|
654
|
+
return authority !== void 0 ? { ...parts, authority } : parts;
|
|
623
655
|
};
|
|
624
|
-
var verifyAitParts = (parts, opts) => verifyFromContext(buildVerifyContextFromParts(parts), opts);
|
|
625
656
|
var aipErrorCode = (failure) => {
|
|
626
657
|
switch (failure) {
|
|
627
658
|
case "no_token":
|
|
@@ -678,15 +709,78 @@ var aipErrorDetail = (failure) => {
|
|
|
678
709
|
return "Token verification failed.";
|
|
679
710
|
}
|
|
680
711
|
};
|
|
681
|
-
var buildAipErrorBody = (failure) => {
|
|
712
|
+
var buildAipErrorBody = (failure, requirements) => {
|
|
682
713
|
const code = aipErrorCode(failure);
|
|
683
|
-
|
|
714
|
+
const body = {
|
|
684
715
|
type: `urn:aip:error:${code}`,
|
|
685
716
|
title: code.replace(/_/g, " "),
|
|
686
717
|
status: aipErrorStatus(failure),
|
|
687
718
|
detail: aipErrorDetail(failure)
|
|
688
719
|
};
|
|
720
|
+
if (requirements) {
|
|
721
|
+
if (code === "untrusted_issuer" && requirements.trustedIssuers?.length) {
|
|
722
|
+
body.trusted_issuers = requirements.trustedIssuers;
|
|
723
|
+
}
|
|
724
|
+
if (code === "insufficient_claims") {
|
|
725
|
+
if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;
|
|
726
|
+
if (requirements.requiredTrustLevel !== void 0) body.required_trust_level = requirements.requiredTrustLevel;
|
|
727
|
+
if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return body;
|
|
731
|
+
};
|
|
732
|
+
var TRUST_RANK = { autonomous: 0, human_present: 1, human_confirmed: 2 };
|
|
733
|
+
var checkTrustRequirements = (payload, requiredTrustLevel, requiredAmr) => {
|
|
734
|
+
if (requiredTrustLevel !== void 0) {
|
|
735
|
+
const have = TRUST_RANK[payload.trust_level ?? "autonomous"] ?? 0;
|
|
736
|
+
const need = TRUST_RANK[requiredTrustLevel] ?? 0;
|
|
737
|
+
if (have < need) {
|
|
738
|
+
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).`;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (requiredAmr !== void 0 && requiredAmr.length > 0) {
|
|
742
|
+
const amr = Array.isArray(payload.auth?.amr) ? payload.auth.amr : [];
|
|
743
|
+
if (!amr.some((m) => requiredAmr.includes(m))) {
|
|
744
|
+
return `This endpoint requires an authentication method in [${requiredAmr.join(", ")}]; the token carries [${amr.join(", ") || "none"}].`;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
return null;
|
|
748
|
+
};
|
|
749
|
+
var buildAipWeakAuthBody = (opts) => ({
|
|
750
|
+
type: "urn:aip:error:weak_auth",
|
|
751
|
+
title: "weak auth",
|
|
752
|
+
status: 403,
|
|
753
|
+
detail: opts.detail,
|
|
754
|
+
...opts.requiredTrustLevel !== void 0 && { required_trust_level: opts.requiredTrustLevel },
|
|
755
|
+
...opts.requiredAmr !== void 0 && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr },
|
|
756
|
+
...opts.trustedIssuers !== void 0 && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }
|
|
757
|
+
});
|
|
758
|
+
var requirementsFromOptions = (opts) => ({
|
|
759
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers },
|
|
760
|
+
...opts.requiredClaims !== void 0 && { requiredClaims: opts.requiredClaims },
|
|
761
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
762
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr }
|
|
763
|
+
});
|
|
764
|
+
var evaluateFromContext = async (ctx, opts) => {
|
|
765
|
+
const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
|
|
766
|
+
if (!result.ok) {
|
|
767
|
+
return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };
|
|
768
|
+
}
|
|
769
|
+
const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);
|
|
770
|
+
if (weak !== null) {
|
|
771
|
+
return {
|
|
772
|
+
ok: false,
|
|
773
|
+
body: buildAipWeakAuthBody({
|
|
774
|
+
detail: weak,
|
|
775
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
776
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr },
|
|
777
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers }
|
|
778
|
+
})
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
return { ok: true, ait: result.ait };
|
|
689
782
|
};
|
|
783
|
+
var evaluateAipParts = (parts, opts) => evaluateFromContext(buildVerifyContextFromParts(partsWithAuthority(parts, opts)), opts);
|
|
690
784
|
|
|
691
785
|
// src/core.ts
|
|
692
786
|
var import_node_crypto = require("crypto");
|
|
@@ -758,7 +852,7 @@ function stripTrailingSlashes(s) {
|
|
|
758
852
|
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
759
853
|
return end === s.length ? s : s.slice(0, end);
|
|
760
854
|
}
|
|
761
|
-
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.
|
|
855
|
+
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.com";
|
|
762
856
|
var WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({
|
|
763
857
|
action: "resign_or_switch_to_operator_token",
|
|
764
858
|
steps: [
|
|
@@ -790,7 +884,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
|
790
884
|
return {
|
|
791
885
|
save_for_future_agentscore_gates: true,
|
|
792
886
|
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.",
|
|
793
|
-
quickstart: "https://docs.agentscore.
|
|
887
|
+
quickstart: "https://docs.agentscore.com/guides/agent-identity",
|
|
794
888
|
identity_check_endpoint: `${api}/v1/credentials`,
|
|
795
889
|
identity_paths: {
|
|
796
890
|
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.",
|
|
@@ -807,7 +901,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
|
807
901
|
}
|
|
808
902
|
function createAgentScoreCore(options) {
|
|
809
903
|
if (!options.apiKey) {
|
|
810
|
-
throw new Error("AgentScore API key is required. Get one at https://agentscore.
|
|
904
|
+
throw new Error("AgentScore API key is required. Get one at https://www.agentscore.com/sign-up");
|
|
811
905
|
}
|
|
812
906
|
const {
|
|
813
907
|
apiKey,
|
|
@@ -818,7 +912,7 @@ function createAgentScoreCore(options) {
|
|
|
818
912
|
allowedJurisdictions,
|
|
819
913
|
failOpen = false,
|
|
820
914
|
cacheSeconds = 300,
|
|
821
|
-
baseUrl: rawBaseUrl = "https://api.agentscore.
|
|
915
|
+
baseUrl: rawBaseUrl = "https://api.agentscore.com",
|
|
822
916
|
chain: gateChain,
|
|
823
917
|
userAgent,
|
|
824
918
|
createSessionOnMissing,
|
|
@@ -826,7 +920,7 @@ function createAgentScoreCore(options) {
|
|
|
826
920
|
} = options;
|
|
827
921
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
828
922
|
const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
|
|
829
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
923
|
+
const defaultUa = `@agent-score/commerce@${"2.6.1"}`;
|
|
830
924
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
831
925
|
const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
832
926
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -844,7 +938,6 @@ function createAgentScoreCore(options) {
|
|
|
844
938
|
return s;
|
|
845
939
|
}
|
|
846
940
|
const cache = new TTLCache(cacheSeconds * 1e3);
|
|
847
|
-
const lastSignerRaw = /* @__PURE__ */ new Map();
|
|
848
941
|
async function tryMintSessionDenial(ctx) {
|
|
849
942
|
if (!createSessionOnMissing) return void 0;
|
|
850
943
|
try {
|
|
@@ -916,7 +1009,7 @@ function createAgentScoreCore(options) {
|
|
|
916
1009
|
...aipStep,
|
|
917
1010
|
"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.",
|
|
918
1011
|
"If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
|
|
919
|
-
"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.
|
|
1012
|
+
"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."
|
|
920
1013
|
],
|
|
921
1014
|
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."
|
|
922
1015
|
});
|
|
@@ -929,21 +1022,26 @@ function createAgentScoreCore(options) {
|
|
|
929
1022
|
}
|
|
930
1023
|
};
|
|
931
1024
|
}
|
|
932
|
-
const
|
|
1025
|
+
const identityKey = identity.aipToken ? `aip:${(0, import_node_crypto.createHash)("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
|
|
1026
|
+
const cacheKey = signer ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)]) : JSON.stringify([identityKey]);
|
|
933
1027
|
const cached = cache.get(cacheKey);
|
|
934
1028
|
if (cached) {
|
|
1029
|
+
const cachedVerdict = cached.raw ? buildSignerVerdict(identity, cached.raw) : void 0;
|
|
935
1030
|
if (cached.allow) {
|
|
936
1031
|
const cachedRaw = cached.raw;
|
|
937
1032
|
const cachedQuota = cachedRaw?.quota;
|
|
938
1033
|
return {
|
|
939
1034
|
kind: "allow",
|
|
940
1035
|
data: cachedRaw,
|
|
941
|
-
...cachedQuota !== void 0 && { quota: cachedQuota }
|
|
1036
|
+
...cachedQuota !== void 0 && { quota: cachedQuota },
|
|
1037
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
942
1038
|
};
|
|
943
1039
|
}
|
|
944
1040
|
if (isFixableDenial(cached.reasons)) {
|
|
945
1041
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
946
|
-
if (sessionReason)
|
|
1042
|
+
if (sessionReason) {
|
|
1043
|
+
return { kind: "deny", reason: sessionReason, ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict } };
|
|
1044
|
+
}
|
|
947
1045
|
}
|
|
948
1046
|
return {
|
|
949
1047
|
kind: "deny",
|
|
@@ -953,7 +1051,8 @@ function createAgentScoreCore(options) {
|
|
|
953
1051
|
reasons: cached.reasons,
|
|
954
1052
|
verify_url: cached.raw?.verify_url,
|
|
955
1053
|
data: cached.raw
|
|
956
|
-
}
|
|
1054
|
+
},
|
|
1055
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
957
1056
|
};
|
|
958
1057
|
}
|
|
959
1058
|
const policy = {};
|
|
@@ -974,7 +1073,10 @@ function createAgentScoreCore(options) {
|
|
|
974
1073
|
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
975
1074
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
976
1075
|
};
|
|
977
|
-
|
|
1076
|
+
if (identity.aipToken !== void 0 && identity.aipSignature === void 0) {
|
|
1077
|
+
throw new Error("AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).");
|
|
1078
|
+
}
|
|
1079
|
+
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 });
|
|
978
1080
|
data = result;
|
|
979
1081
|
} catch (err) {
|
|
980
1082
|
if (err instanceof import_sdk.PaymentRequiredError) {
|
|
@@ -1045,20 +1147,21 @@ function createAgentScoreCore(options) {
|
|
|
1045
1147
|
const decisionReasons = data.decision_reasons ?? [];
|
|
1046
1148
|
const allow = decision === "allow" || decision == null;
|
|
1047
1149
|
cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
1048
|
-
|
|
1049
|
-
lastSignerRaw.set(normalizeAddress(identity.address), data);
|
|
1050
|
-
}
|
|
1150
|
+
const signerVerdict = buildSignerVerdict(identity, data);
|
|
1051
1151
|
if (allow) {
|
|
1052
1152
|
const quota = data.quota;
|
|
1053
1153
|
return {
|
|
1054
1154
|
kind: "allow",
|
|
1055
1155
|
data,
|
|
1056
|
-
...quota !== void 0 && { quota }
|
|
1156
|
+
...quota !== void 0 && { quota },
|
|
1157
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
1057
1158
|
};
|
|
1058
1159
|
}
|
|
1059
1160
|
if (isFixableDenial(decisionReasons)) {
|
|
1060
1161
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
1061
|
-
if (sessionReason)
|
|
1162
|
+
if (sessionReason) {
|
|
1163
|
+
return { kind: "deny", reason: sessionReason, ...signerVerdict !== void 0 && { signerVerdict } };
|
|
1164
|
+
}
|
|
1062
1165
|
}
|
|
1063
1166
|
return {
|
|
1064
1167
|
kind: "deny",
|
|
@@ -1068,7 +1171,8 @@ function createAgentScoreCore(options) {
|
|
|
1068
1171
|
reasons: decisionReasons,
|
|
1069
1172
|
verify_url: data.verify_url,
|
|
1070
1173
|
data
|
|
1071
|
-
}
|
|
1174
|
+
},
|
|
1175
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
1072
1176
|
};
|
|
1073
1177
|
}
|
|
1074
1178
|
async function captureWallet2(options2) {
|
|
@@ -1110,20 +1214,21 @@ function createAgentScoreCore(options) {
|
|
|
1110
1214
|
agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
|
|
1111
1215
|
};
|
|
1112
1216
|
}
|
|
1113
|
-
function
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1217
|
+
function buildSignerVerdict(identity, raw) {
|
|
1218
|
+
if (identity.address === void 0 || identity.operatorToken !== void 0 || identity.aipToken !== void 0) {
|
|
1219
|
+
return void 0;
|
|
1220
|
+
}
|
|
1117
1221
|
const rawMatch = raw.signer_match;
|
|
1118
1222
|
const rawSanctions = raw.signer_sanctions;
|
|
1119
1223
|
if (!rawMatch && !rawSanctions) return void 0;
|
|
1224
|
+
const claimedNorm = normalizeAddress(identity.address);
|
|
1120
1225
|
const signerNorm = rawMatch?.actual_signer ?? claimedNorm;
|
|
1121
1226
|
return {
|
|
1122
1227
|
signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,
|
|
1123
1228
|
signer_sanctions: rawSanctions ?? null
|
|
1124
1229
|
};
|
|
1125
1230
|
}
|
|
1126
|
-
return { evaluate, captureWallet: captureWallet2
|
|
1231
|
+
return { evaluate, captureWallet: captureWallet2 };
|
|
1127
1232
|
}
|
|
1128
1233
|
|
|
1129
1234
|
// src/payment/payment_header.ts
|
|
@@ -1266,11 +1371,16 @@ function agentscoreGate(options) {
|
|
|
1266
1371
|
state.infraReason = outcome.infraReason;
|
|
1267
1372
|
}
|
|
1268
1373
|
if (outcome.quota) state.quota = outcome.quota;
|
|
1374
|
+
if (outcome.signerVerdict) state.signerVerdict = outcome.signerVerdict;
|
|
1269
1375
|
}
|
|
1270
1376
|
if (outcome.data) req.agentscore = outcome.data;
|
|
1271
1377
|
next();
|
|
1272
1378
|
return;
|
|
1273
1379
|
}
|
|
1380
|
+
if (outcome.signerVerdict) {
|
|
1381
|
+
const state = req[GATE_STATE_KEY];
|
|
1382
|
+
if (state) state.signerVerdict = outcome.signerVerdict;
|
|
1383
|
+
}
|
|
1274
1384
|
onDenied(req, res, outcome.reason);
|
|
1275
1385
|
};
|
|
1276
1386
|
}
|
|
@@ -1297,8 +1407,7 @@ async function captureWallet(req, options) {
|
|
|
1297
1407
|
}
|
|
1298
1408
|
function getSignerVerdict(req) {
|
|
1299
1409
|
const state = req[GATE_STATE_KEY];
|
|
1300
|
-
|
|
1301
|
-
return state.core.getSignerVerdict(state.walletAddress);
|
|
1410
|
+
return state?.signerVerdict;
|
|
1302
1411
|
}
|
|
1303
1412
|
function conditionalAgentscoreGate(options) {
|
|
1304
1413
|
const gate = agentscoreGate(options);
|
|
@@ -1317,12 +1426,12 @@ function defaultAipOnDenied(_req, res, body) {
|
|
|
1317
1426
|
function aipGate(options) {
|
|
1318
1427
|
const { onDenied = defaultAipOnDenied, ...gateOpts } = options;
|
|
1319
1428
|
return async function aipGateMiddleware(req, res, next) {
|
|
1320
|
-
const result = await
|
|
1429
|
+
const result = await evaluateAipParts(
|
|
1321
1430
|
{ method: req.method, url: req.url, headers: req.headers },
|
|
1322
1431
|
gateOpts
|
|
1323
1432
|
);
|
|
1324
1433
|
if (!result.ok) {
|
|
1325
|
-
onDenied(req, res,
|
|
1434
|
+
onDenied(req, res, result.body);
|
|
1326
1435
|
return;
|
|
1327
1436
|
}
|
|
1328
1437
|
req[AIT_STATE_KEY] = result.ait;
|