@agent-score/commerce 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -17
- package/dist/challenge/index.d.mts +31 -3
- package/dist/challenge/index.d.ts +31 -3
- package/dist/challenge/index.js +25 -9
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +25 -9
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/{checkout-B-MIzYzW.d.ts → checkout-C4RD7M0Z.d.ts} +117 -13
- package/dist/{checkout-Bn7ZKIBD.d.mts → checkout-CzB9f_jf.d.mts} +117 -13
- package/dist/core.d.mts +40 -7
- package/dist/core.d.ts +40 -7
- package/dist/core.js +52 -27
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +52 -27
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +33 -3
- package/dist/discovery/index.d.ts +33 -3
- package/dist/discovery/index.js +50 -16
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +49 -16
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/gate-D2RP6bZg.d.ts +307 -0
- package/dist/gate-GCXy4FHI.d.mts +307 -0
- package/dist/identity/express.d.mts +28 -1
- package/dist/identity/express.d.ts +28 -1
- package/dist/identity/express.js +714 -31
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +710 -30
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +14 -2
- package/dist/identity/fastify.d.ts +14 -2
- package/dist/identity/fastify.js +727 -31
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +723 -30
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +28 -1
- package/dist/identity/hono.d.ts +28 -1
- package/dist/identity/hono.js +696 -33
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +692 -32
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +5 -0
- package/dist/identity/nextjs.d.ts +5 -0
- package/dist/identity/nextjs.js +695 -30
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +691 -29
- 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 +26 -1
- package/dist/identity/web.d.ts +26 -1
- package/dist/identity/web.js +695 -30
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +691 -29
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +165 -4
- package/dist/index.d.ts +165 -4
- package/dist/index.js +3103 -534
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3086 -545
- 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 +1614 -266
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs +1614 -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 +26 -21
package/dist/identity/nextjs.js
CHANGED
|
@@ -22,8 +22,11 @@ var nextjs_exports = {};
|
|
|
22
22
|
__export(nextjs_exports, {
|
|
23
23
|
agentscoreMiddleware: () => agentscoreMiddleware,
|
|
24
24
|
conditionalAgentscoreMiddleware: () => conditionalAgentscoreMiddleware,
|
|
25
|
+
createAipGate: () => createAipGate,
|
|
25
26
|
withAgentScoreGate: () => withAgentScoreGate,
|
|
26
|
-
|
|
27
|
+
withAipGate: () => withAipGate,
|
|
28
|
+
withConditionalAgentScoreGate: () => withConditionalAgentScoreGate,
|
|
29
|
+
withConditionalAipGate: () => withConditionalAipGate
|
|
27
30
|
});
|
|
28
31
|
module.exports = __toCommonJS(nextjs_exports);
|
|
29
32
|
|
|
@@ -97,7 +100,7 @@ var IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({
|
|
|
97
100
|
var API_ERROR_INSTRUCTIONS = JSON.stringify({
|
|
98
101
|
action: "retry_with_backoff",
|
|
99
102
|
steps: [
|
|
100
|
-
"Verification is temporarily unavailable. Retry the request after 5
|
|
103
|
+
"Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.",
|
|
101
104
|
"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.",
|
|
102
105
|
"If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant's support contact."
|
|
103
106
|
],
|
|
@@ -184,7 +187,605 @@ function denialReasonToBody(reason) {
|
|
|
184
187
|
return body;
|
|
185
188
|
}
|
|
186
189
|
|
|
190
|
+
// src/aip/verify.ts
|
|
191
|
+
var import_jose2 = require("jose");
|
|
192
|
+
|
|
193
|
+
// src/aip/http-signature.ts
|
|
194
|
+
var import_jose = require("jose");
|
|
195
|
+
var { subtle } = globalThis.crypto;
|
|
196
|
+
var b64ToBytes = (b64) => {
|
|
197
|
+
const bin = atob(b64);
|
|
198
|
+
const out = new Uint8Array(bin.length);
|
|
199
|
+
for (let i = 0; i < bin.length; i++) {
|
|
200
|
+
out[i] = bin.charCodeAt(i);
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
};
|
|
204
|
+
var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
|
|
205
|
+
var AIP_SIGNATURE_TAG = "agent-identity";
|
|
206
|
+
var DEFAULT_MAX_SKEW_SECONDS = 60;
|
|
207
|
+
var MAX_POP_WINDOW_SECONDS = 120;
|
|
208
|
+
var normalizeAuthority = (authority) => {
|
|
209
|
+
const lower = authority.trim().toLowerCase();
|
|
210
|
+
const colon = lower.lastIndexOf(":");
|
|
211
|
+
if (colon === -1) {
|
|
212
|
+
return lower;
|
|
213
|
+
}
|
|
214
|
+
if (lower.includes("]") && colon < lower.indexOf("]")) {
|
|
215
|
+
return lower;
|
|
216
|
+
}
|
|
217
|
+
const host = lower.slice(0, colon);
|
|
218
|
+
const port = lower.slice(colon + 1);
|
|
219
|
+
if (port === "80" || port === "443") {
|
|
220
|
+
return host;
|
|
221
|
+
}
|
|
222
|
+
return lower;
|
|
223
|
+
};
|
|
224
|
+
var componentValue = (name, input) => {
|
|
225
|
+
switch (name) {
|
|
226
|
+
case "@method":
|
|
227
|
+
return input.method.toUpperCase();
|
|
228
|
+
case "@authority":
|
|
229
|
+
return normalizeAuthority(input.authority);
|
|
230
|
+
case "@path":
|
|
231
|
+
return input.path;
|
|
232
|
+
case "agent-identity":
|
|
233
|
+
return input.agentIdentity.trim();
|
|
234
|
+
default:
|
|
235
|
+
return input.extra?.[name] ?? null;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
var serializeComponentList = (components) => `(${components.map((c) => `"${c}"`).join(" ")})`;
|
|
239
|
+
var serializeParams = (p) => {
|
|
240
|
+
const parts = [];
|
|
241
|
+
if (p.created !== void 0) {
|
|
242
|
+
parts.push(`created=${p.created}`);
|
|
243
|
+
}
|
|
244
|
+
if (p.expires !== void 0) {
|
|
245
|
+
parts.push(`expires=${p.expires}`);
|
|
246
|
+
}
|
|
247
|
+
if (p.keyid !== void 0) {
|
|
248
|
+
parts.push(`keyid="${p.keyid}"`);
|
|
249
|
+
}
|
|
250
|
+
if (p.alg !== void 0) {
|
|
251
|
+
parts.push(`alg="${p.alg}"`);
|
|
252
|
+
}
|
|
253
|
+
if (p.tag !== void 0) {
|
|
254
|
+
parts.push(`tag="${p.tag}"`);
|
|
255
|
+
}
|
|
256
|
+
return parts.map((s) => `;${s}`).join("");
|
|
257
|
+
};
|
|
258
|
+
var buildSignatureBase = (params, input, rawSignatureParams) => {
|
|
259
|
+
const lines = [];
|
|
260
|
+
for (const name of params.components) {
|
|
261
|
+
const value = componentValue(name, input);
|
|
262
|
+
if (value === null) {
|
|
263
|
+
throw new MissingComponentError(name);
|
|
264
|
+
}
|
|
265
|
+
lines.push(`"${name}": ${value}`);
|
|
266
|
+
}
|
|
267
|
+
const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);
|
|
268
|
+
lines.push(`"@signature-params": ${paramsValue}`);
|
|
269
|
+
return lines.join("\n");
|
|
270
|
+
};
|
|
271
|
+
var MissingComponentError = class extends Error {
|
|
272
|
+
constructor(component) {
|
|
273
|
+
super(`signature base missing covered component: ${component}`);
|
|
274
|
+
this.component = component;
|
|
275
|
+
this.name = "MissingComponentError";
|
|
276
|
+
}
|
|
277
|
+
component;
|
|
278
|
+
};
|
|
279
|
+
var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
|
|
280
|
+
const members = splitDictionary(header);
|
|
281
|
+
if (members.length === 0) {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
const parsed = members.map((m) => {
|
|
285
|
+
const params = parseInnerListMember(m.value);
|
|
286
|
+
return params ? { label: m.label, params, rawParams: m.value } : null;
|
|
287
|
+
}).filter((x) => x !== null);
|
|
288
|
+
if (parsed.length === 0) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
return parsed.find((p) => p.params.tag === tag) ?? null;
|
|
292
|
+
};
|
|
293
|
+
var parseSignatureValue = (header, label) => {
|
|
294
|
+
const members = splitDictionary(header);
|
|
295
|
+
const member = members.find((m) => m.label === label);
|
|
296
|
+
if (!member) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
const v = member.value.trim();
|
|
300
|
+
if (!v.startsWith(":") || !v.endsWith(":") || v.length < 2) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
const b64 = v.slice(1, -1);
|
|
304
|
+
try {
|
|
305
|
+
return b64ToBytes(b64);
|
|
306
|
+
} catch {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
var splitDictionary = (header) => {
|
|
311
|
+
const out = [];
|
|
312
|
+
let depth = 0;
|
|
313
|
+
let inBytes = false;
|
|
314
|
+
let inString = false;
|
|
315
|
+
let current = "";
|
|
316
|
+
for (let i = 0; i < header.length; i++) {
|
|
317
|
+
const ch = header[i];
|
|
318
|
+
if (inString) {
|
|
319
|
+
current += ch;
|
|
320
|
+
if (ch === '"' && header[i - 1] !== "\\") {
|
|
321
|
+
inString = false;
|
|
322
|
+
}
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (ch === '"') {
|
|
326
|
+
inString = true;
|
|
327
|
+
current += ch;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (ch === ":") {
|
|
331
|
+
inBytes = !inBytes;
|
|
332
|
+
current += ch;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (!inBytes && ch === "(") {
|
|
336
|
+
depth++;
|
|
337
|
+
current += ch;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (!inBytes && ch === ")") {
|
|
341
|
+
depth = Math.max(0, depth - 1);
|
|
342
|
+
current += ch;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (!inBytes && depth === 0 && ch === ",") {
|
|
346
|
+
pushMember(out, current);
|
|
347
|
+
current = "";
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
current += ch;
|
|
351
|
+
}
|
|
352
|
+
pushMember(out, current);
|
|
353
|
+
return out;
|
|
354
|
+
};
|
|
355
|
+
var pushMember = (out, raw) => {
|
|
356
|
+
const trimmed = raw.trim();
|
|
357
|
+
if (!trimmed) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const eq = trimmed.indexOf("=");
|
|
361
|
+
if (eq === -1) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const label = trimmed.slice(0, eq).trim();
|
|
365
|
+
const value = trimmed.slice(eq + 1).trim();
|
|
366
|
+
if (label) {
|
|
367
|
+
out.push({ label, value });
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
var parseInnerListMember = (value) => {
|
|
371
|
+
const open = value.indexOf("(");
|
|
372
|
+
const close = value.indexOf(")", open + 1);
|
|
373
|
+
if (open === -1 || close === -1) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
const listBody = value.slice(open + 1, close).trim();
|
|
377
|
+
const components = listBody.length === 0 ? [] : (listBody.match(/"[^"]*"/g) ?? []).map((s) => s.slice(1, -1));
|
|
378
|
+
const params = { components };
|
|
379
|
+
const paramStr = value.slice(close + 1);
|
|
380
|
+
const re = /;\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|-?\d+)/g;
|
|
381
|
+
let match;
|
|
382
|
+
while ((match = re.exec(paramStr)) !== null) {
|
|
383
|
+
const key = match[1];
|
|
384
|
+
const raw = match[2];
|
|
385
|
+
const val = raw.startsWith('"') ? raw.slice(1, -1) : Number(raw);
|
|
386
|
+
if (key === "created") {
|
|
387
|
+
params.created = val;
|
|
388
|
+
} else if (key === "expires") {
|
|
389
|
+
params.expires = val;
|
|
390
|
+
} else if (key === "keyid") {
|
|
391
|
+
params.keyid = val;
|
|
392
|
+
} else if (key === "tag") {
|
|
393
|
+
params.tag = val;
|
|
394
|
+
} else if (key === "alg") {
|
|
395
|
+
params.alg = val;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return params;
|
|
399
|
+
};
|
|
400
|
+
var verifyMessageSignature = async (input) => {
|
|
401
|
+
const selected = parseSignatureInput(input.signatureInput);
|
|
402
|
+
if (!selected) {
|
|
403
|
+
return { ok: false, reason: "no_aip_signature" };
|
|
404
|
+
}
|
|
405
|
+
const { label, params, rawParams } = selected;
|
|
406
|
+
if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
|
|
407
|
+
return { ok: false, reason: "unsupported_alg" };
|
|
408
|
+
}
|
|
409
|
+
for (const required of AIP_COVERED_COMPONENTS) {
|
|
410
|
+
if (!params.components.includes(required)) {
|
|
411
|
+
return { ok: false, reason: "missing_covered_component" };
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (params.created === void 0) {
|
|
415
|
+
return { ok: false, reason: "created_missing" };
|
|
416
|
+
}
|
|
417
|
+
if (params.expires === void 0) {
|
|
418
|
+
return { ok: false, reason: "expires_missing" };
|
|
419
|
+
}
|
|
420
|
+
if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {
|
|
421
|
+
return { ok: false, reason: "pop_window_too_long" };
|
|
422
|
+
}
|
|
423
|
+
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
424
|
+
const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
|
|
425
|
+
if (params.created > now + skew) {
|
|
426
|
+
return { ok: false, reason: "created_in_future" };
|
|
427
|
+
}
|
|
428
|
+
if (params.expires < now - skew) {
|
|
429
|
+
return { ok: false, reason: "expired" };
|
|
430
|
+
}
|
|
431
|
+
if (!params.keyid) {
|
|
432
|
+
return { ok: false, reason: "missing_keyid" };
|
|
433
|
+
}
|
|
434
|
+
const cnf = input.cnfJwk;
|
|
435
|
+
if (cnf.kty !== "OKP" || cnf.crv !== "Ed25519" || typeof cnf.x !== "string" || cnf.x.length === 0) {
|
|
436
|
+
return { ok: false, reason: "unsupported_cnf_key" };
|
|
437
|
+
}
|
|
438
|
+
let thumbprint;
|
|
439
|
+
try {
|
|
440
|
+
thumbprint = await (0, import_jose.calculateJwkThumbprint)(input.cnfJwk, "sha256");
|
|
441
|
+
} catch {
|
|
442
|
+
return { ok: false, reason: "unsupported_cnf_key" };
|
|
443
|
+
}
|
|
444
|
+
if (params.keyid !== thumbprint) {
|
|
445
|
+
return { ok: false, reason: "keyid_mismatch" };
|
|
446
|
+
}
|
|
447
|
+
const sig = parseSignatureValue(input.signature, label);
|
|
448
|
+
if (!sig) {
|
|
449
|
+
return { ok: false, reason: "malformed_signature" };
|
|
450
|
+
}
|
|
451
|
+
let base;
|
|
452
|
+
try {
|
|
453
|
+
base = buildSignatureBase(params, {
|
|
454
|
+
method: input.method,
|
|
455
|
+
authority: input.authority,
|
|
456
|
+
path: input.path,
|
|
457
|
+
agentIdentity: input.agentIdentity,
|
|
458
|
+
extra: input.extraComponents
|
|
459
|
+
}, rawParams);
|
|
460
|
+
} catch (err) {
|
|
461
|
+
if (err instanceof MissingComponentError) {
|
|
462
|
+
return { ok: false, reason: "missing_covered_component" };
|
|
463
|
+
}
|
|
464
|
+
throw err;
|
|
465
|
+
}
|
|
466
|
+
let valid;
|
|
467
|
+
try {
|
|
468
|
+
const key = await (0, import_jose.importJWK)(input.cnfJwk, "EdDSA");
|
|
469
|
+
if (!(key instanceof CryptoKey)) {
|
|
470
|
+
return { ok: false, reason: "signature_invalid" };
|
|
471
|
+
}
|
|
472
|
+
valid = await subtle.verify(
|
|
473
|
+
{ name: "Ed25519" },
|
|
474
|
+
key,
|
|
475
|
+
sig,
|
|
476
|
+
new TextEncoder().encode(base)
|
|
477
|
+
);
|
|
478
|
+
} catch {
|
|
479
|
+
return { ok: false, reason: "signature_invalid" };
|
|
480
|
+
}
|
|
481
|
+
return valid ? { ok: true, params } : { ok: false, reason: "signature_invalid" };
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
// src/aip/types.ts
|
|
485
|
+
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
486
|
+
var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
|
|
487
|
+
var isAitShape = (payload) => isObject(payload) && isObject(payload.cnf) && isObject(payload.agent);
|
|
488
|
+
var validateAitPayload = (payload) => {
|
|
489
|
+
if (!isObject(payload)) {
|
|
490
|
+
return { ok: false, reason: "not_an_object" };
|
|
491
|
+
}
|
|
492
|
+
if (!isNonEmptyString(payload.aip_version)) {
|
|
493
|
+
return { ok: false, reason: "missing_aip_version" };
|
|
494
|
+
}
|
|
495
|
+
if (!isNonEmptyString(payload.iss)) {
|
|
496
|
+
return { ok: false, reason: "missing_iss" };
|
|
497
|
+
}
|
|
498
|
+
if (!isNonEmptyString(payload.sub)) {
|
|
499
|
+
return { ok: false, reason: "missing_sub" };
|
|
500
|
+
}
|
|
501
|
+
if (typeof payload.iat !== "number") {
|
|
502
|
+
return { ok: false, reason: "missing_iat" };
|
|
503
|
+
}
|
|
504
|
+
if (typeof payload.exp !== "number") {
|
|
505
|
+
return { ok: false, reason: "missing_exp" };
|
|
506
|
+
}
|
|
507
|
+
if (!isObject(payload.cnf) || !isObject(payload.cnf.jwk)) {
|
|
508
|
+
return { ok: false, reason: "missing_cnf" };
|
|
509
|
+
}
|
|
510
|
+
if (!isObject(payload.agent) || !isNonEmptyString(payload.agent.provider)) {
|
|
511
|
+
return { ok: false, reason: "missing_agent_provider" };
|
|
512
|
+
}
|
|
513
|
+
if (payload.trust_level === "human_confirmed") {
|
|
514
|
+
const auth = payload.auth;
|
|
515
|
+
const amr = isObject(auth) ? auth.amr : void 0;
|
|
516
|
+
if (!Array.isArray(amr) || amr.length === 0) {
|
|
517
|
+
return { ok: false, reason: "human_confirmed_without_amr" };
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return { ok: true, payload };
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// src/aip/verify.ts
|
|
524
|
+
var AGENT_IDENTITY_HEADER = "agent-identity";
|
|
525
|
+
var verifyAit = async (ctx, opts) => {
|
|
526
|
+
if (ctx.agentIdentityHeaders.length === 0) {
|
|
527
|
+
return { ok: false, reason: "no_token" };
|
|
528
|
+
}
|
|
529
|
+
if (!ctx.signatureInput || !ctx.signature) {
|
|
530
|
+
return { ok: false, reason: "pop_signature_missing" };
|
|
531
|
+
}
|
|
532
|
+
const signatureInput = ctx.signatureInput;
|
|
533
|
+
const signature = ctx.signature;
|
|
534
|
+
let lastFailure = "malformed_token";
|
|
535
|
+
for (const raw of ctx.agentIdentityHeaders) {
|
|
536
|
+
const token = stripBearer(raw);
|
|
537
|
+
let header;
|
|
538
|
+
let payload;
|
|
539
|
+
try {
|
|
540
|
+
header = (0, import_jose2.decodeProtectedHeader)(token);
|
|
541
|
+
payload = (0, import_jose2.decodeJwt)(token);
|
|
542
|
+
} catch {
|
|
543
|
+
lastFailure = "malformed_token";
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (header.alg === void 0 || header.alg.toLowerCase() === "none") {
|
|
547
|
+
lastFailure = "malformed_token";
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (!isAitShape(payload)) {
|
|
551
|
+
lastFailure = "malformed_token";
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
const validated = validateAitPayload(payload);
|
|
555
|
+
if (!validated.ok) {
|
|
556
|
+
lastFailure = "invalid_claims";
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
const claims = validated.payload;
|
|
560
|
+
const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);
|
|
561
|
+
if (!keyLookup.ok) {
|
|
562
|
+
lastFailure = keyLookup.reason === "untrusted_issuer" || keyLookup.reason === "insecure_issuer" ? "untrusted_issuer" : "key_unavailable";
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
const jwtClockTolerance = opts.maxSkewSeconds ?? 60;
|
|
566
|
+
try {
|
|
567
|
+
const idpKey = await (0, import_jose2.importJWK)(keyLookup.key, normalizeAlg(header.alg));
|
|
568
|
+
await (0, import_jose2.jwtVerify)(token, idpKey, {
|
|
569
|
+
// Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
|
|
570
|
+
// this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
|
|
571
|
+
// non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256
|
|
572
|
+
// token that verifies. Matches the server-side allowlist in the AgentScore API verifier.
|
|
573
|
+
algorithms: AIT_SIGNING_ALGS,
|
|
574
|
+
clockTolerance: jwtClockTolerance,
|
|
575
|
+
currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
|
|
576
|
+
});
|
|
577
|
+
} catch (err) {
|
|
578
|
+
lastFailure = isExpiry(err) ? "expired_token" : "idp_signature_invalid";
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const nowSec = opts.now ?? Math.floor(Date.now() / 1e3);
|
|
582
|
+
if (claims.iat > nowSec + jwtClockTolerance) {
|
|
583
|
+
lastFailure = "expired_token";
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {
|
|
587
|
+
lastFailure = "expired_token";
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
const popResult = await verifyMessageSignature({
|
|
591
|
+
method: ctx.method,
|
|
592
|
+
authority: ctx.authority,
|
|
593
|
+
path: ctx.path,
|
|
594
|
+
// The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is
|
|
595
|
+
// transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and
|
|
596
|
+
// the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.
|
|
597
|
+
agentIdentity: token,
|
|
598
|
+
signatureInput,
|
|
599
|
+
signature,
|
|
600
|
+
cnfJwk: claims.cnf.jwk,
|
|
601
|
+
now: opts.now,
|
|
602
|
+
maxSkewSeconds: opts.maxSkewSeconds
|
|
603
|
+
});
|
|
604
|
+
if (!popResult.ok) {
|
|
605
|
+
lastFailure = "pop_signature_invalid";
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
ok: true,
|
|
610
|
+
ait: {
|
|
611
|
+
payload: claims,
|
|
612
|
+
iss: claims.iss,
|
|
613
|
+
cnfJwk: claims.cnf.jwk,
|
|
614
|
+
token,
|
|
615
|
+
signatureMaterial: {
|
|
616
|
+
method: ctx.method,
|
|
617
|
+
authority: ctx.authority,
|
|
618
|
+
path: ctx.path,
|
|
619
|
+
signature_input: signatureInput,
|
|
620
|
+
signature
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
return { ok: false, reason: lastFailure };
|
|
626
|
+
};
|
|
627
|
+
var stripBearer = (value) => {
|
|
628
|
+
const trimmed = value.trim();
|
|
629
|
+
return /^bearer\s+/i.test(trimmed) ? trimmed.replace(/^bearer\s+/i, "") : trimmed;
|
|
630
|
+
};
|
|
631
|
+
var AIT_SIGNING_ALGS = ["EdDSA", "ES256"];
|
|
632
|
+
var normalizeAlg = (alg) => alg.toLowerCase() === "eddsa" ? "EdDSA" : alg;
|
|
633
|
+
var isExpiry = (err) => typeof err === "object" && err !== null && err.code === "ERR_JWT_EXPIRED";
|
|
634
|
+
|
|
635
|
+
// src/aip/request.ts
|
|
636
|
+
var readAgentIdentityHeaders = (headers) => {
|
|
637
|
+
const raw = headers.get(AGENT_IDENTITY_HEADER);
|
|
638
|
+
if (!raw) {
|
|
639
|
+
return [];
|
|
640
|
+
}
|
|
641
|
+
return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
642
|
+
};
|
|
643
|
+
var deriveAuthority = (req, url) => req.headers.get("host") ?? url.host;
|
|
644
|
+
var buildVerifyContextFromRequest = (req, authority) => {
|
|
645
|
+
const url = new URL(req.url);
|
|
646
|
+
return {
|
|
647
|
+
method: req.method,
|
|
648
|
+
authority: authority ?? deriveAuthority(req, url),
|
|
649
|
+
path: url.pathname,
|
|
650
|
+
agentIdentityHeaders: readAgentIdentityHeaders(req.headers),
|
|
651
|
+
signatureInput: req.headers.get("signature-input"),
|
|
652
|
+
signature: req.headers.get("signature")
|
|
653
|
+
};
|
|
654
|
+
};
|
|
655
|
+
var hasAgentIdentityHeader = (req) => readAgentIdentityHeaders(req.headers).length > 0;
|
|
656
|
+
|
|
657
|
+
// src/aip/gate.ts
|
|
658
|
+
var aipErrorCode = (failure) => {
|
|
659
|
+
switch (failure) {
|
|
660
|
+
case "no_token":
|
|
661
|
+
case "pop_signature_missing":
|
|
662
|
+
return "agent_identity_required";
|
|
663
|
+
case "untrusted_issuer":
|
|
664
|
+
return "untrusted_issuer";
|
|
665
|
+
case "expired_token":
|
|
666
|
+
return "expired_token";
|
|
667
|
+
case "invalid_claims":
|
|
668
|
+
return "insufficient_claims";
|
|
669
|
+
case "key_unavailable":
|
|
670
|
+
return "idp_unavailable";
|
|
671
|
+
case "malformed_token":
|
|
672
|
+
case "idp_signature_invalid":
|
|
673
|
+
case "pop_signature_invalid":
|
|
674
|
+
return "invalid_signature";
|
|
675
|
+
default:
|
|
676
|
+
return "invalid_signature";
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
var aipErrorStatus = (failure) => {
|
|
680
|
+
switch (failure) {
|
|
681
|
+
case "key_unavailable":
|
|
682
|
+
return 503;
|
|
683
|
+
case "untrusted_issuer":
|
|
684
|
+
case "invalid_claims":
|
|
685
|
+
return 403;
|
|
686
|
+
default:
|
|
687
|
+
return 401;
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
var aipErrorDetail = (failure) => {
|
|
691
|
+
switch (failure) {
|
|
692
|
+
case "no_token":
|
|
693
|
+
return "No Agent-Identity token was presented.";
|
|
694
|
+
case "pop_signature_missing":
|
|
695
|
+
return "The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.";
|
|
696
|
+
case "untrusted_issuer":
|
|
697
|
+
return "The token's issuer is not in this service's trusted-issuer list.";
|
|
698
|
+
case "expired_token":
|
|
699
|
+
return "The Agent Identity Token has expired.";
|
|
700
|
+
case "invalid_claims":
|
|
701
|
+
return "The token is missing required claims for this endpoint.";
|
|
702
|
+
case "malformed_token":
|
|
703
|
+
return "The Agent-Identity header could not be parsed as an Agent Identity Token.";
|
|
704
|
+
case "idp_signature_invalid":
|
|
705
|
+
return "The identity provider's signature on the token failed verification.";
|
|
706
|
+
case "pop_signature_invalid":
|
|
707
|
+
return "The request signature did not match the key bound to the token.";
|
|
708
|
+
case "key_unavailable":
|
|
709
|
+
return "The identity provider's signing key could not be resolved.";
|
|
710
|
+
default:
|
|
711
|
+
return "Token verification failed.";
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
var buildAipErrorBody = (failure, requirements) => {
|
|
715
|
+
const code = aipErrorCode(failure);
|
|
716
|
+
const body = {
|
|
717
|
+
type: `urn:aip:error:${code}`,
|
|
718
|
+
title: code.replace(/_/g, " "),
|
|
719
|
+
status: aipErrorStatus(failure),
|
|
720
|
+
detail: aipErrorDetail(failure)
|
|
721
|
+
};
|
|
722
|
+
if (requirements) {
|
|
723
|
+
if (code === "untrusted_issuer" && requirements.trustedIssuers?.length) {
|
|
724
|
+
body.trusted_issuers = requirements.trustedIssuers;
|
|
725
|
+
}
|
|
726
|
+
if (code === "insufficient_claims") {
|
|
727
|
+
if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;
|
|
728
|
+
if (requirements.requiredTrustLevel !== void 0) body.required_trust_level = requirements.requiredTrustLevel;
|
|
729
|
+
if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return body;
|
|
733
|
+
};
|
|
734
|
+
var TRUST_RANK = { autonomous: 0, human_present: 1, human_confirmed: 2 };
|
|
735
|
+
var checkTrustRequirements = (payload, requiredTrustLevel, requiredAmr) => {
|
|
736
|
+
if (requiredTrustLevel !== void 0) {
|
|
737
|
+
const have = TRUST_RANK[payload.trust_level ?? "autonomous"] ?? 0;
|
|
738
|
+
const need = TRUST_RANK[requiredTrustLevel] ?? 0;
|
|
739
|
+
if (have < need) {
|
|
740
|
+
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).`;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (requiredAmr !== void 0 && requiredAmr.length > 0) {
|
|
744
|
+
const amr = Array.isArray(payload.auth?.amr) ? payload.auth.amr : [];
|
|
745
|
+
if (!amr.some((m) => requiredAmr.includes(m))) {
|
|
746
|
+
return `This endpoint requires an authentication method in [${requiredAmr.join(", ")}]; the token carries [${amr.join(", ") || "none"}].`;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return null;
|
|
750
|
+
};
|
|
751
|
+
var buildAipWeakAuthBody = (opts) => ({
|
|
752
|
+
type: "urn:aip:error:weak_auth",
|
|
753
|
+
title: "weak auth",
|
|
754
|
+
status: 403,
|
|
755
|
+
detail: opts.detail,
|
|
756
|
+
...opts.requiredTrustLevel !== void 0 && { required_trust_level: opts.requiredTrustLevel },
|
|
757
|
+
...opts.requiredAmr !== void 0 && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr },
|
|
758
|
+
...opts.trustedIssuers !== void 0 && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }
|
|
759
|
+
});
|
|
760
|
+
var requirementsFromOptions = (opts) => ({
|
|
761
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers },
|
|
762
|
+
...opts.requiredClaims !== void 0 && { requiredClaims: opts.requiredClaims },
|
|
763
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
764
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr }
|
|
765
|
+
});
|
|
766
|
+
var evaluateFromContext = async (ctx, opts) => {
|
|
767
|
+
const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
|
|
768
|
+
if (!result.ok) {
|
|
769
|
+
return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };
|
|
770
|
+
}
|
|
771
|
+
const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);
|
|
772
|
+
if (weak !== null) {
|
|
773
|
+
return {
|
|
774
|
+
ok: false,
|
|
775
|
+
body: buildAipWeakAuthBody({
|
|
776
|
+
detail: weak,
|
|
777
|
+
...opts.requireTrustLevel !== void 0 && { requiredTrustLevel: opts.requireTrustLevel },
|
|
778
|
+
...opts.requireAmr !== void 0 && { requiredAmr: opts.requireAmr },
|
|
779
|
+
...opts.trustedIssuers !== void 0 && { trustedIssuers: opts.trustedIssuers }
|
|
780
|
+
})
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
return { ok: true, ait: result.ait };
|
|
784
|
+
};
|
|
785
|
+
var evaluateAipRequest = (req, opts) => evaluateFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);
|
|
786
|
+
|
|
187
787
|
// src/core.ts
|
|
788
|
+
var import_node_crypto = require("crypto");
|
|
188
789
|
var import_sdk = require("@agent-score/sdk");
|
|
189
790
|
|
|
190
791
|
// src/address.ts
|
|
@@ -253,7 +854,7 @@ function stripTrailingSlashes(s) {
|
|
|
253
854
|
while (end > 0 && s.charCodeAt(end - 1) === 47) end--;
|
|
254
855
|
return end === s.length ? s : s.slice(0, end);
|
|
255
856
|
}
|
|
256
|
-
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.
|
|
857
|
+
var CANONICAL_AGENTSCORE_API = "https://api.agentscore.com";
|
|
257
858
|
var WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({
|
|
258
859
|
action: "resign_or_switch_to_operator_token",
|
|
259
860
|
steps: [
|
|
@@ -279,17 +880,22 @@ var INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({
|
|
|
279
880
|
],
|
|
280
881
|
user_message: "The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one."
|
|
281
882
|
});
|
|
282
|
-
function buildAgentMemoryHint() {
|
|
883
|
+
function buildAgentMemoryHint(aipTrustedIssuers) {
|
|
283
884
|
const api = CANONICAL_AGENTSCORE_API;
|
|
885
|
+
const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
|
|
284
886
|
return {
|
|
285
887
|
save_for_future_agentscore_gates: true,
|
|
286
888
|
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.",
|
|
287
|
-
quickstart: "https://docs.agentscore.
|
|
889
|
+
quickstart: "https://docs.agentscore.com/guides/agent-identity",
|
|
288
890
|
identity_check_endpoint: `${api}/v1/credentials`,
|
|
289
891
|
identity_paths: {
|
|
290
892
|
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.",
|
|
291
|
-
operator_token: "For any rail (Stripe SPT, card, or a wallet you have not linked yet), send `X-Operator-Token: opc_...`. Reusable across merchants until the token expires."
|
|
893
|
+
operator_token: "For any rail (Stripe SPT, card, or a wallet you have not linked yet), send `X-Operator-Token: opc_...`. Reusable across merchants until the token expires.",
|
|
894
|
+
...acceptsAip && {
|
|
895
|
+
agent_identity: 'If you hold an AIP Agent Identity Token from a trusted issuer (see aip_trusted_issuers), present it: send the JWT in an `Agent-Identity` header plus an RFC 9421 HTTP Message Signature (Signature-Input + Signature over @method @authority @path agent-identity, tag="agent-identity") signed with the token-bound cnf key. The merchant verifies it and applies its policy \u2014 no separate AgentScore credential needed.'
|
|
896
|
+
}
|
|
292
897
|
},
|
|
898
|
+
...acceptsAip && { aip_trusted_issuers: aipTrustedIssuers },
|
|
293
899
|
bootstrap: "If you have neither a linked wallet nor a valid operator_token, follow the session/verify flow in the per-request `agent_instructions` block. This happens at most once per agent identity \u2014 after first verification, the operator_token and any subsequently used wallet are reusable everywhere.",
|
|
294
900
|
do_not_persist_in_memory: ["operator_token", "poll_secret"],
|
|
295
901
|
persist_in_credential_store: ["operator_token"]
|
|
@@ -297,7 +903,7 @@ function buildAgentMemoryHint() {
|
|
|
297
903
|
}
|
|
298
904
|
function createAgentScoreCore(options) {
|
|
299
905
|
if (!options.apiKey) {
|
|
300
|
-
throw new Error("AgentScore API key is required. Get one at https://agentscore.
|
|
906
|
+
throw new Error("AgentScore API key is required. Get one at https://www.agentscore.com/sign-up");
|
|
301
907
|
}
|
|
302
908
|
const {
|
|
303
909
|
apiKey,
|
|
@@ -308,14 +914,15 @@ function createAgentScoreCore(options) {
|
|
|
308
914
|
allowedJurisdictions,
|
|
309
915
|
failOpen = false,
|
|
310
916
|
cacheSeconds = 300,
|
|
311
|
-
baseUrl: rawBaseUrl = "https://api.agentscore.
|
|
917
|
+
baseUrl: rawBaseUrl = "https://api.agentscore.com",
|
|
312
918
|
chain: gateChain,
|
|
313
919
|
userAgent,
|
|
314
|
-
createSessionOnMissing
|
|
920
|
+
createSessionOnMissing,
|
|
921
|
+
aipTrustedIssuers
|
|
315
922
|
} = options;
|
|
316
923
|
const baseUrl = stripTrailingSlashes(rawBaseUrl);
|
|
317
|
-
const agentMemoryHint = buildAgentMemoryHint();
|
|
318
|
-
const defaultUa = `@agent-score/commerce@${"2.
|
|
924
|
+
const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
|
|
925
|
+
const defaultUa = `@agent-score/commerce@${"2.6.0"}`;
|
|
319
926
|
const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
|
|
320
927
|
const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
|
|
321
928
|
const sessionSdkCache = /* @__PURE__ */ new Map();
|
|
@@ -390,16 +997,21 @@ function createAgentScoreCore(options) {
|
|
|
390
997
|
}
|
|
391
998
|
}
|
|
392
999
|
async function evaluate(identity, ctx, signer) {
|
|
393
|
-
if (!identity || !identity.address && !identity.operatorToken) {
|
|
1000
|
+
if (!identity || !identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim()) {
|
|
394
1001
|
if (failOpen) return { kind: "allow" };
|
|
395
1002
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
396
1003
|
if (sessionReason) return { kind: "deny", reason: sessionReason };
|
|
1004
|
+
const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
|
|
1005
|
+
const aipStep = acceptsAip ? [
|
|
1006
|
+
`If you hold an AIP Agent Identity Token from a trusted issuer (${aipTrustedIssuers.join(", ")}): present it \u2014 send the JWT in an Agent-Identity header plus an RFC 9421 HTTP Message Signature (Signature-Input + Signature over @method @authority @path agent-identity, tag="agent-identity") signed with the token-bound cnf key. This satisfies identity in one round trip without an AgentScore credential.`
|
|
1007
|
+
] : [];
|
|
397
1008
|
const missingIdentityInstructions = JSON.stringify({
|
|
398
1009
|
action: "probe_identity_then_session",
|
|
399
1010
|
steps: [
|
|
1011
|
+
...aipStep,
|
|
400
1012
|
"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.",
|
|
401
1013
|
"If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
|
|
402
|
-
"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.
|
|
1014
|
+
"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."
|
|
403
1015
|
],
|
|
404
1016
|
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."
|
|
405
1017
|
});
|
|
@@ -412,21 +1024,26 @@ function createAgentScoreCore(options) {
|
|
|
412
1024
|
}
|
|
413
1025
|
};
|
|
414
1026
|
}
|
|
415
|
-
const
|
|
1027
|
+
const identityKey = identity.aipToken ? `aip:${(0, import_node_crypto.createHash)("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
|
|
1028
|
+
const cacheKey = signer ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)]) : JSON.stringify([identityKey]);
|
|
416
1029
|
const cached = cache.get(cacheKey);
|
|
417
1030
|
if (cached) {
|
|
1031
|
+
const cachedVerdict = cached.raw ? buildSignerVerdict(identity, cached.raw) : void 0;
|
|
418
1032
|
if (cached.allow) {
|
|
419
1033
|
const cachedRaw = cached.raw;
|
|
420
1034
|
const cachedQuota = cachedRaw?.quota;
|
|
421
1035
|
return {
|
|
422
1036
|
kind: "allow",
|
|
423
1037
|
data: cachedRaw,
|
|
424
|
-
...cachedQuota !== void 0 && { quota: cachedQuota }
|
|
1038
|
+
...cachedQuota !== void 0 && { quota: cachedQuota },
|
|
1039
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
425
1040
|
};
|
|
426
1041
|
}
|
|
427
1042
|
if (isFixableDenial(cached.reasons)) {
|
|
428
1043
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
429
|
-
if (sessionReason)
|
|
1044
|
+
if (sessionReason) {
|
|
1045
|
+
return { kind: "deny", reason: sessionReason, ...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict } };
|
|
1046
|
+
}
|
|
430
1047
|
}
|
|
431
1048
|
return {
|
|
432
1049
|
kind: "deny",
|
|
@@ -436,7 +1053,8 @@ function createAgentScoreCore(options) {
|
|
|
436
1053
|
reasons: cached.reasons,
|
|
437
1054
|
verify_url: cached.raw?.verify_url,
|
|
438
1055
|
data: cached.raw
|
|
439
|
-
}
|
|
1056
|
+
},
|
|
1057
|
+
...cachedVerdict !== void 0 && { signerVerdict: cachedVerdict }
|
|
440
1058
|
};
|
|
441
1059
|
}
|
|
442
1060
|
const policy = {};
|
|
@@ -457,7 +1075,10 @@ function createAgentScoreCore(options) {
|
|
|
457
1075
|
// regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
|
|
458
1076
|
...signer && { signer: { address: signer.address, network: signer.network } }
|
|
459
1077
|
};
|
|
460
|
-
|
|
1078
|
+
if (identity.aipToken !== void 0 && identity.aipSignature === void 0) {
|
|
1079
|
+
throw new Error("AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).");
|
|
1080
|
+
}
|
|
1081
|
+
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 });
|
|
461
1082
|
data = result;
|
|
462
1083
|
} catch (err) {
|
|
463
1084
|
if (err instanceof import_sdk.PaymentRequiredError) {
|
|
@@ -528,17 +1149,21 @@ function createAgentScoreCore(options) {
|
|
|
528
1149
|
const decisionReasons = data.decision_reasons ?? [];
|
|
529
1150
|
const allow = decision === "allow" || decision == null;
|
|
530
1151
|
cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
|
|
1152
|
+
const signerVerdict = buildSignerVerdict(identity, data);
|
|
531
1153
|
if (allow) {
|
|
532
1154
|
const quota = data.quota;
|
|
533
1155
|
return {
|
|
534
1156
|
kind: "allow",
|
|
535
1157
|
data,
|
|
536
|
-
...quota !== void 0 && { quota }
|
|
1158
|
+
...quota !== void 0 && { quota },
|
|
1159
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
537
1160
|
};
|
|
538
1161
|
}
|
|
539
1162
|
if (isFixableDenial(decisionReasons)) {
|
|
540
1163
|
const sessionReason = await tryMintSessionDenial(ctx);
|
|
541
|
-
if (sessionReason)
|
|
1164
|
+
if (sessionReason) {
|
|
1165
|
+
return { kind: "deny", reason: sessionReason, ...signerVerdict !== void 0 && { signerVerdict } };
|
|
1166
|
+
}
|
|
542
1167
|
}
|
|
543
1168
|
return {
|
|
544
1169
|
kind: "deny",
|
|
@@ -548,7 +1173,8 @@ function createAgentScoreCore(options) {
|
|
|
548
1173
|
reasons: decisionReasons,
|
|
549
1174
|
verify_url: data.verify_url,
|
|
550
1175
|
data
|
|
551
|
-
}
|
|
1176
|
+
},
|
|
1177
|
+
...signerVerdict !== void 0 && { signerVerdict }
|
|
552
1178
|
};
|
|
553
1179
|
}
|
|
554
1180
|
async function captureWallet(options2) {
|
|
@@ -590,22 +1216,21 @@ function createAgentScoreCore(options) {
|
|
|
590
1216
|
agentInstructions: sm.agent_instructions ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS
|
|
591
1217
|
};
|
|
592
1218
|
}
|
|
593
|
-
function
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const raw = cached.raw;
|
|
598
|
-
if (!raw) return void 0;
|
|
1219
|
+
function buildSignerVerdict(identity, raw) {
|
|
1220
|
+
if (identity.address === void 0 || identity.operatorToken !== void 0 || identity.aipToken !== void 0) {
|
|
1221
|
+
return void 0;
|
|
1222
|
+
}
|
|
599
1223
|
const rawMatch = raw.signer_match;
|
|
600
1224
|
const rawSanctions = raw.signer_sanctions;
|
|
601
1225
|
if (!rawMatch && !rawSanctions) return void 0;
|
|
1226
|
+
const claimedNorm = normalizeAddress(identity.address);
|
|
602
1227
|
const signerNorm = rawMatch?.actual_signer ?? claimedNorm;
|
|
603
1228
|
return {
|
|
604
1229
|
signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,
|
|
605
1230
|
signer_sanctions: rawSanctions ?? null
|
|
606
1231
|
};
|
|
607
1232
|
}
|
|
608
|
-
return { evaluate, captureWallet
|
|
1233
|
+
return { evaluate, captureWallet };
|
|
609
1234
|
}
|
|
610
1235
|
|
|
611
1236
|
// src/signer.ts
|
|
@@ -710,7 +1335,8 @@ function createAgentScoreGate(options) {
|
|
|
710
1335
|
const outcome = await core.evaluate(identity, req, signer);
|
|
711
1336
|
if (outcome.kind === "allow") {
|
|
712
1337
|
const captureWallet = identity?.operatorToken ? (opts) => core.captureWallet({ operatorToken: identity.operatorToken, ...opts }) : void 0;
|
|
713
|
-
const
|
|
1338
|
+
const signerVerdict = outcome.signerVerdict;
|
|
1339
|
+
const getSignerVerdictBound = identity?.address && !identity?.operatorToken ? () => signerVerdict : void 0;
|
|
714
1340
|
return {
|
|
715
1341
|
allowed: true,
|
|
716
1342
|
data: outcome.data,
|
|
@@ -724,6 +1350,42 @@ function createAgentScoreGate(options) {
|
|
|
724
1350
|
return { allowed: false, response };
|
|
725
1351
|
};
|
|
726
1352
|
}
|
|
1353
|
+
var defaultAipResponse = (body) => new Response(JSON.stringify(body), { status: body.status, headers: { "content-type": "application/problem+json" } });
|
|
1354
|
+
function createAipGate(options) {
|
|
1355
|
+
const { onDenied, ...gateOpts } = options;
|
|
1356
|
+
return async (req) => {
|
|
1357
|
+
const result = await evaluateAipRequest(req, gateOpts);
|
|
1358
|
+
if (result.ok) {
|
|
1359
|
+
return { allowed: true, ait: result.ait };
|
|
1360
|
+
}
|
|
1361
|
+
const body = result.body;
|
|
1362
|
+
const response = onDenied ? await onDenied(req, body) : defaultAipResponse(body);
|
|
1363
|
+
return { allowed: false, response };
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
function withAipGate(options, handler) {
|
|
1367
|
+
const guard = createAipGate(options);
|
|
1368
|
+
return async (req, ctx) => {
|
|
1369
|
+
const result = await guard(req);
|
|
1370
|
+
if (!result.allowed) {
|
|
1371
|
+
return result.response;
|
|
1372
|
+
}
|
|
1373
|
+
return handler(req, { ait: result.ait }, ctx);
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
function withConditionalAipGate(options, handler) {
|
|
1377
|
+
const guard = createAipGate(options);
|
|
1378
|
+
return async (req, ctx) => {
|
|
1379
|
+
if (!hasAgentIdentityHeader(req)) {
|
|
1380
|
+
return handler(req, {}, ctx);
|
|
1381
|
+
}
|
|
1382
|
+
const result = await guard(req);
|
|
1383
|
+
if (!result.allowed) {
|
|
1384
|
+
return result.response;
|
|
1385
|
+
}
|
|
1386
|
+
return handler(req, { ait: result.ait }, ctx);
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
727
1389
|
|
|
728
1390
|
// src/identity/nextjs.ts
|
|
729
1391
|
function withAgentScoreGate(options, handler) {
|
|
@@ -773,7 +1435,10 @@ function conditionalAgentscoreMiddleware(options) {
|
|
|
773
1435
|
0 && (module.exports = {
|
|
774
1436
|
agentscoreMiddleware,
|
|
775
1437
|
conditionalAgentscoreMiddleware,
|
|
1438
|
+
createAipGate,
|
|
776
1439
|
withAgentScoreGate,
|
|
777
|
-
|
|
1440
|
+
withAipGate,
|
|
1441
|
+
withConditionalAgentScoreGate,
|
|
1442
|
+
withConditionalAipGate
|
|
778
1443
|
});
|
|
779
1444
|
//# sourceMappingURL=nextjs.js.map
|