@agent-score/commerce 2.3.0 → 2.5.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.
Files changed (80) hide show
  1. package/README.md +6 -6
  2. package/dist/challenge/index.d.mts +9 -5
  3. package/dist/challenge/index.d.ts +9 -5
  4. package/dist/challenge/index.js +11 -4
  5. package/dist/challenge/index.js.map +1 -1
  6. package/dist/challenge/index.mjs +11 -4
  7. package/dist/challenge/index.mjs.map +1 -1
  8. package/dist/{checkout-ChyOi7aU.d.ts → checkout-McfNpZJf.d.ts} +80 -12
  9. package/dist/{checkout-Ceo1_rVJ.d.mts → checkout-o17dIxHi.d.mts} +80 -12
  10. package/dist/core.d.mts +27 -7
  11. package/dist/core.d.ts +27 -7
  12. package/dist/core.js +25 -11
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +25 -11
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/discovery/index.d.mts +26 -10
  17. package/dist/discovery/index.d.ts +26 -10
  18. package/dist/discovery/index.js +58 -10
  19. package/dist/discovery/index.js.map +1 -1
  20. package/dist/discovery/index.mjs +58 -10
  21. package/dist/discovery/index.mjs.map +1 -1
  22. package/dist/gate-CWP10xPQ.d.mts +339 -0
  23. package/dist/gate-CWP10xPQ.d.ts +339 -0
  24. package/dist/identity/express.d.mts +26 -1
  25. package/dist/identity/express.d.ts +26 -1
  26. package/dist/identity/express.js +599 -25
  27. package/dist/identity/express.js.map +1 -1
  28. package/dist/identity/express.mjs +595 -24
  29. package/dist/identity/express.mjs.map +1 -1
  30. package/dist/identity/fastify.d.mts +12 -2
  31. package/dist/identity/fastify.d.ts +12 -2
  32. package/dist/identity/fastify.js +607 -25
  33. package/dist/identity/fastify.js.map +1 -1
  34. package/dist/identity/fastify.mjs +603 -24
  35. package/dist/identity/fastify.mjs.map +1 -1
  36. package/dist/identity/hono.d.mts +26 -1
  37. package/dist/identity/hono.d.ts +26 -1
  38. package/dist/identity/hono.js +588 -25
  39. package/dist/identity/hono.js.map +1 -1
  40. package/dist/identity/hono.mjs +584 -24
  41. package/dist/identity/hono.mjs.map +1 -1
  42. package/dist/identity/nextjs.d.mts +3 -0
  43. package/dist/identity/nextjs.d.ts +3 -0
  44. package/dist/identity/nextjs.js +593 -25
  45. package/dist/identity/nextjs.js.map +1 -1
  46. package/dist/identity/nextjs.mjs +589 -24
  47. package/dist/identity/nextjs.mjs.map +1 -1
  48. package/dist/identity/policy.js.map +1 -1
  49. package/dist/identity/policy.mjs.map +1 -1
  50. package/dist/identity/web.d.mts +24 -1
  51. package/dist/identity/web.d.ts +24 -1
  52. package/dist/identity/web.js +593 -25
  53. package/dist/identity/web.js.map +1 -1
  54. package/dist/identity/web.mjs +589 -24
  55. package/dist/identity/web.mjs.map +1 -1
  56. package/dist/index.d.mts +129 -14
  57. package/dist/index.d.ts +129 -14
  58. package/dist/index.js +978 -99
  59. package/dist/index.js.map +1 -1
  60. package/dist/index.mjs +956 -99
  61. package/dist/index.mjs.map +1 -1
  62. package/dist/{default_rails-DtR_E9N9.d.ts → network_kind-BIJM2peR.d.ts} +22 -8
  63. package/dist/{default_rails-K25PtWrL.d.mts → network_kind-C0EMkdzz.d.mts} +22 -8
  64. package/dist/payment/index.d.mts +16 -26
  65. package/dist/payment/index.d.ts +16 -26
  66. package/dist/payment/index.js +62 -57
  67. package/dist/payment/index.js.map +1 -1
  68. package/dist/payment/index.mjs +62 -57
  69. package/dist/payment/index.mjs.map +1 -1
  70. package/dist/{pricing-B3-aKxSz.d.ts → pricing-CytRwhC2.d.ts} +1 -1
  71. package/dist/{pricing-BReyZiqN.d.mts → pricing-KHDqMLd7.d.mts} +1 -1
  72. package/dist/{rail_spec-B1239jPp.d.mts → rail_spec-BFZmW9RN.d.mts} +3 -4
  73. package/dist/{rail_spec-B1239jPp.d.ts → rail_spec-BFZmW9RN.d.ts} +3 -4
  74. package/dist/stripe-multichain/index.d.mts +2 -9
  75. package/dist/stripe-multichain/index.d.ts +2 -9
  76. package/dist/stripe-multichain/index.js.map +1 -1
  77. package/dist/stripe-multichain/index.mjs.map +1 -1
  78. package/dist/{wwwauthenticate-D_FMnPgU.d.mts → wwwauthenticate-CVaGUMjU.d.mts} +8 -6
  79. package/dist/{wwwauthenticate-D_FMnPgU.d.ts → wwwauthenticate-CVaGUMjU.d.ts} +8 -6
  80. package/package.json +14 -13
