@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.
Files changed (80) hide show
  1. package/README.md +19 -17
  2. package/dist/challenge/index.d.mts +31 -3
  3. package/dist/challenge/index.d.ts +31 -3
  4. package/dist/challenge/index.js +25 -9
  5. package/dist/challenge/index.js.map +1 -1
  6. package/dist/challenge/index.mjs +25 -9
  7. package/dist/challenge/index.mjs.map +1 -1
  8. package/dist/{checkout-B-MIzYzW.d.ts → checkout-C4RD7M0Z.d.ts} +117 -13
  9. package/dist/{checkout-Bn7ZKIBD.d.mts → checkout-CzB9f_jf.d.mts} +117 -13
  10. package/dist/core.d.mts +40 -7
  11. package/dist/core.d.ts +40 -7
  12. package/dist/core.js +52 -27
  13. package/dist/core.js.map +1 -1
  14. package/dist/core.mjs +52 -27
  15. package/dist/core.mjs.map +1 -1
  16. package/dist/discovery/index.d.mts +33 -3
  17. package/dist/discovery/index.d.ts +33 -3
  18. package/dist/discovery/index.js +50 -16
  19. package/dist/discovery/index.js.map +1 -1
  20. package/dist/discovery/index.mjs +49 -16
  21. package/dist/discovery/index.mjs.map +1 -1
  22. package/dist/gate-D2RP6bZg.d.ts +307 -0
  23. package/dist/gate-GCXy4FHI.d.mts +307 -0
  24. package/dist/identity/express.d.mts +28 -1
  25. package/dist/identity/express.d.ts +28 -1
  26. package/dist/identity/express.js +714 -31
  27. package/dist/identity/express.js.map +1 -1
  28. package/dist/identity/express.mjs +710 -30
  29. package/dist/identity/express.mjs.map +1 -1
  30. package/dist/identity/fastify.d.mts +14 -2
  31. package/dist/identity/fastify.d.ts +14 -2
  32. package/dist/identity/fastify.js +727 -31
  33. package/dist/identity/fastify.js.map +1 -1
  34. package/dist/identity/fastify.mjs +723 -30
  35. package/dist/identity/fastify.mjs.map +1 -1
  36. package/dist/identity/hono.d.mts +28 -1
  37. package/dist/identity/hono.d.ts +28 -1
  38. package/dist/identity/hono.js +696 -33
  39. package/dist/identity/hono.js.map +1 -1
  40. package/dist/identity/hono.mjs +692 -32
  41. package/dist/identity/hono.mjs.map +1 -1
  42. package/dist/identity/nextjs.d.mts +5 -0
  43. package/dist/identity/nextjs.d.ts +5 -0
  44. package/dist/identity/nextjs.js +695 -30
  45. package/dist/identity/nextjs.js.map +1 -1
  46. package/dist/identity/nextjs.mjs +691 -29
  47. package/dist/identity/nextjs.mjs.map +1 -1
  48. package/dist/identity/policy.d.mts +21 -2
  49. package/dist/identity/policy.d.ts +21 -2
  50. package/dist/identity/policy.js +22 -1
  51. package/dist/identity/policy.js.map +1 -1
  52. package/dist/identity/policy.mjs +21 -1
  53. package/dist/identity/policy.mjs.map +1 -1
  54. package/dist/identity/web.d.mts +26 -1
  55. package/dist/identity/web.d.ts +26 -1
  56. package/dist/identity/web.js +695 -30
  57. package/dist/identity/web.js.map +1 -1
  58. package/dist/identity/web.mjs +691 -29
  59. package/dist/identity/web.mjs.map +1 -1
  60. package/dist/index.d.mts +165 -4
  61. package/dist/index.d.ts +165 -4
  62. package/dist/index.js +3103 -534
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +3086 -545
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/payment/index.d.mts +1 -1
  67. package/dist/payment/index.d.ts +1 -1
  68. package/dist/payment/index.js +10 -2
  69. package/dist/payment/index.js.map +1 -1
  70. package/dist/payment/index.mjs +10 -2
  71. package/dist/payment/index.mjs.map +1 -1
  72. package/dist/stripe-multichain/index.js +1614 -266
  73. package/dist/stripe-multichain/index.js.map +1 -1
  74. package/dist/stripe-multichain/index.mjs +1614 -266
  75. package/dist/stripe-multichain/index.mjs.map +1 -1
  76. package/dist/types-D1slMt0H.d.mts +137 -0
  77. package/dist/types-D1slMt0H.d.ts +137 -0
  78. package/dist/{wwwauthenticate-CVaGUMjU.d.mts → wwwauthenticate-Dgm-_af9.d.mts} +11 -1
  79. package/dist/{wwwauthenticate-CVaGUMjU.d.ts → wwwauthenticate-Dgm-_af9.d.ts} +11 -1
  80. package/package.json +26 -21
