@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/web.mjs
CHANGED
|
@@ -44,7 +44,7 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
|
44
44
|
var API_ERROR_INSTRUCTIONS = JSON.stringify({
|
|
45
45
|
action: "retry_with_backoff",
|
|
46
46
|
steps: [
|
|
47
|
-
"Verification is temporarily unavailable. Retry the request after 5
|
|
47
|
+
"Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.",
|
|
48
48
|
"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.",
|
|
49
49
|
"If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
|
|
50
50
|
],
|
|
@@ -148,6 +148,7 @@ var b64ToBytes = (b64) => {
|
|
|
148
148
|
var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
|
|
149
149
|
var AIP_SIGNATURE_TAG = "agent-identity";
|
|
150
150
|
var DEFAULT_MAX_SKEW_SECONDS = 60;
|
|
151
|
+
var MAX_POP_WINDOW_SECONDS = 120;
|
|
151
152
|
var normalizeAuthority = (authority) => {
|
|
152
153
|
const lower = authority.trim().toLowerCase();
|
|
153
154
|
const colon = lower.lastIndexOf(":");
|
|
@@ -198,7 +199,7 @@ var serializeParams = (p) => {
|
|
|
198
199
|
}
|
|
199
200
|
return parts.map((s) => `;${s}`).join("");
|
|
200
201
|
};
|
|
201
|
-
var buildSignatureBase = (params, input) => {
|
|
202
|
+
var buildSignatureBase = (params, input, rawSignatureParams) => {
|
|
202
203
|
const lines = [];
|
|
203
204
|
for (const name of params.components) {
|
|
204
205
|
const value = componentValue(name, input);
|
|
@@ -207,7 +208,7 @@ var buildSignatureBase = (params, input) => {
|
|
|
207
208
|
}
|
|
208
209
|
lines.push(`"${name}": ${value}`);
|
|
209
210
|
}
|
|
210
|
-
const paramsValue = serializeComponentList(params.components) + serializeParams(params);
|
|
211
|
+
const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);
|
|
211
212
|
lines.push(`"@signature-params": ${paramsValue}`);
|
|
212
213
|
return lines.join("\n");
|
|
213
214
|
};
|
|
@@ -226,19 +227,12 @@ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
|
|
|
226
227
|
}
|
|
227
228
|
const parsed = members.map((m) => {
|
|
228
229
|
const params = parseInnerListMember(m.value);
|
|
229
|
-
return params ? { label: m.label, params } : null;
|
|
230
|
+
return params ? { label: m.label, params, rawParams: m.value } : null;
|
|
230
231
|
}).filter((x) => x !== null);
|
|
231
232
|
if (parsed.length === 0) {
|
|
232
233
|
return null;
|
|
233
234
|
}
|
|
234
|
-
|
|
235
|
-
if (tagged) {
|
|
236
|
-
return tagged;
|
|
237
|
-
}
|
|
238
|
-
if (parsed.length === 1 && parsed[0].params.tag === void 0) {
|
|
239
|
-
return parsed[0];
|
|
240
|
-
}
|
|
241
|
-
return null;
|
|
235
|
+
return parsed.find((p) => p.params.tag === tag) ?? null;
|
|
242
236
|
};
|
|
243
237
|
var parseSignatureValue = (header, label) => {
|
|
244
238
|
const members = splitDictionary(header);
|
|
@@ -352,7 +346,7 @@ var verifyMessageSignature = async (input) => {
|
|
|
352
346
|
if (!selected) {
|
|
353
347
|
return { ok: false, reason: "no_aip_signature" };
|
|
354
348
|
}
|
|
355
|
-
const { label, params } = selected;
|
|
349
|
+
const { label, params, rawParams } = selected;
|
|
356
350
|
if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
|
|
357
351
|
return { ok: false, reason: "unsupported_alg" };
|
|
358
352
|
}
|
|
@@ -361,12 +355,21 @@ var verifyMessageSignature = async (input) => {
|
|
|
361
355
|
return { ok: false, reason: "missing_covered_component" };
|
|
362
356
|
}
|
|
363
357
|
}
|
|
358
|
+
if (params.created === void 0) {
|
|
359
|
+
return { ok: false, reason: "created_missing" };
|
|
360
|
+
}
|
|
361
|
+
if (params.expires === void 0) {
|
|
362
|
+
return { ok: false, reason: "expires_missing" };
|
|
363
|
+
}
|
|
364
|
+
if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {
|
|
365
|
+
return { ok: false, reason: "pop_window_too_long" };
|
|
366
|
+
}
|
|
364
367
|
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
365
368
|
const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
|
|
366
|
-
if (params.created
|
|
369
|
+
if (params.created > now + skew) {
|
|
367
370
|
return { ok: false, reason: "created_in_future" };
|
|
368
371
|
}
|
|
369
|
-
if (params.expires
|
|
372
|
+
if (params.expires < now - skew) {
|
|
370
373
|
return { ok: false, reason: "expired" };
|
|
371
374
|
}
|
|
372
375
|
if (!params.keyid) {
|
|
@@ -397,7 +400,7 @@ var verifyMessageSignature = async (input) => {
|
|
|
397
400
|
path: input.path,
|
|
398
401
|
agentIdentity: input.agentIdentity,
|
|
399
402
|
extra: input.extraComponents
|
|
400
|
-
});
|
|
403
|
+
}, rawParams);
|
|
401
404
|
} catch (err) {
|
|
402
405
|
if (err instanceof MissingComponentError) {
|
|
403
406
|
return { ok: false, reason: "missing_covered_component" };
|
|
@@ -470,6 +473,8 @@ var verifyAit = async (ctx, opts) => {
|
|
|
470
473
|
if (!ctx.signatureInput || !ctx.signature) {
|
|
471
474
|
return { ok: false, reason: "pop_signature_missing" };
|
|
472
475
|
}
|
|
476
|
+
const signatureInput = ctx.signatureInput;
|
|
477
|
+
const signature = ctx.signature;
|
|
473
478
|
let lastFailure = "malformed_token";
|
|
474
479
|
for (const raw of ctx.agentIdentityHeaders) {
|
|
475
480
|
const token = stripBearer(raw);
|
|
@@ -508,7 +513,7 @@ var verifyAit = async (ctx, opts) => {
|
|
|
508
513
|
// Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
|
|
509
514
|
// this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
|
|
510
515
|
// non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
|
|
511
|
-
// token that verifies. Matches the server-side allowlist in
|
|
516
|
+
// token that verifies. Matches the server-side allowlist in the AgentScore API verifier.
|
|
512
517
|
algorithms: AIT_SIGNING_ALGS,
|
|
513
518
|
clockTolerance: jwtClockTolerance,
|
|
514
519
|
currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
|
|
@@ -522,13 +527,20 @@ var verifyAit = async (ctx, opts) => {
|
|
|
522
527
|
lastFailure = "expired_token";
|
|
523
528
|
continue;
|
|
524
529
|
}
|
|
530
|
+
if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {
|
|
531
|
+
lastFailure = "expired_token";
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
525
534
|
const popResult = await verifyMessageSignature({
|
|
526
535
|
method: ctx.method,
|
|
527
536
|
authority: ctx.authority,
|
|
528
537
|
path: ctx.path,
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
538
|
+
// The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is
|
|
539
|
+
// transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and
|
|
540
|
+
// the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.
|
|
541
|
+
agentIdentity: token,
|
|
542
|
+
signatureInput,
|
|
543
|
+
signature,
|
|
532
544
|
cnfJwk: claims.cnf.jwk,
|
|
533
545
|
now: opts.now,
|
|
534
546
|
maxSkewSeconds: opts.maxSkewSeconds
|
|
@@ -537,7 +549,22 @@ var verifyAit = async (ctx, opts) => {
|
|
|
537
549
|
lastFailure = "pop_signature_invalid";
|
|
538
550
|
continue;
|
|
539
551
|
}
|
|
540
|
-
return {
|
|
552
|
+
return {
|
|
553
|
+
ok: true,
|
|
554
|
+
ait: {
|
|
555
|
+
payload: claims,
|
|
556
|
+
iss: claims.iss,
|
|
557
|
+
cnfJwk: claims.cnf.jwk,
|
|
558
|
+
token,
|
|
559
|
+
signatureMaterial: {
|
|
560
|
+
method: ctx.method,
|
|
561
|
+
authority: ctx.authority,
|
|
562
|
+
path: ctx.path,
|
|
563
|
+
signature_input: signatureInput,
|
|
564
|
+
signature
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
};
|
|
541
568
|
}
|
|
542
569
|
return { ok: false, reason: lastFailure };
|
|
543
570
|
};
|
|
@@ -558,11 +585,11 @@ var readAgentIdentityHeaders = (headers) => {
|
|
|
558
585
|
return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
559
586
|
};
|
|
560
587
|
var deriveAuthority = (req, url) => req.headers.get("host") ?? url.host;
|
|
561
|
-
var buildVerifyContextFromRequest = (req) => {
|
|
588
|
+
var buildVerifyContextFromRequest = (req, authority) => {
|
|
562
589
|
const url = new URL(req.url);
|
|
563
590
|
return {
|
|
564
591
|
method: req.method,
|
|
565
|
-
authority: deriveAuthority(req, url),
|
|
592
|
+
authority: authority ?? deriveAuthority(req, url),
|
|
566
593
|
path: url.pathname,
|
|
567
594
|
agentIdentityHeaders: readAgentIdentityHeaders(req.headers),
|
|
568
595
|
signatureInput: req.headers.get("signature-input"),
|
|
@@ -572,11 +599,6 @@ var buildVerifyContextFromRequest = (req) => {
|
|
|
572
599
|
var hasAgentIdentityHeader = (req) => readAgentIdentityHeaders(req.headers).length > 0;
|
|
573
600
|
|
|
574
601
|
// src/aip/gate.ts
|
|
575
|
-
var verifyFromContext = async (ctx, opts) => {
|
|
576
|
-
const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
|
|
577
|
-
return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };
|
|
578
|
-
};
|
|
579
|
-
var verifyAitRequest = (req, opts) => verifyFromContext(buildVerifyContextFromRequest(req), opts);
|
|
580
602
|
var aipErrorCode = (failure) => {
|
|
581
603
|
switch (failure) {
|
|
582
604
|
case "no_token":
|
|
@@ -633,15 +655,78 @@ var aipErrorDetail = (failure) => {
|
|
|
633
655
|
return "Token verification failed.";
|
|
634
656
|
}
|
|
635
657
|
};
|
|
636
|
-
var buildAipErrorBody = (failure) => {
|
|
658
|
+
var buildAipErrorBody = (failure, requirements) => {
|
|
637
659
|
const code = aipErrorCode(failure);
|
|
638
|
-
|
|
660
|
+
const body = {
|
|
639
661
|
type: `urn:aip:error:${code}`,
|
|
640
662
|
title: code.replace(/_/g, " "),
|
|
641
663
|
status: aipErrorStatus(failure),
|
|
642
664
|
detail: aipErrorDetail(failure)
|
|
643
665
|
};
|
|
666
|
+
if (requirements) {
|
|
667
|
+
if (code === "untrusted_issuer" && requirements.trustedIssuers?.length) {
|
|
668
|
+
body.trusted_issuers = requirements.trustedIssuers;
|
|
669
|
+
}
|
|
670
|
+
if (code === "insufficient_claims") {
|
|
671
|
+
if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;
|
|
672
|
+
if (requirements.requiredTrustLevel !== void 0) body.required_trust_level = requirements.requiredTrustLevel;
|
|
673
|
+
if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return body;
|
|
644
677
|
};
|
|
678
|
+
var TRUST_RANK = { autonomous: 0, human_present: 1, human_confirmed: 2 };
|
|
679
|
+
var checkTrustRequirements = (payload, requiredTrustLevel, requiredAmr) => {
|
|
680
|
+
if (requiredTrustLevel !== void 0) {
|
|
681
|
+
const have = TRUST_RANK[payload.trust_level ?? "autonomous"] ?? 0;
|
|
682
|
+
const need = TRUST_RANK[requiredTrustLevel] ?? 0;
|
|
683
|
+
if (have < need) {
|
|
684
|
+
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).`;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (requiredAmr !== void 0 && requiredAmr.length > 0) {
|
|
688
|
+
const amr = Array.isArray(payload.auth?.amr) ? payload.auth.amr : [];
|
|
689
|
+
if (!amr.some((m) => requiredAmr.includes(m))) {
|
|
690
|
+
return `This endpoint requires an authentication method in [${requiredAmr.join(", ")}]; the token carries [${amr.join(", ") || "none"}].`;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
};
|
|
695
|
+
var buildAipWeakAuthBody = (opts) => ({
|
|
696
|
+
type: "urn:aip:error:weak_auth",
|
|
697
|
+
title: "weak auth",
|
|
698
|
+
status: 403,
|
|
699
|
+
detail: opts.detail,
|
|
700
|
+
...opts.requiredTrustLevel !== void 0 && { required_trust_level: opts.requiredTrustLevel },
|
|
701
|
+
...opts.requiredAmr !== void 0 && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr },
|
|
702
|
+
...opts.trustedIssuers !== void 0 && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }
|
|
703
|
+
});
|
|
704
|
+
var requirementsFromOptions = (opts) => ({
|
|
705
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers },
|
|
706
|
+
...opts.requiredClaims !== void 0 && { requiredClaims: opts.requiredClaims },
|
|
707
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
708
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr }
|
|
709
|
+
});
|
|
710
|
+
var evaluateFromContext = async (ctx, opts) => {
|
|
711
|
+
const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
|
|
712
|
+
if (!result.ok) {
|
|
713
|
+
return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };
|
|
714
|
+
}
|
|
715
|
+
const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);
|
|
716
|
+
if (weak !== null) {
|
|
717
|
+
return {
|
|
718
|
+
ok: false,
|
|
719
|
+
body: buildAipWeakAuthBody({
|
|
720
|
+
detail: weak,
|
|
721
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
722
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr },
|
|
723
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers }
|
|
724
|
+
})
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
return { ok: true, ait: result.ait };
|
|
728
|
+
};
|
|
729
|
+
var evaluateAipRequest = (req, opts) => evaluateFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);
|
|
645
730
|
|
|
646
731
|
// src/core.ts
|
|
647
732
|
import { createHash } from "crypto";
|
|
@@ -720,7 +805,7 @@ function stripTrailingSlashes(s) {
|
|
|
720
805
|
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
721
806
|
return end === s.length ? s : s.slice(0, end);
|
|
722
807
|
}
|
|
723
|
-
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.
|
|
808
|
+
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.com";
|
|
724
809
|
var WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({
|
|
725
810
|
action: "resign_or_switch_to_operator_token",
|
|
726
811
|
steps: [
|
|
@@ -752,7 +837,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
|
752
837
|
return {
|
|
753
838
|
save_for_future_agentscore_gates: true,
|
|
754
839
|
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.",
|
|
755
|
-
quickstart: "https://docs.agentscore.
|
|
840
|
+
quickstart: "https://docs.agentscore.com/guides/agent-identity",
|
|
756
841
|
identity_check_endpoint: `${api}/v1/credentials`,
|
|
757
842
|
identity_paths: {
|
|
758
843
|
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.",
|
|
@@ -769,7 +854,7 @@ function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
|
769
854
|
}
|
|
770
855
|
function createAgentScoreCore(options) {
|
|
771
856
|
if (!options.apiKey) {
|
|
772
|
-
throw new Error("AgentScore API key is required. Get one at https://agentscore.
|
|
857
|
+
throw new Error("AgentScore API key is required. Get one at https://www.agentscore.com/sign-up");
|
|
773
858
|
}
|
|
774
859
|
const {
|
|
775
860
|
apiKey,
|
|
@@ -780,7 +865,7 @@ function createAgentScoreCore(options) {
|
|
|
780
865
|
allowedJurisdictions,
|
|
781
866
|
failOpen = false,
|
|
782
867
|
cacheSeconds = 300,
|
|
783
|
-
baseUrl: rawBaseUrl = "https://api.agentscore.
|
|
868
|
+
baseUrl: rawBaseUrl = "https://api.agentscore.com",
|
|
784
869
|
chain: gateChain,
|
|
785
870
|
userAgent,
|
|
786
871
|
createSessionOnMissing,
|
|
@@ -788,7 +873,7 @@ function createAgentScoreCore(options) {
|
|
|
788
873
|
} = options;
|
|
789
874
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
790
875
|
const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
|
|
791
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
876
|
+
const defaultUa = `@agent-score/commerce@${"2.6.1"}`;
|
|
792
877
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
793
878
|
const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
794
879
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -806,7 +891,6 @@ function createAgentScoreCore(options) {
|
|
|
806
891
|
return s;
|
|
807
892
|
}
|
|
808
893
|
const cache = new TTLCache(cacheSeconds * 1e3);
|
|
809
|
-
const lastSignerRaw = /* @__PURE__ */ new Map();
|
|
810
894
|
async function tryMintSessionDenial(ctx) {
|
|
811
895
|
if (!createSessionOnMissing) return void 0;
|
|
812
896
|
try {
|
|
@@ -878,7 +962,7 @@ function createAgentScoreCore(options) {
|
|
|
878
962
|
...aipStep,
|
|
879
963
|
"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.",
|
|
880
964
|
"If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
|
|
881
|
-
"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.
|
|
965
|
+
"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."
|
|
882
966
|
],
|
|
883
967
|
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."
|
|
884
968
|
});
|
|
@@ -891,21 +975,26 @@ function createAgentScoreCore(options) {
|
|
|
891
975
|
}
|
|
892
976
|
};
|
|
893
977
|
}
|
|
894
|
-
const
|
|
978
|
+
const identityKey = identity.aipToken ? `aip:${createHash("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
|
|
979
|
+
const cacheKey = signer ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)]) : JSON.stringify([identityKey]);
|
|
895
980
|
const cached = cache.get(cacheKey);
|
|
896
981
|
if (cached) {
|
|
982
|
+
const cachedVerdict = cached.raw ? buildSignerVerdict(identity, cached.raw) : void 0;
|
|
897
983
|
if (cached.allow) {
|
|
898
984
|
const cachedRaw = cached.raw;
|
|
899
985
|
const cachedQuota = cachedRaw?.quota;
|
|
900
986
|
return {
|
|
901
987
|
kind: "allow",
|
|
902
988
|
data: cachedRaw,
|
|
903
|
-
...cachedQuota !== void 0 && { quota: cachedQuota }
|
|
989
|
+
...cachedQuota !== void 0 && { quota: cachedQuota },
|
|
990
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
904
991
|
};
|
|
905
992
|
}
|
|
906
993
|
if (isFixableDenial(cached.reasons)) {
|
|
907
994
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
908
|
-
if (sessionReason)
|
|
995
|
+
if (sessionReason) {
|
|
996
|
+
return { kind: "deny", reason: sessionReason, ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict } };
|
|
997
|
+
}
|
|
909
998
|
}
|
|
910
999
|
return {
|
|
911
1000
|
kind: "deny",
|
|
@@ -915,7 +1004,8 @@ function createAgentScoreCore(options) {
|
|
|
915
1004
|
reasons: cached.reasons,
|
|
916
1005
|
verify_url: cached.raw?.verify_url,
|
|
917
1006
|
data: cached.raw
|
|
918
|
-
}
|
|
1007
|
+
},
|
|
1008
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
919
1009
|
};
|
|
920
1010
|
}
|
|
921
1011
|
const policy = {};
|
|
@@ -936,7 +1026,10 @@ function createAgentScoreCore(options) {
|
|
|
936
1026
|
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
937
1027
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
938
1028
|
};
|
|
939
|
-
|
|
1029
|
+
if (identity.aipToken !== void 0 && identity.aipSignature === void 0) {
|
|
1030
|
+
throw new Error("AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).");
|
|
1031
|
+
}
|
|
1032
|
+
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 });
|
|
940
1033
|
data = result;
|
|
941
1034
|
} catch (err) {
|
|
942
1035
|
if (err instanceof PaymentRequiredError) {
|
|
@@ -1007,20 +1100,21 @@ function createAgentScoreCore(options) {
|
|
|
1007
1100
|
const decisionReasons = data.decision_reasons ?? [];
|
|
1008
1101
|
const allow = decision === "allow" || decision == null;
|
|
1009
1102
|
cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
1010
|
-
|
|
1011
|
-
lastSignerRaw.set(normalizeAddress(identity.address), data);
|
|
1012
|
-
}
|
|
1103
|
+
const signerVerdict = buildSignerVerdict(identity, data);
|
|
1013
1104
|
if (allow) {
|
|
1014
1105
|
const quota = data.quota;
|
|
1015
1106
|
return {
|
|
1016
1107
|
kind: "allow",
|
|
1017
1108
|
data,
|
|
1018
|
-
...quota !== void 0 && { quota }
|
|
1109
|
+
...quota !== void 0 && { quota },
|
|
1110
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
1019
1111
|
};
|
|
1020
1112
|
}
|
|
1021
1113
|
if (isFixableDenial(decisionReasons)) {
|
|
1022
1114
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
1023
|
-
if (sessionReason)
|
|
1115
|
+
if (sessionReason) {
|
|
1116
|
+
return { kind: "deny", reason: sessionReason, ...signerVerdict !== void 0 && { signerVerdict } };
|
|
1117
|
+
}
|
|
1024
1118
|
}
|
|
1025
1119
|
return {
|
|
1026
1120
|
kind: "deny",
|
|
@@ -1030,7 +1124,8 @@ function createAgentScoreCore(options) {
|
|
|
1030
1124
|
reasons: decisionReasons,
|
|
1031
1125
|
verify_url: data.verify_url,
|
|
1032
1126
|
data
|
|
1033
|
-
}
|
|
1127
|
+
},
|
|
1128
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
1034
1129
|
};
|
|
1035
1130
|
}
|
|
1036
1131
|
async function captureWallet(options2) {
|
|
@@ -1072,20 +1167,21 @@ function createAgentScoreCore(options) {
|
|
|
1072
1167
|
agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
|
|
1073
1168
|
};
|
|
1074
1169
|
}
|
|
1075
|
-
function
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1170
|
+
function buildSignerVerdict(identity, raw) {
|
|
1171
|
+
if (identity.address === void 0 || identity.operatorToken !== void 0 || identity.aipToken !== void 0) {
|
|
1172
|
+
return void 0;
|
|
1173
|
+
}
|
|
1079
1174
|
const rawMatch = raw.signer_match;
|
|
1080
1175
|
const rawSanctions = raw.signer_sanctions;
|
|
1081
1176
|
if (!rawMatch && !rawSanctions) return void 0;
|
|
1177
|
+
const claimedNorm = normalizeAddress(identity.address);
|
|
1082
1178
|
const signerNorm = rawMatch?.actual_signer ?? claimedNorm;
|
|
1083
1179
|
return {
|
|
1084
1180
|
signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,
|
|
1085
1181
|
signer_sanctions: rawSanctions ?? null
|
|
1086
1182
|
};
|
|
1087
1183
|
}
|
|
1088
|
-
return { evaluate, captureWallet
|
|
1184
|
+
return { evaluate, captureWallet };
|
|
1089
1185
|
}
|
|
1090
1186
|
|
|
1091
1187
|
// src/payment/payment_header.ts
|
|
@@ -1214,7 +1310,8 @@ function createAgentScoreGate(options) {
|
|
|
1214
1310
|
const outcome = await core.evaluate(identity, req, signer);
|
|
1215
1311
|
if (outcome.kind === "allow") {
|
|
1216
1312
|
const captureWallet = identity?.operatorToken ? (opts) => core.captureWallet({ operatorToken: identity.operatorToken, ...opts }) : void 0;
|
|
1217
|
-
const
|
|
1313
|
+
const signerVerdict = outcome.signerVerdict;
|
|
1314
|
+
const getSignerVerdictBound = identity?.address && !identity?.operatorToken ? () => signerVerdict : void 0;
|
|
1218
1315
|
return {
|
|
1219
1316
|
allowed: true,
|
|
1220
1317
|
data: outcome.data,
|
|
@@ -1264,11 +1361,11 @@ var defaultAipResponse = (body) => new Response(JSON.stringify(body), { status:
|
|
|
1264
1361
|
function createAipGate(options) {
|
|
1265
1362
|
const { onDenied, ...gateOpts } = options;
|
|
1266
1363
|
return async (req) => {
|
|
1267
|
-
const result = await
|
|
1364
|
+
const result = await evaluateAipRequest(req, gateOpts);
|
|
1268
1365
|
if (result.ok) {
|
|
1269
1366
|
return { allowed: true, ait: result.ait };
|
|
1270
1367
|
}
|
|
1271
|
-
const body =
|
|
1368
|
+
const body = result.body;
|
|
1272
1369
|
const response = onDenied ? await onDenied(req, body) : defaultAipResponse(body);
|
|
1273
1370
|
return { allowed: false, response };
|
|
1274
1371
|
};
|