@@ -21,12 +21,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var express_exports = {};
22
22
  __export(express_exports, {
23
23
  agentscoreGate: () => agentscoreGate,
24
+ aipGate: () => aipGate,
24
25
  captureWallet: () => captureWallet,
25
26
  conditionalAgentscoreGate: () => conditionalAgentscoreGate,
27
+ conditionalAipGate: () => conditionalAipGate,
26
28
  getAgentScoreData: () => getAgentScoreData,
27
29
  getGateDegradedState: () => getGateDegradedState,
28
30
  getGateQuotaInfo: () => getGateQuotaInfo,
29
- getSignerVerdict: () => getSignerVerdict
31
+ getSignerVerdict: () => getSignerVerdict,
32
+ getVerifiedAit: () => getVerifiedAit
30
33
  });
31
34
  module.exports = __toCommonJS(express_exports);
32
35
 
@@ -163,7 +166,530 @@ function denialReasonToBody(reason) {
163
166
  return body;
164
167
  }
165
168
 
169
+ // src/aip/verify.ts
170
+ var import_jose2 = require("jose");
171
+
172
+ // src/aip/http-signature.ts
173
+ var import_jose = require("jose");
174
+ var { subtle } = globalThis.crypto;
175
+ var b64ToBytes = (b64) => {
176
+ const bin = atob(b64);
177
+ const out = new Uint8Array(bin.length);
178
+ for (let i = 0; i < bin.length; i++) {
179
+ out[i] = bin.charCodeAt(i);
180
+ }
181
+ return out;
182
+ };
183
+ var AIP_COVERED_COMPONENTS = ["@method", "@authority", "@path", "agent-identity"];
184
+ var AIP_SIGNATURE_TAG = "agent-identity";
185
+ var DEFAULT_MAX_SKEW_SECONDS = 60;
186
+ var normalizeAuthority = (authority) => {
187
+ const lower = authority.trim().toLowerCase();
188
+ const colon = lower.lastIndexOf(":");
189
+ if (colon === -1) {
190
+ return lower;
191
+ }
192
+ if (lower.includes("]") && colon < lower.indexOf("]")) {
193
+ return lower;
194
+ }
195
+ const host = lower.slice(0, colon);
196
+ const port = lower.slice(colon + 1);
197
+ if (port === "80" || port === "443") {
198
+ return host;
199
+ }
200
+ return lower;
201
+ };
202
+ var componentValue = (name, input) => {
203
+ switch (name) {
204
+ case "@method":
205
+ return input.method.toUpperCase();
206
+ case "@authority":
207
+ return normalizeAuthority(input.authority);
208
+ case "@path":
209
+ return input.path;
210
+ case "agent-identity":
211
+ return input.agentIdentity.trim();
212
+ default:
213
+ return input.extra?.[name] ?? null;
214
+ }
215
+ };
216
+ var serializeComponentList = (components) => `(${components.map((c) => `"${c}"`).join(" ")})`;
217
+ var serializeParams = (p) => {
218
+ const parts = [];
219
+ if (p.created !== void 0) {
220
+ parts.push(`created=${p.created}`);
221
+ }
222
+ if (p.expires !== void 0) {
223
+ parts.push(`expires=${p.expires}`);
224
+ }
225
+ if (p.keyid !== void 0) {
226
+ parts.push(`keyid="${p.keyid}"`);
227
+ }
228
+ if (p.alg !== void 0) {
229
+ parts.push(`alg="${p.alg}"`);
230
+ }
231
+ if (p.tag !== void 0) {
232
+ parts.push(`tag="${p.tag}"`);
233
+ }
234
+ return parts.map((s) => `;${s}`).join("");
235
+ };
236
+ var buildSignatureBase = (params, input) => {
237
+ const lines = [];
238
+ for (const name of params.components) {
239
+ const value = componentValue(name, input);
240
+ if (value === null) {
241
+ throw new MissingComponentError(name);
242
+ }
243
+ lines.push(`"${name}": ${value}`);
244
+ }
245
+ const paramsValue = serializeComponentList(params.components) + serializeParams(params);
246
+ lines.push(`"@signature-params": ${paramsValue}`);
247
+ return lines.join("\n");
248
+ };
249
+ var MissingComponentError = class extends Error {
250
+ constructor(component) {
251
+ super(`signature base missing covered component: ${component}`);
252
+ this.component = component;
253
+ this.name = "MissingComponentError";
254
+ }
255
+ component;
256
+ };
257
+ var parseSignatureInput = (header, tag = AIP_SIGNATURE_TAG) => {
258
+ const members = splitDictionary(header);
259
+ if (members.length === 0) {
260
+ return null;
261
+ }
262
+ const parsed = members.map((m) => {
263
+ const params = parseInnerListMember(m.value);
264
+ return params ? { label: m.label, params } : null;
265
+ }).filter((x) => x !== null);
266
+ if (parsed.length === 0) {
267
+ return null;
268
+ }
269
+ const tagged = parsed.find((p) => p.params.tag === tag);
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;
277
+ };
278
+ var parseSignatureValue = (header, label) => {
279
+ const members = splitDictionary(header);
280
+ const member = members.find((m) => m.label === label);
281
+ if (!member) {
282
+ return null;
283
+ }
284
+ const v = member.value.trim();
285
+ if (!v.startsWith(":") || !v.endsWith(":") || v.length < 2) {
286
+ return null;
287
+ }
288
+ const b64 = v.slice(1, -1);
289
+ try {
290
+ return b64ToBytes(b64);
291
+ } catch {
292
+ return null;
293
+ }
294
+ };
295
+ var splitDictionary = (header) => {
296
+ const out = [];
297
+ let depth = 0;
298
+ let inBytes = false;
299
+ let inString = false;
300
+ let current = "";
301
+ for (let i = 0; i < header.length; i++) {
302
+ const ch = header[i];
303
+ if (inString) {
304
+ current += ch;
305
+ if (ch === '"' && header[i - 1] !== "\\") {
306
+ inString = false;
307
+ }
308
+ continue;
309
+ }
310
+ if (ch === '"') {
311
+ inString = true;
312
+ current += ch;
313
+ continue;
314
+ }
315
+ if (ch === ":") {
316
+ inBytes = !inBytes;
317
+ current += ch;
318
+ continue;
319
+ }
320
+ if (!inBytes && ch === "(") {
321
+ depth++;
322
+ current += ch;
323
+ continue;
324
+ }
325
+ if (!inBytes && ch === ")") {
326
+ depth = Math.max(0, depth - 1);
327
+ current += ch;
328
+ continue;
329
+ }
330
+ if (!inBytes && depth === 0 && ch === ",") {
331
+ pushMember(out, current);
332
+ current = "";
333
+ continue;
334
+ }
335
+ current += ch;
336
+ }
337
+ pushMember(out, current);
338
+ return out;
339
+ };
340
+ var pushMember = (out, raw) => {
341
+ const trimmed = raw.trim();
342
+ if (!trimmed) {
343
+ return;
344
+ }
345
+ const eq = trimmed.indexOf("=");
346
+ if (eq === -1) {
347
+ return;
348
+ }
349
+ const label = trimmed.slice(0, eq).trim();
350
+ const value = trimmed.slice(eq + 1).trim();
351
+ if (label) {
352
+ out.push({ label, value });
353
+ }
354
+ };
355
+ var parseInnerListMember = (value) => {
356
+ const open = value.indexOf("(");
357
+ const close = value.indexOf(")", open + 1);
358
+ if (open === -1 || close === -1) {
359
+ return null;
360
+ }
361
+ const listBody = value.slice(open + 1, close).trim();
362
+ const components = listBody.length === 0 ? [] : (listBody.match(/"[^"]*"/g) ?? []).map((s) => s.slice(1, -1));
363
+ const params = { components };
364
+ const paramStr = value.slice(close + 1);
365
+ const re = /;\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*=\s*("(?:[^"\\]|\\.)*"|-?\d+)/g;
366
+ let match;
367
+ while ((match = re.exec(paramStr)) !== null) {
368
+ const key = match[1];
369
+ const raw = match[2];
370
+ const val = raw.startsWith('"') ? raw.slice(1, -1) : Number(raw);
371
+ if (key === "created") {
372
+ params.created = val;
373
+ } else if (key === "expires") {
374
+ params.expires = val;
375
+ } else if (key === "keyid") {
376
+ params.keyid = val;
377
+ } else if (key === "tag") {
378
+ params.tag = val;
379
+ } else if (key === "alg") {
380
+ params.alg = val;
381
+ }
382
+ }
383
+ return params;
384
+ };
385
+ var verifyMessageSignature = async (input) => {
386
+ const selected = parseSignatureInput(input.signatureInput);
387
+ if (!selected) {
388
+ return { ok: false, reason: "no_aip_signature" };
389
+ }
390
+ const { label, params } = selected;
391
+ if (params.alg !== void 0 && !["ed25519", "eddsa"].includes(params.alg.toLowerCase())) {
392
+ return { ok: false, reason: "unsupported_alg" };
393
+ }
394
+ for (const required of AIP_COVERED_COMPONENTS) {
395
+ if (!params.components.includes(required)) {
396
+ return { ok: false, reason: "missing_covered_component" };
397
+ }
398
+ }
399
+ const now = input.now ?? Math.floor(Date.now() / 1e3);
400
+ const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;
401
+ if (params.created !== void 0 && params.created > now + skew) {
402
+ return { ok: false, reason: "created_in_future" };
403
+ }
404
+ if (params.expires !== void 0 && params.expires < now - skew) {
405
+ return { ok: false, reason: "expired" };
406
+ }
407
+ if (!params.keyid) {
408
+ return { ok: false, reason: "missing_keyid" };
409
+ }
410
+ const cnf = input.cnfJwk;
411
+ if (cnf.kty !== "OKP" || cnf.crv !== "Ed25519" || typeof cnf.x !== "string" || cnf.x.length === 0) {
412
+ return { ok: false, reason: "unsupported_cnf_key" };
413
+ }
414
+ let thumbprint;
415
+ try {
416
+ thumbprint = await (0, import_jose.calculateJwkThumbprint)(input.cnfJwk, "sha256");
417
+ } catch {
418
+ return { ok: false, reason: "unsupported_cnf_key" };
419
+ }
420
+ if (params.keyid !== thumbprint) {
421
+ return { ok: false, reason: "keyid_mismatch" };
422
+ }
423
+ const sig = parseSignatureValue(input.signature, label);
424
+ if (!sig) {
425
+ return { ok: false, reason: "malformed_signature" };
426
+ }
427
+ let base;
428
+ try {
429
+ base = buildSignatureBase(params, {
430
+ method: input.method,
431
+ authority: input.authority,
432
+ path: input.path,
433
+ agentIdentity: input.agentIdentity,
434
+ extra: input.extraComponents
435
+ });
436
+ } catch (err) {
437
+ if (err instanceof MissingComponentError) {
438
+ return { ok: false, reason: "missing_covered_component" };
439
+ }
440
+ throw err;
441
+ }
442
+ let valid;
443
+ try {
444
+ const key = await (0, import_jose.importJWK)(input.cnfJwk, "EdDSA");
445
+ if (!(key instanceof CryptoKey)) {
446
+ return { ok: false, reason: "signature_invalid" };
447
+ }
448
+ valid = await subtle.verify(
449
+ { name: "Ed25519" },
450
+ key,
451
+ sig,
452
+ new TextEncoder().encode(base)
453
+ );
454
+ } catch {
455
+ return { ok: false, reason: "signature_invalid" };
456
+ }
457
+ return valid ? { ok: true, params } : { ok: false, reason: "signature_invalid" };
458
+ };
459
+
460
+ // src/aip/types.ts
461
+ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
462
+ var isNonEmptyString = (v) => typeof v === "string" && v.length > 0;
463
+ var isAitShape = (payload) => isObject(payload) && isObject(payload.cnf) && isObject(payload.agent);
464
+ var validateAitPayload = (payload) => {
465
+ if (!isObject(payload)) {
466
+ return { ok: false, reason: "not_an_object" };
467
+ }
468
+ if (!isNonEmptyString(payload.aip_version)) {
469
+ return { ok: false, reason: "missing_aip_version" };
470
+ }
471
+ if (!isNonEmptyString(payload.iss)) {
472
+ return { ok: false, reason: "missing_iss" };
473
+ }
474
+ if (!isNonEmptyString(payload.sub)) {
475
+ return { ok: false, reason: "missing_sub" };
476
+ }
477
+ if (typeof payload.iat !== "number") {
478
+ return { ok: false, reason: "missing_iat" };
479
+ }
480
+ if (typeof payload.exp !== "number") {
481
+ return { ok: false, reason: "missing_exp" };
482
+ }
483
+ if (!isObject(payload.cnf) || !isObject(payload.cnf.jwk)) {
484
+ return { ok: false, reason: "missing_cnf" };
485
+ }
486
+ if (!isObject(payload.agent) || !isNonEmptyString(payload.agent.provider)) {
487
+ return { ok: false, reason: "missing_agent_provider" };
488
+ }
489
+ if (payload.trust_level === "human_confirmed") {
490
+ const auth = payload.auth;
491
+ const amr = isObject(auth) ? auth.amr : void 0;
492
+ if (!Array.isArray(amr) || amr.length === 0) {
493
+ return { ok: false, reason: "human_confirmed_without_amr" };
494
+ }
495
+ }
496
+ return { ok: true, payload };
497
+ };
498
+
499
+ // src/aip/verify.ts
500
+ var verifyAit = async (ctx, opts) => {
501
+ if (ctx.agentIdentityHeaders.length === 0) {
502
+ return { ok: false, reason: "no_token" };
503
+ }
504
+ if (!ctx.signatureInput || !ctx.signature) {
505
+ return { ok: false, reason: "pop_signature_missing" };
506
+ }
507
+ let lastFailure = "malformed_token";
508
+ for (const raw of ctx.agentIdentityHeaders) {
509
+ const token = stripBearer(raw);
510
+ let header;
511
+ let payload;
512
+ try {
513
+ header = (0, import_jose2.decodeProtectedHeader)(token);
514
+ payload = (0, import_jose2.decodeJwt)(token);
515
+ } catch {
516
+ lastFailure = "malformed_token";
517
+ continue;
518
+ }
519
+ if (header.alg === void 0 || header.alg.toLowerCase() === "none") {
520
+ lastFailure = "malformed_token";
521
+ continue;
522
+ }
523
+ if (!isAitShape(payload)) {
524
+ lastFailure = "malformed_token";
525
+ continue;
526
+ }
527
+ const validated = validateAitPayload(payload);
528
+ if (!validated.ok) {
529
+ lastFailure = "invalid_claims";
530
+ continue;
531
+ }
532
+ const claims = validated.payload;
533
+ const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);
534
+ if (!keyLookup.ok) {
535
+ lastFailure = keyLookup.reason === "untrusted_issuer" || keyLookup.reason === "insecure_issuer" ? "untrusted_issuer" : "key_unavailable";
536
+ continue;
537
+ }
538
+ const jwtClockTolerance = opts.maxSkewSeconds ?? 60;
539
+ try {
540
+ const idpKey = await (0, import_jose2.importJWK)(keyLookup.key, normalizeAlg(header.alg));
541
+ await (0, import_jose2.jwtVerify)(token, idpKey, {
542
+ // Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without
543
+ // this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a
544
+ // 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 core/api aip-verify.
546
+ algorithms: AIT_SIGNING_ALGS,
547
+ clockTolerance: jwtClockTolerance,
548
+ currentDate: opts.now !== void 0 ? new Date(opts.now * 1e3) : void 0
549
+ });
550
+ } catch (err) {
551
+ lastFailure = isExpiry(err) ? "expired_token" : "idp_signature_invalid";
552
+ continue;
553
+ }
554
+ const nowSec = opts.now ?? Math.floor(Date.now() / 1e3);
555
+ if (claims.iat > nowSec + jwtClockTolerance) {
556
+ lastFailure = "expired_token";
557
+ continue;
558
+ }
559
+ const popResult = await verifyMessageSignature({
560
+ method: ctx.method,
561
+ authority: ctx.authority,
562
+ path: ctx.path,
563
+ agentIdentity: raw,
564
+ signatureInput: ctx.signatureInput,
565
+ signature: ctx.signature,
566
+ cnfJwk: claims.cnf.jwk,
567
+ now: opts.now,
568
+ maxSkewSeconds: opts.maxSkewSeconds
569
+ });
570
+ if (!popResult.ok) {
571
+ lastFailure = "pop_signature_invalid";
572
+ continue;
573
+ }
574
+ return { ok: true, ait: { payload: claims, iss: claims.iss, cnfJwk: claims.cnf.jwk, token } };
575
+ }
576
+ return { ok: false, reason: lastFailure };
577
+ };
578
+ var stripBearer = (value) => {
579
+ const trimmed = value.trim();
580
+ return /^bearer\s+/i.test(trimmed) ? trimmed.replace(/^bearer\s+/i, "") : trimmed;
581
+ };
582
+ var AIT_SIGNING_ALGS = ["EdDSA", "ES256"];
583
+ var normalizeAlg = (alg) => alg.toLowerCase() === "eddsa" ? "EdDSA" : alg;
584
+ var isExpiry = (err) => typeof err === "object" && err !== null && err.code === "ERR_JWT_EXPIRED";
585
+
586
+ // src/aip/request.ts
587
+ var readNodeHeader = (headers, name) => {
588
+ const v = headers[name] ?? headers[name.toLowerCase()];
589
+ if (v === void 0) {
590
+ return void 0;
591
+ }
592
+ return Array.isArray(v) ? v.join(", ") : v;
593
+ };
594
+ var hasAgentIdentityHeaderNode = (headers) => {
595
+ const raw = readNodeHeader(headers, "agent-identity");
596
+ return raw !== void 0 && raw.split(",").some((s) => s.trim().length > 0);
597
+ };
598
+ var buildVerifyContextFromParts = (parts) => {
599
+ const agentIdentityRaw = readNodeHeader(parts.headers, "agent-identity");
600
+ const agentIdentityHeaders = agentIdentityRaw ? agentIdentityRaw.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
601
+ const host = parts.authority ?? readNodeHeader(parts.headers, "host") ?? "";
602
+ let path;
603
+ try {
604
+ path = new URL(parts.url, host ? `http://${host}` : "http://localhost").pathname;
605
+ } catch {
606
+ const q = parts.url.indexOf("?");
607
+ path = q === -1 ? parts.url : parts.url.slice(0, q);
608
+ }
609
+ return {
610
+ method: parts.method,
611
+ authority: host,
612
+ path,
613
+ agentIdentityHeaders,
614
+ signatureInput: readNodeHeader(parts.headers, "signature-input") ?? null,
615
+ signature: readNodeHeader(parts.headers, "signature") ?? null
616
+ };
617
+ };
618
+
619
+ // src/aip/gate.ts
620
+ var verifyFromContext = async (ctx, opts) => {
621
+ const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });
622
+ return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };
623
+ };
624
+ var verifyAitParts = (parts, opts) => verifyFromContext(buildVerifyContextFromParts(parts), opts);
625
+ var aipErrorCode = (failure) => {
626
+ switch (failure) {
627
+ case "no_token":
628
+ case "pop_signature_missing":
629
+ return "agent_identity_required";
630
+ case "untrusted_issuer":
631
+ return "untrusted_issuer";
632
+ case "expired_token":
633
+ return "expired_token";
634
+ case "invalid_claims":
635
+ return "insufficient_claims";
636
+ case "key_unavailable":
637
+ return "idp_unavailable";
638
+ case "malformed_token":
639
+ case "idp_signature_invalid":
640
+ case "pop_signature_invalid":
641
+ return "invalid_signature";
642
+ default:
643
+ return "invalid_signature";
644
+ }
645
+ };
646
+ var aipErrorStatus = (failure) => {
647
+ switch (failure) {
648
+ case "key_unavailable":
649
+ return 503;
650
+ case "untrusted_issuer":
651
+ case "invalid_claims":
652
+ return 403;
653
+ default:
654
+ return 401;
655
+ }
656
+ };
657
+ var aipErrorDetail = (failure) => {
658
+ switch (failure) {
659
+ case "no_token":
660
+ return "No Agent-Identity token was presented.";
661
+ case "pop_signature_missing":
662
+ return "The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.";
663
+ case "untrusted_issuer":
664
+ return "The token's issuer is not in this service's trusted-issuer list.";
665
+ case "expired_token":
666
+ return "The Agent Identity Token has expired.";
667
+ case "invalid_claims":
668
+ return "The token is missing required claims for this endpoint.";
669
+ case "malformed_token":
670
+ return "The Agent-Identity header could not be parsed as an Agent Identity Token.";
671
+ case "idp_signature_invalid":
672
+ return "The identity provider's signature on the token failed verification.";
673
+ case "pop_signature_invalid":
674
+ return "The request signature did not match the key bound to the token.";
675
+ case "key_unavailable":
676
+ return "The identity provider's signing key could not be resolved.";
677
+ default:
678
+ return "Token verification failed.";
679
+ }
680
+ };
681
+ var buildAipErrorBody = (failure) => {
682
+ const code = aipErrorCode(failure);
683
+ return {
684
+ type: `urn:aip:error:${code}`,
685
+ title: code.replace(/_/g, " "),
686
+ status: aipErrorStatus(failure),
687
+ detail: aipErrorDetail(failure)
688
+ };
689
+ };
690
+
166
691
  // src/core.ts