@@ -0,0 +1,307 @@
1
+ import { a as AitPayload, T as TrustLevel } from './types-D1slMt0H.js';
2
+ import { JWK } from 'jose';
3
+
4
+ /**
5
+ * AIP IdP key discovery: fetch, cache, and select JWKS signing keys.
6
+ *
7
+ * Verifiers resolve an IdP's public keys from `https://{iss}/.well-known/agent-identity/jwks.json`
8
+ * (the spec's well-known path). This module owns:
9
+ *
10
+ * - **Trusted-issuer enforcement** — only `iss` values on the allowlist are fetched, compared
11
+ * after URL canonicalization (lowercase scheme+host, no default port, no trailing slash) so
12
+ * `https://issuer.example` and `https://issuer.example/` match.
13
+ * - **HTTPS-only** — JWKS over plain HTTP is MITM-vulnerable; we refuse it.
14
+ * - **Caching with a HARD cap** — we honor `Cache-Control: max-age` as advisory but never
15
+ * cache longer than {@link HARD_MAX_CACHE_SECONDS}, regardless of what the IdP sends. A
16
+ * compromised IdP can't pin stale keys with `max-age=31536000`.
17
+ * - **kid-miss refresh** — a lookup for a `kid` not in the cached set triggers one refetch
18
+ * (rotation may have published a new key inside the cache window).
19
+ * - **use:"sig" filtering** — only signing keys are returned.
20
+ *
21
+ * Pure-ish: the only I/O is `fetch`, injectable for tests.
22
+ */
23
+
24
+ /** The spec's well-known JWKS path, relative to the issuer origin. */
25
+ declare const JWKS_WELL_KNOWN_PATH = "/.well-known/agent-identity/jwks.json";
26
+ /** Hard ceiling on cache age, regardless of IdP-supplied Cache-Control. */
27
+ declare const HARD_MAX_CACHE_SECONDS = 86400;
28
+ type FetchLike = (url: string, init?: {
29
+ headers?: Record<string, string>;
30
+ }) => Promise<{
31
+ ok: boolean;
32
+ status: number;
33
+ headers: {
34
+ get(name: string): string | null;
35
+ };
36
+ json(): Promise<unknown>;
37
+ }>;
38
+ /** AgentScore's own AIT issuer. ALWAYS trusted by every {@link JwksCache} (and therefore every
39
+ * gate/adapter built on it) without the merchant listing it — this SDK is the AgentScore
40
+ * verifier, so a merchant can't accidentally fail to trust AgentScore-issued AITs. `trustedIssuers`
41
+ * only needs to name ADDITIONAL external issuers. */
42
+ declare const AGENTSCORE_CANONICAL_ISSUER = "https://www.agentscore.com";
43
+ interface JwksCacheOptions {
44
+ /** ADDITIONAL external issuer URLs to trust beyond AgentScore's own (compared after
45
+ * canonicalization). AgentScore's canonical issuer is always trusted; omit/empty to accept
46
+ * only AgentScore-issued AITs. */
47
+ trustedIssuers?: string[];
48
+ /** Injectable fetch (defaults to global fetch). */
49
+ fetchImpl?: FetchLike;
50
+ /** Injectable clock (ms), for tests. */
51
+ now?: () => number;
52
+ /** User-Agent for JWKS requests. */
53
+ userAgent?: string;
54
+ }
55
+ type JwksLookupFailure = 'untrusted_issuer' | 'insecure_issuer' | 'fetch_failed' | 'malformed_jwks' | 'key_not_found';
56
+ type JwksLookupResult = {
57
+ ok: true;
58
+ key: JWK;
59
+ } | {
60
+ ok: false;
61
+ reason: JwksLookupFailure;
62
+ };
63
+ /**
64
+ * Canonicalize an issuer URL for trust-list comparison: lowercase scheme + host, drop the
65
+ * default port for the scheme, strip a trailing slash on an empty path. Returns null if the
66
+ * input is not a parseable absolute URL.
67
+ */
68
+ declare const canonicalizeIssuer: (iss: string) => string | null;
69
+ /**
70
+ * JWKS resolver bound to a trusted-issuer allowlist. One instance can serve many issuers;
71
+ * each issuer's key set is cached independently.
72
+ */
73
+ declare class JwksCache {
74
+ private readonly trusted;
75
+ private readonly fetchImpl;
76
+ private readonly now;
77
+ private readonly userAgent;
78
+ private readonly cache;
79
+ /** Per-issuer in-flight refresh promise — coalesces concurrent refreshes to ONE upstream fetch.
80
+ * Without it, a concurrent burst of distinct-kid lookups on a cold/expired cache each call
81
+ * `refresh()` before any has populated the cache → N parallel JWKS GETs (refetch amplification).
82
+ * The cooldown only suppresses SEQUENTIAL refetches; single-flight suppresses CONCURRENT ones.
83
+ * Entry is cleared in a `finally` once the fetch settles. */
84
+ private readonly inflight;
85
+ constructor(opts: JwksCacheOptions);
86
+ /** Is this issuer on the canonicalized trust list? */
87
+ isTrusted(iss: string): boolean;
88
+ /**
89
+ * Resolve the signing key for `(iss, kid)`. Enforces trust + HTTPS, serves from cache when
90
+ * fresh, and refetches once on a kid-miss before giving up.
91
+ */
92
+ getKey(iss: string, kid: string | undefined): Promise<JwksLookupResult>;
93
+ private select;
94
+ /**
95
+ * Refresh the cached key set for `canonIssuer`, coalescing concurrent callers onto a single
96
+ * upstream fetch (single-flight). The first caller for an issuer with no in-flight refresh kicks
97
+ * off the fetch and registers the promise; concurrent callers await that same promise instead of
98
+ * issuing their own GET. The entry is cleared once the fetch settles so the NEXT cold/expired
99
+ * lookup can refresh again.
100
+ */
101
+ private refresh;
102
+ private fetchAndCache;
103
+ /** Stamp the per-issuer refetch cooldown on a FAILED fetch attempt (the negative cache). Any
104
+ * previously cached keys + expiry are preserved — a failed kid-miss refetch must not nuke a
105
+ * still-fresh key set; only the cooldown and failure reason are updated. */
106
+ private stampFailure;
107
+ }
108
+
109
+ /**
110
+ * AIP Agent Identity Token (AIT) verification pipeline — the verifier orchestrator.
111
+ *
112
+ * This is the function a merchant gate calls. It executes the spec's verification steps over
113
+ * a presented request, composing the three foundation modules:
114
+ * - {@link ./jwks} — trusted-issuer enforcement + key discovery
115
+ * - {@link ./http-signature} — RFC 9421 proof-of-possession over the request
116
+ * - {@link ./types} — AIT structural contract
117
+ *
118
+ * Steps (per spec):
119
+ * 1. read the `Agent-Identity` header (one or more)
120
+ * 2. decode the JWT header (`kid`) + payload; confirm AIT shape (`cnf` + `agent`)
121
+ * 3. resolve the IdP's signing key from its JWKS (trusted-issuer + HTTPS enforced)
122
+ * 4. verify the IdP signature on the JWT (reject `alg:none`; key is Ed25519)
123
+ * 5. check `exp` / `iat` with skew
124
+ * 6. extract `cnf.jwk`
125
+ * 7. verify the RFC 9421 HTTP Message Signature with `cnf.jwk`
126
+ * 8. confirm the signature `keyid` == JWK thumbprint of `cnf.jwk` (done inside step 7)
127
+ *
128
+ * On success it returns the validated, signature-checked claims. On failure it returns a
129
+ * typed reason that maps onto AIP's wire error codes (the gate turns these into 401/403).
130
+ */
131
+
132
+ /** Header that carries the AIT JWT. */
133
+ declare const AGENT_IDENTITY_HEADER = "agent-identity";
134
+ /** Request fields the verifier needs. Framework-agnostic; adapters map their req onto this. */
135
+ interface VerifyRequestContext {
136
+ method: string;
137
+ authority: string;
138
+ path: string;
139
+ /** All `Agent-Identity` header values present on the request (one per IdP). */
140
+ agentIdentityHeaders: string[];
141
+ signatureInput: string | null;
142
+ signature: string | null;
143
+ }
144
+ interface VerifyAitOptions {
145
+ jwks: JwksCache;
146
+ now?: number;
147
+ maxSkewSeconds?: number;
148
+ /** Max accepted AIT lifetime (`exp - iat`) in seconds. Defense-in-depth vs an external issuer
149
+ * minting a long-lived bearer credential. The spec recommends a 60–300s window; default 300 so a
150
+ * stolen AIT's usable window stays short even at the edge (standalone `aipGate`, no `/v1/assess`).
151
+ * Our own mint is 300s, so first-party tokens sit exactly at the ceiling. Matches the
152
+ * authoritative API verifier's default (the AgentScore API verifier), lowered from 3600. */
153
+ maxLifetimeSeconds?: number;
154
+ }
155
+ /**
156
+ * Failure reasons, aligned with AIP wire error codes. The gate maps:
157
+ * no_token / malformed_token / invalid_signature / expired_token → 401
158
+ * untrusted_issuer / weak_auth / invalid_claims → 403
159
+ */
160
+ type VerifyAitFailure = 'no_token' | 'malformed_token' | 'untrusted_issuer' | 'key_unavailable' | 'idp_signature_invalid' | 'expired_token' | 'invalid_claims' | 'pop_signature_missing' | 'pop_signature_invalid';
161
+ interface VerifiedAit {
162
+ payload: AitPayload;
163
+ /** The issuer (canonical, as presented). */
164
+ iss: string;
165
+ /** The agent's bound public key (`cnf.jwk`). */
166
+ cnfJwk: AitPayload['cnf']['jwk'];
167
+ /** The raw JWT string that verified (the winning `Agent-Identity` header value, Bearer
168
+ * prefix stripped). Lets a gate forward the exact token to `/v1/assess` as `aip_token`. */
169
+ token: string;
170
+ /** The RFC 9421 signature material for this request — forwarded to `/v1/assess` as
171
+ * `aip_signature` so the API re-verifies proof-of-possession authoritatively (the edge
172
+ * check here is only a fail-fast filter; the API is the source of truth). */
173
+ signatureMaterial: {
174
+ method: string;
175
+ authority: string;
176
+ path: string;
177
+ signature_input: string;
178
+ signature: string;
179
+ };
180
+ }
181
+ type VerifyAitResult = {
182
+ ok: true;
183
+ ait: VerifiedAit;
184
+ } | {
185
+ ok: false;
186
+ reason: VerifyAitFailure;
187
+ };
188
+ /**
189
+ * Verify the AIP credential on a request. When multiple `Agent-Identity` headers are present,
190
+ * each is tried; the first that fully verifies AND whose `cnf.jwk` matches the request's
191
+ * RFC 9421 signature wins (all AITs on one request must share the same `cnf` key, so the PoP
192
+ * signature is checked once against the winning key).
193
+ */
194
+ declare const verifyAit: (ctx: VerifyRequestContext, opts: VerifyAitOptions) => Promise<VerifyAitResult>;
195
+
196
+ /**
197
+ * Framework-agnostic AIP gate orchestration.
198
+ *
199
+ * `verifyAitRequest` is the one call a framework adapter makes: hand it a standard `Request`
200
+ * plus a {@link JwksCache}, and it returns the verified AIT claims or a typed failure. The
201
+ * helpers here also map that failure onto the AIP wire contract — HTTP status + error code +
202
+ * an RFC 9457 problem-details body — so every adapter renders denials identically.
203
+ *
204
+ * This layer does identity *verification* only (is this a real, key-bound AIT from a trusted
205
+ * IdP?). Policy enrichment — sanctions, jurisdiction, cross-merchant graph — happens when the
206
+ * merchant additionally feeds the verified claims to `/v1/assess`; that's the gate's choice,
207
+ * not something this module forces.
208
+ */
209
+
210
+ interface AipGateOptions {
211
+ jwks: JwksCache;
212
+ now?: number;
213
+ maxSkewSeconds?: number;
214
+ /** Expected `@authority` (public hostname) the RFC 9421 signature must cover. When set, the
215
+ * verifier binds the signature to this value instead of trusting the inbound `Host` header —
216
+ * pin it to your real public host (e.g. `'wine.example.com'`) when behind a proxy or
217
+ * multi-vhost listener that does not normalize `Host`, to prevent a captured AIT+signature
218
+ * from being replayed to a different virtual host on the same origin. Same semantics as
219
+ * Checkout's `AipGateConfig.authority`. */
220
+ authority?: string;
221
+ /** Minimum `trust_level` (autonomous < human_present < human_confirmed) the AIT must assert —
222
+ * the spec's human-presence gate. Insufficient → 403 weak_auth with `required_trust_level`.
223
+ * Enforced by {@link evaluateAipRequest} / {@link evaluateAipParts}. Unset = any trust level. */
224
+ requireTrustLevel?: TrustLevel;
225
+ /** Acceptable `auth.amr` methods (RFC 8176); the AIT must carry ≥1. Insufficient → 403 weak_auth
226
+ * with `required_amr`. Unset = not enforced. */
227
+ requireAmr?: string[];
228
+ /** Identity claims the endpoint needs — surfaced as `required_claims` on insufficient_claims
229
+ * denials so the agent can self-correct. Advisory only (enforce by feeding the verified claims
230
+ * to your own policy / `/v1/assess`; this gate does identity + trust_level/amr). */
231
+ requiredClaims?: string[];
232
+ /** Trusted issuer URLs surfaced as `trusted_issuers` on untrusted_issuer denials. */
233
+ trustedIssuers?: string[];
234
+ }
235
+ type AipGateResult = {
236
+ ok: true;
237
+ ait: VerifiedAit;
238
+ } | {
239
+ ok: false;
240
+ failure: VerifyAitFailure;
241
+ };
242
+ /** Verify the AIP credential on a standard Fetch `Request` (Hono / Web / Next.js). */
243
+ declare const verifyAitRequest: (req: Request, opts: AipGateOptions) => Promise<AipGateResult>;
244
+ /** Map an internal verify failure to the AIP wire error code (per spec error taxonomy). */
245
+ declare const aipErrorCode: (failure: VerifyAitFailure) => string;
246
+ /** HTTP status for an AIP verify failure: 503 when our infra couldn't reach the IdP (retryable),
247
+ * 403 for trust/claims, 401 for auth-presence/signature. */
248
+ declare const aipErrorStatus: (failure: VerifyAitFailure) => 401 | 403 | 503;
249
+ /** RFC 9457 problem-details body for an AIP denial. Known fields are typed; `required_*` /
250
+ * `trusted_issuers` escalation extensions ride in the index signature. */
251
+ type AipErrorBody = {
252
+ type: string;
253
+ title: string;
254
+ status: number;
255
+ detail: string;
256
+ [k: string]: unknown;
257
+ };
258
+ /** Merchant requirements attached to an AIP escalation body so the agent can self-correct. */
259
+ interface AipErrorRequirements {
260
+ trustedIssuers?: string[];
261
+ requiredClaims?: string[];
262
+ requiredTrustLevel?: TrustLevel;
263
+ requiredAmr?: string[];
264
+ }
265
+ /**
266
+ * Build an RFC 9457 problem-details body for an AIP verify failure. Adapters serialize this as
267
+ * `application/problem+json` with {@link aipErrorStatus}. Optionally carries the merchant's
268
+ * requirements — `trusted_issuers` on untrusted_issuer; `required_claims` / `required_trust_level` /
269
+ * `required_amr` on insufficient_claims — so the agent learns what would satisfy the gate.
270
+ */
271
+ declare const buildAipErrorBody: (failure: VerifyAitFailure, requirements?: AipErrorRequirements) => AipErrorBody;
272
+ /**
273
+ * Check a verified AIT against the gate's `trust_level` / `auth.amr` requirements (the spec's
274
+ * human-presence gate). Returns a detail string when insufficient (→ weak_auth), else null.
275
+ */
276
+ declare const checkTrustRequirements: (payload: {
277
+ trust_level?: string | undefined;
278
+ auth?: {
279
+ amr?: string[] | undefined;
280
+ } | undefined;
281
+ }, requiredTrustLevel?: TrustLevel, requiredAmr?: string[]) => string | null;
282
+ /** Build an RFC 9457 `weak_auth` body for a token that failed the trust_level / auth.amr gate. */
283
+ declare const buildAipWeakAuthBody: (opts: {
284
+ detail: string;
285
+ requiredTrustLevel?: TrustLevel;
286
+ requiredAmr?: string[];
287
+ trustedIssuers?: string[];
288
+ }) => AipErrorBody;
289
+ /** A verified AIT, or a ready-to-render RFC 9457 denial body (HTTP status on `body.status`). */
290
+ type AipGateEvaluation = {
291
+ ok: true;
292
+ ait: VerifiedAit;
293
+ } | {
294
+ ok: false;
295
+ body: AipErrorBody;
296
+ };
297
+ /** Verify + trust-enforce on a standard Fetch `Request` (Hono / Web / Next.js adapters). */
298
+ declare const evaluateAipRequest: (req: Request, opts: AipGateOptions) => Promise<AipGateEvaluation>;
299
+ /** Verify + trust-enforce from Express/Fastify-style parts (Node header map + method + url). */
300
+ declare const evaluateAipParts: (parts: {
301
+ method: string;
302
+ url: string;
303
+ headers: Record<string, string | string[] | undefined>;
304
+ authority?: string;
305
+ }, opts: AipGateOptions) => Promise<AipGateEvaluation>;
306
+
307
+ export { AGENTSCORE_CANONICAL_ISSUER as A, HARD_MAX_CACHE_SECONDS as H, JWKS_WELL_KNOWN_PATH as J, type VerifiedAit as V, AGENT_IDENTITY_HEADER as a, type AipErrorRequirements as b, type AipGateEvaluation as c, type AipGateOptions as d, type AipGateResult as e, JwksCache as f, type JwksCacheOptions as g, type JwksLookupResult as h, type VerifyAitFailure as i, type VerifyAitOptions as j, type VerifyAitResult as k, type VerifyRequestContext as l, aipErrorCode as m, aipErrorStatus as n, buildAipErrorBody as o, buildAipWeakAuthBody as p, canonicalizeIssuer as q, checkTrustRequirements as r, evaluateAipParts as s, evaluateAipRequest as t, verifyAitRequest as u, verifyAit as v };
@@ -0,0 +1,307 @@
1
+ import { a as AitPayload, T as TrustLevel } from './types-D1slMt0H.mjs';
2
+ import { JWK } from 'jose';
3
+
4
+ /**
5
+ * AIP IdP key discovery: fetch, cache, and select JWKS signing keys.
6
+ *
7
+ * Verifiers resolve an IdP's public keys from `https://{iss}/.well-known/agent-identity/jwks.json`
8
+ * (the spec's well-known path). This module owns:
9
+ *
10
+ * - **Trusted-issuer enforcement** — only `iss` values on the allowlist are fetched, compared
11
+ * after URL canonicalization (lowercase scheme+host, no default port, no trailing slash) so
12
+ * `https://issuer.example` and `https://issuer.example/` match.
13
+ * - **HTTPS-only** — JWKS over plain HTTP is MITM-vulnerable; we refuse it.
14
+ * - **Caching with a HARD cap** — we honor `Cache-Control: max-age` as advisory but never
15
+ * cache longer than {@link HARD_MAX_CACHE_SECONDS}, regardless of what the IdP sends. A
16
+ * compromised IdP can't pin stale keys with `max-age=31536000`.
17
+ * - **kid-miss refresh** — a lookup for a `kid` not in the cached set triggers one refetch
18
+ * (rotation may have published a new key inside the cache window).
19
+ * - **use:"sig" filtering** — only signing keys are returned.
20
+ *
21
+ * Pure-ish: the only I/O is `fetch`, injectable for tests.
22
+ */
23
+
24
+ /** The spec's well-known JWKS path, relative to the issuer origin. */
25
+ declare const JWKS_WELL_KNOWN_PATH = "/.well-known/agent-identity/jwks.json";
26
+ /** Hard ceiling on cache age, regardless of IdP-supplied Cache-Control. */
27
+ declare const HARD_MAX_CACHE_SECONDS = 86400;
28
+ type FetchLike = (url: string, init?: {
29
+ headers?: Record<string, string>;
30
+ }) => Promise<{
31
+ ok: boolean;
32
+ status: number;
33
+ headers: {
34
+ get(name: string): string | null;
35
+ };
36
+ json(): Promise<unknown>;
37
+ }>;
38
+ /** AgentScore's own AIT issuer. ALWAYS trusted by every {@link JwksCache} (and therefore every
39
+ * gate/adapter built on it) without the merchant listing it — this SDK is the AgentScore
40
+ * verifier, so a merchant can't accidentally fail to trust AgentScore-issued AITs. `trustedIssuers`
41
+ * only needs to name ADDITIONAL external issuers. */
42
+ declare const AGENTSCORE_CANONICAL_ISSUER = "https://www.agentscore.com";
43
+ interface JwksCacheOptions {
44
+ /** ADDITIONAL external issuer URLs to trust beyond AgentScore's own (compared after
45
+ * canonicalization). AgentScore's canonical issuer is always trusted; omit/empty to accept
46
+ * only AgentScore-issued AITs. */
47
+ trustedIssuers?: string[];
48
+ /** Injectable fetch (defaults to global fetch). */
49
+ fetchImpl?: FetchLike;
50
+ /** Injectable clock (ms), for tests. */
51
+ now?: () => number;
52
+ /** User-Agent for JWKS requests. */
53
+ userAgent?: string;
54
+ }
55
+ type JwksLookupFailure = 'untrusted_issuer' | 'insecure_issuer' | 'fetch_failed' | 'malformed_jwks' | 'key_not_found';
56
+ type JwksLookupResult = {
57
+ ok: true;
58
+ key: JWK;
59
+ } | {
60
+ ok: false;
61
+ reason: JwksLookupFailure;
62
+ };
63
+ /**
64
+ * Canonicalize an issuer URL for trust-list comparison: lowercase scheme + host, drop the
65
+ * default port for the scheme, strip a trailing slash on an empty path. Returns null if the
66
+ * input is not a parseable absolute URL.
67
+ */
68
+ declare const canonicalizeIssuer: (iss: string) => string | null;
69
+ /**
70
+ * JWKS resolver bound to a trusted-issuer allowlist. One instance can serve many issuers;
71
+ * each issuer's key set is cached independently.
72
+ */
73
+ declare class JwksCache {
74
+ private readonly trusted;
75
+ private readonly fetchImpl;
76
+ private readonly now;
77
+ private readonly userAgent;
78
+ private readonly cache;
79
+ /** Per-issuer in-flight refresh promise — coalesces concurrent refreshes to ONE upstream fetch.
80
+ * Without it, a concurrent burst of distinct-kid lookups on a cold/expired cache each call
81
+ * `refresh()` before any has populated the cache → N parallel JWKS GETs (refetch amplification).
82
+ * The cooldown only suppresses SEQUENTIAL refetches; single-flight suppresses CONCURRENT ones.
83
+ * Entry is cleared in a `finally` once the fetch settles. */
84
+ private readonly inflight;
85
+ constructor(opts: JwksCacheOptions);
86
+ /** Is this issuer on the canonicalized trust list? */
87
+ isTrusted(iss: string): boolean;
88
+ /**
89
+ * Resolve the signing key for `(iss, kid)`. Enforces trust + HTTPS, serves from cache when
90
+ * fresh, and refetches once on a kid-miss before giving up.
91
+ */
92
+ getKey(iss: string, kid: string | undefined): Promise<JwksLookupResult>;
93
+ private select;
94
+ /**
95
+ * Refresh the cached key set for `canonIssuer`, coalescing concurrent callers onto a single
96
+ * upstream fetch (single-flight). The first caller for an issuer with no in-flight refresh kicks
97
+ * off the fetch and registers the promise; concurrent callers await that same promise instead of
98
+ * issuing their own GET. The entry is cleared once the fetch settles so the NEXT cold/expired
99
+ * lookup can refresh again.
100
+ */
101
+ private refresh;
102
+ private fetchAndCache;
103
+ /** Stamp the per-issuer refetch cooldown on a FAILED fetch attempt (the negative cache). Any
104
+ * previously cached keys + expiry are preserved — a failed kid-miss refetch must not nuke a
105
+ * still-fresh key set; only the cooldown and failure reason are updated. */
106
+ private stampFailure;
107
+ }
108
+
109
+ /**
110
+ * AIP Agent Identity Token (AIT) verification pipeline — the verifier orchestrator.
111
+ *
112
+ * This is the function a merchant gate calls. It executes the spec's verification steps over
113
+ * a presented request, composing the three foundation modules:
114
+ * - {@link ./jwks} — trusted-issuer enforcement + key discovery
115
+ * - {@link ./http-signature} — RFC 9421 proof-of-possession over the request
116
+ * - {@link ./types} — AIT structural contract
117
+ *
118
+ * Steps (per spec):
119
+ * 1. read the `Agent-Identity` header (one or more)
120
+ * 2. decode the JWT header (`kid`) + payload; confirm AIT shape (`cnf` + `agent`)
121
+ * 3. resolve the IdP's signing key from its JWKS (trusted-issuer + HTTPS enforced)
122
+ * 4. verify the IdP signature on the JWT (reject `alg:none`; key is Ed25519)
123
+ * 5. check `exp` / `iat` with skew
124
+ * 6. extract `cnf.jwk`
125
+ * 7. verify the RFC 9421 HTTP Message Signature with `cnf.jwk`
126
+ * 8. confirm the signature `keyid` == JWK thumbprint of `cnf.jwk` (done inside step 7)
127
+ *
128
+ * On success it returns the validated, signature-checked claims. On failure it returns a
129
+ * typed reason that maps onto AIP's wire error codes (the gate turns these into 401/403).
130
+ */
131
+
132
+ /** Header that carries the AIT JWT. */
133
+ declare const AGENT_IDENTITY_HEADER = "agent-identity";
134
+ /** Request fields the verifier needs. Framework-agnostic; adapters map their req onto this. */
135
+ interface VerifyRequestContext {
136
+ method: string;
137
+ authority: string;
138
+ path: string;
139
+ /** All `Agent-Identity` header values present on the request (one per IdP). */
140
+ agentIdentityHeaders: string[];
141
+ signatureInput: string | null;
142
+ signature: string | null;
143
+ }
144
+ interface VerifyAitOptions {
145
+ jwks: JwksCache;
146
+ now?: number;
147
+ maxSkewSeconds?: number;
148
+ /** Max accepted AIT lifetime (`exp - iat`) in seconds. Defense-in-depth vs an external issuer
149
+ * minting a long-lived bearer credential. The spec recommends a 60–300s window; default 300 so a
150
+ * stolen AIT's usable window stays short even at the edge (standalone `aipGate`, no `/v1/assess`).
151
+ * Our own mint is 300s, so first-party tokens sit exactly at the ceiling. Matches the
152
+ * authoritative API verifier's default (the AgentScore API verifier), lowered from 3600. */
153
+ maxLifetimeSeconds?: number;
154
+ }
155
+ /**
156
+ * Failure reasons, aligned with AIP wire error codes. The gate maps:
157
+ * no_token / malformed_token / invalid_signature / expired_token → 401
158
+ * untrusted_issuer / weak_auth / invalid_claims → 403
159
+ */
160
+ type VerifyAitFailure = 'no_token' | 'malformed_token' | 'untrusted_issuer' | 'key_unavailable' | 'idp_signature_invalid' | 'expired_token' | 'invalid_claims' | 'pop_signature_missing' | 'pop_signature_invalid';
161
+ interface VerifiedAit {
162
+ payload: AitPayload;
163
+ /** The issuer (canonical, as presented). */
164
+ iss: string;
165
+ /** The agent's bound public key (`cnf.jwk`). */
166
+ cnfJwk: AitPayload['cnf']['jwk'];
167
+ /** The raw JWT string that verified (the winning `Agent-Identity` header value, Bearer
168
+ * prefix stripped). Lets a gate forward the exact token to `/v1/assess` as `aip_token`. */
169
+ token: string;
170
+ /** The RFC 9421 signature material for this request — forwarded to `/v1/assess` as
171
+ * `aip_signature` so the API re-verifies proof-of-possession authoritatively (the edge
172
+ * check here is only a fail-fast filter; the API is the source of truth). */
173
+ signatureMaterial: {
174
+ method: string;
175
+ authority: string;
176
+ path: string;
177
+ signature_input: string;
178
+ signature: string;
179
+ };
180
+ }
181
+ type VerifyAitResult = {
182
+ ok: true;
183
+ ait: VerifiedAit;
184
+ } | {
185
+ ok: false;
186
+ reason: VerifyAitFailure;
187
+ };
188
+ /**
189
+ * Verify the AIP credential on a request. When multiple `Agent-Identity` headers are present,
190
+ * each is tried; the first that fully verifies AND whose `cnf.jwk` matches the request's
191
+ * RFC 9421 signature wins (all AITs on one request must share the same `cnf` key, so the PoP
192
+ * signature is checked once against the winning key).
193
+ */
194
+ declare const verifyAit: (ctx: VerifyRequestContext, opts: VerifyAitOptions) => Promise<VerifyAitResult>;
195
+
196
+ /**
197
+ * Framework-agnostic AIP gate orchestration.
198
+ *
199
+ * `verifyAitRequest` is the one call a framework adapter makes: hand it a standard `Request`
200
+ * plus a {@link JwksCache}, and it returns the verified AIT claims or a typed failure. The
201
+ * helpers here also map that failure onto the AIP wire contract — HTTP status + error code +
202
+ * an RFC 9457 problem-details body — so every adapter renders denials identically.
203
+ *
204
+ * This layer does identity *verification* only (is this a real, key-bound AIT from a trusted
205
+ * IdP?). Policy enrichment — sanctions, jurisdiction, cross-merchant graph — happens when the
206
+ * merchant additionally feeds the verified claims to `/v1/assess`; that's the gate's choice,
207
+ * not something this module forces.
208
+ */
209
+
210
+ interface AipGateOptions {
211
+ jwks: JwksCache;
212
+ now?: number;
213
+ maxSkewSeconds?: number;
214
+ /** Expected `@authority` (public hostname) the RFC 9421 signature must cover. When set, the
215
+ * verifier binds the signature to this value instead of trusting the inbound `Host` header —
216
+ * pin it to your real public host (e.g. `'wine.example.com'`) when behind a proxy or
217
+ * multi-vhost listener that does not normalize `Host`, to prevent a captured AIT+signature
218
+ * from being replayed to a different virtual host on the same origin. Same semantics as
219
+ * Checkout's `AipGateConfig.authority`. */
220
+ authority?: string;
221
+ /** Minimum `trust_level` (autonomous < human_present < human_confirmed) the AIT must assert —
222
+ * the spec's human-presence gate. Insufficient → 403 weak_auth with `required_trust_level`.
223
+ * Enforced by {@link evaluateAipRequest} / {@link evaluateAipParts}. Unset = any trust level. */
224
+ requireTrustLevel?: TrustLevel;
225
+ /** Acceptable `auth.amr` methods (RFC 8176); the AIT must carry ≥1. Insufficient → 403 weak_auth
226
+ * with `required_amr`. Unset = not enforced. */
227
+ requireAmr?: string[];
228
+ /** Identity claims the endpoint needs — surfaced as `required_claims` on insufficient_claims
229
+ * denials so the agent can self-correct. Advisory only (enforce by feeding the verified claims
230
+ * to your own policy / `/v1/assess`; this gate does identity + trust_level/amr). */
231
+ requiredClaims?: string[];
232
+ /** Trusted issuer URLs surfaced as `trusted_issuers` on untrusted_issuer denials. */
233
+ trustedIssuers?: string[];
234
+ }
235
+ type AipGateResult = {
236
+ ok: true;
237
+ ait: VerifiedAit;
238
+ } | {
239
+ ok: false;
240
+ failure: VerifyAitFailure;
241
+ };
242
+ /** Verify the AIP credential on a standard Fetch `Request` (Hono / Web / Next.js). */
243
+ declare const verifyAitRequest: (req: Request, opts: AipGateOptions) => Promise<AipGateResult>;
244
+ /** Map an internal verify failure to the AIP wire error code (per spec error taxonomy). */
245
+ declare const aipErrorCode: (failure: VerifyAitFailure) => string;
246
+ /** HTTP status for an AIP verify failure: 503 when our infra couldn't reach the IdP (retryable),
247
+ * 403 for trust/claims, 401 for auth-presence/signature. */
248
+ declare const aipErrorStatus: (failure: VerifyAitFailure) => 401 | 403 | 503;
249
+ /** RFC 9457 problem-details body for an AIP denial. Known fields are typed; `required_*` /
250
+ * `trusted_issuers` escalation extensions ride in the index signature. */
251
+ type AipErrorBody = {
252
+ type: string;
253
+ title: string;
254
+ status: number;
255
+ detail: string;
256
+ [k: string]: unknown;
257
+ };
258
+ /** Merchant requirements attached to an AIP escalation body so the agent can self-correct. */
259
+ interface AipErrorRequirements {
260
+ trustedIssuers?: string[];
261
+ requiredClaims?: string[];
262
+ requiredTrustLevel?: TrustLevel;
263
+ requiredAmr?: string[];
264
+ }
265
+ /**
266
+ * Build an RFC 9457 problem-details body for an AIP verify failure. Adapters serialize this as
267
+ * `application/problem+json` with {@link aipErrorStatus}. Optionally carries the merchant's
268
+ * requirements — `trusted_issuers` on untrusted_issuer; `required_claims` / `required_trust_level` /
269
+ * `required_amr` on insufficient_claims — so the agent learns what would satisfy the gate.
270
+ */
271
+ declare const buildAipErrorBody: (failure: VerifyAitFailure, requirements?: AipErrorRequirements) => AipErrorBody;
272
+ /**
273
+ * Check a verified AIT against the gate's `trust_level` / `auth.amr` requirements (the spec's
274
+ * human-presence gate). Returns a detail string when insufficient (→ weak_auth), else null.
275
+ */
276
+ declare const checkTrustRequirements: (payload: {
277
+ trust_level?: string | undefined;
278
+ auth?: {
279
+ amr?: string[] | undefined;
280
+ } | undefined;
281
+ }, requiredTrustLevel?: TrustLevel, requiredAmr?: string[]) => string | null;
282
+ /** Build an RFC 9457 `weak_auth` body for a token that failed the trust_level / auth.amr gate. */
283
+ declare const buildAipWeakAuthBody: (opts: {
284
+ detail: string;
285
+ requiredTrustLevel?: TrustLevel;
286
+ requiredAmr?: string[];
287
+ trustedIssuers?: string[];
288
+ }) => AipErrorBody;
289
+ /** A verified AIT, or a ready-to-render RFC 9457 denial body (HTTP status on `body.status`). */
290
+ type AipGateEvaluation = {
291
+ ok: true;
292
+ ait: VerifiedAit;
293
+ } | {
294
+ ok: false;
295
+ body: AipErrorBody;
296
+ };
297
+ /** Verify + trust-enforce on a standard Fetch `Request` (Hono / Web / Next.js adapters). */
298
+ declare const evaluateAipRequest: (req: Request, opts: AipGateOptions) => Promise<AipGateEvaluation>;
299
+ /** Verify + trust-enforce from Express/Fastify-style parts (Node header map + method + url). */
300
+ declare const evaluateAipParts: (parts: {
301
+ method: string;
302
+ url: string;
303
+ headers: Record<string, string | string[] | undefined>;
304
+ authority?: string;
305
+ }, opts: AipGateOptions) => Promise<AipGateEvaluation>;
306
+
307
+ export { AGENTSCORE_CANONICAL_ISSUER as A, HARD_MAX_CACHE_SECONDS as H, JWKS_WELL_KNOWN_PATH as J, type VerifiedAit as V, AGENT_IDENTITY_HEADER as a, type AipErrorRequirements as b, type AipGateEvaluation as c, type AipGateOptions as d, type AipGateResult as e, JwksCache as f, type JwksCacheOptions as g, type JwksLookupResult as h, type VerifyAitFailure as i, type VerifyAitOptions as j, type VerifyAitResult as k, type VerifyRequestContext as l, aipErrorCode as m, aipErrorStatus as n, buildAipErrorBody as o, buildAipWeakAuthBody as p, canonicalizeIssuer as q, checkTrustRequirements as r, evaluateAipParts as s, evaluateAipRequest as t, verifyAitRequest as u, verifyAit as v };
@@ -1,5 +1,9 @@
1
+ import { d as AipGateOptions, o as buildAipErrorBody, V as VerifiedAit } from '../gate-GCXy4FHI.mjs';
1
2
  import { AgentScoreCoreOptions, AgentIdentity, DenialReason, CreateSessionOnMissing, AssessResult, FailOpenInfraReason, GateQuotaInfo, SignerVerdict } from '../core.mjs';