692
+ var import_node_crypto = require("crypto");
167
693
  var import_sdk = require("@agent-score/sdk");
168
694
 
169
695
  // src/address.ts
@@ -258,8 +784,9 @@ var INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({
258
784
  ],
259
785
  user_message: "The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one."
260
786
  });
261
- function buildAgentMemoryHint() {
787
+ function buildAgentMemoryHint(aipTrustedIssuers) {
262
788
  const api = CANONICAL_AGENTSCORE_API;
789
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
263
790
  return {
264
791
  save_for_future_agentscore_gates: true,
265
792
  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.",
@@ -267,8 +794,12 @@ function buildAgentMemoryHint() {
267
794
  identity_check_endpoint: `${api}/v1/credentials`,
268
795
  identity_paths: {
269
796
  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.",
270
- 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."
797
+ 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.",
798
+ ...acceptsAip && {
799
+ 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.'
800
+ }
271
801
  },
802
+ ...acceptsAip && { aip_trusted_issuers: aipTrustedIssuers },
272
803
  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.",
273
804
  do_not_persist_in_memory: ["operator_token", "poll_secret"],
274
805
  persist_in_credential_store: ["operator_token"]
@@ -290,11 +821,12 @@ function createAgentScoreCore(options) {
290
821
  baseUrl: rawBaseUrl = "https://api.agentscore.sh",
291
822
  chain: gateChain,
292
823
  userAgent,
293
- createSessionOnMissing
824
+ createSessionOnMissing,
825
+ aipTrustedIssuers
294
826
  } = options;
295
827
  const baseUrl = stripTrailingSlashes(rawBaseUrl);
296
- const agentMemoryHint = buildAgentMemoryHint();
297
- const defaultUa = `@agent-score/commerce@${"2.3.0"}`;
828
+ const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);
829
+ const defaultUa = `@agent-score/commerce@${"2.5.0"}`;
298
830
  const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;
299
831
  const sdk = new import_sdk.AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });
300
832
  const sessionSdkCache = /* @__PURE__ */ new Map();
@@ -312,6 +844,7 @@ function createAgentScoreCore(options) {
312
844
  return s;
313
845
  }
314
846
  const cache = new TTLCache(cacheSeconds * 1e3);
847
+ const lastSignerRaw = /* @__PURE__ */ new Map();
315
848
  async function tryMintSessionDenial(ctx) {
316
849
  if (!createSessionOnMissing) return void 0;
317
850
  try {
@@ -369,13 +902,18 @@ function createAgentScoreCore(options) {
369
902
  }
370
903
  }
371
904
  async function evaluate(identity, ctx, signer) {
372
- if (!identity || !identity.address && !identity.operatorToken) {
905
+ if (!identity || !identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim()) {
373
906
  if (failOpen) return { kind: "allow" };
374
907
  const sessionReason = await tryMintSessionDenial(ctx);
375
908
  if (sessionReason) return { kind: "deny", reason: sessionReason };
909
+ const acceptsAip = aipTrustedIssuers !== void 0 && aipTrustedIssuers.length > 0;
910
+ const aipStep = acceptsAip ? [
911
+ `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.`
912
+ ] : [];
376
913
  const missingIdentityInstructions = JSON.stringify({
377
914
  action: "probe_identity_then_session",
378
915
  steps: [
916
+ ...aipStep,
379
917
  "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.",
380
918
  "If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.",
381
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.sh/sign-up to create an AgentScore identity and mint an operator_token from their dashboard (https://agentscore.sh/dashboard/verify). The user hands the opc_... to you, and you retry with X-Operator-Token."
@@ -391,7 +929,7 @@ function createAgentScoreCore(options) {
391
929
  }
392
930
  };
393
931
  }
394
- const cacheKey = identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
932
+ const cacheKey = identity.aipToken ? `aip:${(0, import_node_crypto.createHash)("sha256").update(identity.aipToken).digest("hex")}` : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : "");
395
933
  const cached = cache.get(cacheKey);
396
934
  if (cached) {
397
935
  if (cached.allow) {
@@ -436,7 +974,7 @@ function createAgentScoreCore(options) {
436
974
  // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).
437
975
  ...signer && { signer: { address: signer.address, network: signer.network } }
438
976
  };
439
- const result = identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
977
+ const result = identity.aipToken ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken }) : identity.address ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken }) : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken });
440
978
  data = result;
441
979
  } catch (err) {
442
980
  if (err instanceof import_sdk.PaymentRequiredError) {
@@ -507,6 +1045,9 @@ function createAgentScoreCore(options) {
507
1045
  const decisionReasons = data.decision_reasons ?? [];
508
1046
  const allow = decision === "allow" || decision == null;
509
1047
  cache.set(cacheKey, { allow, decision: decision ?? void 0, reasons: decisionReasons, raw: data });
1048
+ if (identity.address !== void 0 && identity.operatorToken === void 0 && identity.aipToken === void 0 && (data.signer_match !== void 0 || data.signer_sanctions !== void 0)) {
1049
+ lastSignerRaw.set(normalizeAddress(identity.address), data);
1050
+ }
510
1051
  if (allow) {
511
1052
  const quota = data.quota;
512
1053
  return {
@@ -571,9 +1112,7 @@ function createAgentScoreCore(options) {
571
1112
  }
572
1113
  function getSignerVerdict2(claimedAddress) {
573
1114
  const claimedNorm = normalizeAddress(claimedAddress);
574
- const cached = cache.get(claimedNorm);
575
- if (!cached) return void 0;
576
- const raw = cached.raw;
1115
+ const raw = lastSignerRaw.get(claimedNorm) ?? cache.get(claimedNorm)?.raw;
577
1116
  if (!raw) return void 0;
578
1117
  const rawMatch = raw.signer_match;
579
1118
  const rawSanctions = raw.signer_sanctions;
@@ -651,6 +1190,18 @@ async function extractSolanaSignerFromCredential(credential) {
651
1190
  }
652
1191
  }
653
1192
  async function extractPaymentSigner(request, x402PaymentHeader) {
1193
+ if (x402PaymentHeader) {
1194
+ try {
1195
+ const decoded = atob(x402PaymentHeader);
1196
+ const parsed = JSON.parse(decoded);
1197
+ const from = parsed?.payload?.authorization?.from;
1198
+ if (typeof from === "string" && /^0x[0-9a-fA-F]{40}$/.test(from)) {
1199
+ return { address: from.toLowerCase(), network: "evm" };
1200
+ }
1201
+ } catch (err) {
1202
+ console.warn("[gate] x402 signer extraction failed:", err instanceof Error ? err.message : err);
1203
+ }
1204
+ }
654
1205
  const authHeader = request.headers.get("authorization");
655
1206
  if (authHeader) {
656
1207
  try {
@@ -670,18 +1221,6 @@ async function extractPaymentSigner(request, x402PaymentHeader) {
670
1221
  console.warn("[gate] MPP signer extraction failed:", err instanceof Error ? err.message : err);
671
1222
  }
672
1223
  }
673
- if (x402PaymentHeader) {
674
- try {
675
- const decoded = atob(x402PaymentHeader);
676
- const parsed = JSON.parse(decoded);
677
- const from = parsed?.payload?.authorization?.from;
678
- if (typeof from === "string" && /^0x[0-9a-fA-F]{40}$/.test(from)) {
679
- return { address: from.toLowerCase(), network: "evm" };
680
- }
681
- } catch (err) {
682
- console.warn("[gate] x402 signer extraction failed:", err instanceof Error ? err.message : err);
683
- }
684
- }
685
1224
  return null;
686
1225
  }
687
1226
  async function extractPaymentSignerFromAuth(authHeader, x402PaymentHeader) {
@@ -771,14 +1310,49 @@ function conditionalAgentscoreGate(options) {
771
1310
  return gate(req, res, next);
772
1311
  };
773
1312
  }
1313
+ var AIT_STATE_KEY = "__agentscoreAit";
1314
+ function defaultAipOnDenied(_req, res, body) {
1315
+ res.status(body.status).type("application/problem+json").json(body);
1316
+ }
1317
+ function aipGate(options) {
1318
+ const { onDenied = defaultAipOnDenied, ...gateOpts } = options;
1319
+ return async function aipGateMiddleware(req, res, next) {
1320
+ const result = await verifyAitParts(
1321
+ { method: req.method, url: req.url, headers: req.headers },
1322
+ gateOpts
1323
+ );
1324
+ if (!result.ok) {
1325
+ onDenied(req, res, buildAipErrorBody(result.failure));
1326
+ return;
1327
+ }
1328
+ req[AIT_STATE_KEY] = result.ait;
1329
+ next();
1330
+ };
1331
+ }
1332
+ function conditionalAipGate(options) {
1333
+ const gate = aipGate(options);
1334
+ return async function conditionalAipMiddleware(req, res, next) {
1335
+ if (!hasAgentIdentityHeaderNode(req.headers)) {
1336
+ next();
1337
+ return;
1338
+ }
1339
+ return gate(req, res, next);
1340
+ };
1341
+ }
1342
+ function getVerifiedAit(req) {
1343
+ return req[AIT_STATE_KEY];
1344
+ }
774
1345
  // Annotate the CommonJS export names for ESM import in node:
775
1346
  0 && (module.exports = {
776
1347
  agentscoreGate,
1348
+ aipGate,
777
1349
  captureWallet,
778
1350
  conditionalAgentscoreGate,
1351
+ conditionalAipGate,
779
1352
  getAgentScoreData,
780
1353
  getGateDegradedState,
781
1354
  getGateQuotaInfo,
782
- getSignerVerdict
1355
+ getSignerVerdict,
1356
+ getVerifiedAit
783
1357
  });
784
1358
  //# sourceMappingURL=express.js.map