2
3
  import { Request, Response, NextFunction } from 'express';
4
+ import '../types-D1slMt0H.mjs';
5
+ import 'jose';
6
+ import '@agent-score/sdk';
3
7
  import '../signer-3FAit11j.mjs';
4
8
 
5
9
  interface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {
@@ -60,5 +64,28 @@ declare function getSignerVerdict(req: Request): SignerVerdict | undefined;
60
64
  * unauthenticated and the handler emits a 402 with all rails; settle legs
61
65
  * trigger the full gate. */
62
66
  declare function conditionalAgentscoreGate(options: AgentScoreGateOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
67
+ interface AipGateExpressOptions extends AipGateOptions {
68
+ /** Custom denial responder. Defaults to a 401/403 `application/problem+json` body. */
69
+ onDenied?: (req: Request, res: Response, body: ReturnType<typeof buildAipErrorBody>) => void;
70
+ }
71
+ /**
72
+ * Express middleware that requires a valid AIT on every request it guards.
73
+ *
74
+ * ```ts
75
+ * import { JwksCache } from '@agent-score/commerce';
76
+ * import { aipGate, getVerifiedAit } from '@agent-score/commerce/identity/express';
77
+ *
78
+ * const jwks = new JwksCache({ trustedIssuers: ['https://issuer.example'] }); // AgentScore always trusted
79
+ * app.post('/checkout', aipGate({ jwks }), (req, res) => {
80
+ * const ait = getVerifiedAit(req)!;
81
+ * res.json({ buyer: ait.payload.identity?.email });
82
+ * });
83
+ * ```
84
+ */
85
+ declare function aipGate(options: AipGateExpressOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
86
+ /** Wrap {@link aipGate} so it only runs when an `Agent-Identity` header is present. */
87
+ declare function conditionalAipGate(options: AipGateExpressOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
88
+ /** Read the verified AIT attached to an Express request by {@link aipGate}. */
89
+ declare function getVerifiedAit(req: Request): VerifiedAit | undefined;
63
90
 
64
- export { agentscoreGate, captureWallet, conditionalAgentscoreGate, getAgentScoreData, getGateDegradedState, getGateQuotaInfo, getSignerVerdict };
91
+ export { type AipGateExpressOptions, agentscoreGate, aipGate, captureWallet, conditionalAgentscoreGate, conditionalAipGate, getAgentScoreData, getGateDegradedState, getGateQuotaInfo, getSignerVerdict, getVerifiedAit };