@agent-score/commerce 2.6.3 → 2.6.5

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 (42) hide show
  1. package/README.md +2 -2
  2. package/dist/{checkout-CzB9f_jf.d.mts → checkout-DOd9GDmt.d.mts} +15 -3
  3. package/dist/{checkout-C4RD7M0Z.d.ts → checkout-GcDNDzSK.d.ts} +15 -3
  4. package/dist/core.js +1 -1
  5. package/dist/core.mjs +1 -1
  6. package/dist/discovery/index.d.mts +1 -1
  7. package/dist/discovery/index.d.ts +1 -1
  8. package/dist/identity/express.js +1 -1
  9. package/dist/identity/express.js.map +1 -1
  10. package/dist/identity/express.mjs +1 -1
  11. package/dist/identity/express.mjs.map +1 -1
  12. package/dist/identity/fastify.js +1 -1
  13. package/dist/identity/fastify.js.map +1 -1
  14. package/dist/identity/fastify.mjs +1 -1
  15. package/dist/identity/fastify.mjs.map +1 -1
  16. package/dist/identity/hono.js +1 -1
  17. package/dist/identity/hono.js.map +1 -1
  18. package/dist/identity/hono.mjs +1 -1
  19. package/dist/identity/hono.mjs.map +1 -1
  20. package/dist/identity/nextjs.js +1 -1
  21. package/dist/identity/nextjs.js.map +1 -1
  22. package/dist/identity/nextjs.mjs +1 -1
  23. package/dist/identity/nextjs.mjs.map +1 -1
  24. package/dist/identity/web.js +1 -1
  25. package/dist/identity/web.js.map +1 -1
  26. package/dist/identity/web.mjs +1 -1
  27. package/dist/identity/web.mjs.map +1 -1
  28. package/dist/index.d.mts +35 -17
  29. package/dist/index.d.ts +35 -17
  30. package/dist/index.js +99 -9
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +97 -9
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/{network_kind-BIJM2peR.d.ts → network_kind-BmbWKNud.d.ts} +23 -1
  35. package/dist/{network_kind-C0EMkdzz.d.mts → network_kind-D2xpo2Fj.d.mts} +23 -1
  36. package/dist/payment/index.d.mts +42 -21
  37. package/dist/payment/index.d.ts +42 -21
  38. package/dist/payment/index.js +53 -0
  39. package/dist/payment/index.js.map +1 -1
  40. package/dist/payment/index.mjs +51 -0
  41. package/dist/payment/index.mjs.map +1 -1
  42. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/identity/web.ts","../../src/_denial.ts","../../src/_response.ts","../../src/aip/verify.ts","../../src/aip/http-signature.ts","../../src/aip/types.ts","../../src/aip/request.ts","../../src/aip/gate.ts","../../src/core.ts","../../src/address.ts","../../src/cache.ts","../../src/payment/payment_header.ts","../../src/signer.ts"],"sourcesContent":["import { denialReasonStatus } from '../_denial';\nimport { denialReasonToBody } from '../_response';\nimport { buildAipErrorBody, evaluateAipRequest, type AipGateOptions } from '../aip/gate';\nimport { hasAgentIdentityHeader } from '../aip/request';\nimport { createAgentScoreCore } from '../core';\nimport { hasPaymentHeader } from '../payment/payment_header';\nimport { extractPaymentSigner, readX402PaymentHeader } from '../signer';\nimport type { VerifiedAit } from '../aip/verify';\nimport type {\n AgentIdentity,\n AgentScoreCoreOptions,\n AssessResult,\n CreateSessionOnMissing,\n DenialReason,\n FailOpenInfraReason,\n GateQuotaInfo,\n SignerVerdict,\n} from '../core';\n\ninterface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {\n /** Custom function to extract agent identity from a Request. */\n extractIdentity?: (req: Request) => AgentIdentity | undefined;\n /** Custom handler invoked when a request is denied. Must return a Response. */\n onDenied?: (req: Request, reason: DenialReason) => Response | Promise<Response>;\n /** Auto-create a verification session on missing identity. Hooks receive the `Request`. */\n createSessionOnMissing?: CreateSessionOnMissing<Request>;\n}\n\n/**\n * Result of a gate check. `allowed: true` means the request passed; forward it to your\n * handler. `allowed: false` means it was denied; return `response` directly to the client.\n *\n * When the request was authenticated via `operator_token`, `captureWallet` is bound to the\n * identity and can be called after payment to report the signer wallet back to AgentScore.\n * When the request was wallet-authenticated (nothing to associate), `captureWallet` is\n * undefined. Always fire-and-forget.\n */\nexport type GuardResult =\n | {\n allowed: true;\n data?: AssessResult;\n captureWallet?: (opts: {\n walletAddress: string;\n network: 'evm' | 'solana';\n idempotencyKey?: string;\n }) => Promise<void>;\n /** Synchronous read of the cached signer verdicts (`signer_match` wallet-binding\n * + `signer_sanctions` OFAC SDN wallet-address check). Both verdicts composed by\n * the gate's primary `/v1/assess` call in one round trip. Bound only on strict\n * wallet-auth requests; `undefined` otherwise (operator-token paths, discovery\n * legs, or routes the gate didn't run on). */\n getSignerVerdict?: () => SignerVerdict | undefined;\n /** Set to `true` only when the gate fail-open'd due to AgentScore-side infra failure\n * (429/5xx/network timeout). Compliance was NOT enforced this request — log/alert. */\n degraded?: boolean;\n /** Why the gate degraded — quota_exceeded / api_error / network_timeout. */\n infraReason?: FailOpenInfraReason;\n /** Per-account assess quota observability from X-Quota-* response headers. */\n quota?: GateQuotaInfo;\n }\n | { allowed: false; response: Response };\n\nfunction defaultExtractIdentity(req: Request): AgentIdentity | undefined {\n const token = req.headers.get('x-operator-token');\n const addr = req.headers.get('x-wallet-address');\n const identity: AgentIdentity = {};\n if (token && token.length > 0) identity.operatorToken = token;\n if (addr && addr.length > 0) identity.address = addr;\n if (identity.operatorToken || identity.address) return identity;\n return undefined;\n}\n\nfunction defaultOnDenied(_req: Request, reason: DenialReason): Response {\n return new Response(JSON.stringify(denialReasonToBody(reason)), {\n status: denialReasonStatus(reason),\n headers: { 'content-type': 'application/json' },\n });\n}\n\n/**\n * Create a Web Fetch-compatible gate. Works with any runtime that speaks the standard\n * Request/Response API: Cloudflare Workers, Deno Deploy, Bun, Next.js App Router, etc.\n *\n * ```ts\n * const guard = createAgentScoreGate({ apiKey: 'as_live_...', requireKyc: true });\n *\n * export default {\n * async fetch(req: Request) {\n * const result = await guard(req);\n * if (!result.allowed) return result.response;\n * return handle(req, result.data);\n * },\n * };\n * ```\n */\nexport function createAgentScoreGate(options: AgentScoreGateOptions): (req: Request) => Promise<GuardResult> {\n const { extractIdentity = defaultExtractIdentity, onDenied = defaultOnDenied, ...coreOptions } = options;\n const core = createAgentScoreCore(coreOptions as AgentScoreCoreOptions);\n\n return async (req: Request): Promise<GuardResult> => {\n const identity = extractIdentity(req);\n // Extract the payment signer pre-evaluate. When present, the API composes\n // signer_match + signer_sanctions verdicts on the primary assess response in one\n // round trip. Wallet-OFAC enforcement is unconditional — SDN wallet hits flip\n // decision -> deny inline before the handler runs, regardless of policy flags.\n const signer = await extractPaymentSigner(req, readX402PaymentHeader(req));\n const outcome = await core.evaluate(identity, req, signer);\n\n if (outcome.kind === 'allow') {\n const captureWallet = identity?.operatorToken\n ? (opts: { walletAddress: string; network: 'evm' | 'solana'; idempotencyKey?: string }) =>\n core.captureWallet({ operatorToken: identity.operatorToken!, ...opts })\n : undefined;\n // Synchronous getter — returns THIS request's signer verdicts (signer_match +\n // signer_sanctions), captured on the per-request `outcome` (NOT a shared core slot) so\n // concurrent same-wallet/different-signer requests can't read each other's verdict. Bound\n // on strict wallet-auth requests (the getter itself returns `undefined` when no signer was\n // in the request); absent for operator-token / AIT paths.\n const signerVerdict = outcome.signerVerdict;\n const getSignerVerdictBound = identity?.address && !identity?.operatorToken\n ? () => signerVerdict\n : undefined;\n return {\n allowed: true,\n data: outcome.data,\n captureWallet,\n getSignerVerdict: getSignerVerdictBound,\n ...(outcome.degraded ? { degraded: true, infraReason: outcome.infraReason } : {}),\n ...(outcome.quota ? { quota: outcome.quota } : {}),\n };\n }\n\n const response = await onDenied(req, outcome.reason);\n return { allowed: false, response };\n };\n}\n\n/**\n * Wrap a Web Fetch request handler with the gate. Denied requests are returned directly;\n * allowed requests are passed to `handler` along with the assess data.\n *\n * ```ts\n * export const POST = withAgentScoreGate(\n * { apiKey: 'as_live_...', requireKyc: true },\n * async (req, { data }) => Response.json({ ok: true }),\n * );\n * ```\n */\nexport function withAgentScoreGate<TCtx = unknown>(\n options: AgentScoreGateOptions,\n handler: (\n req: Request,\n gate: {\n data?: AssessResult;\n captureWallet?: (opts: {\n walletAddress: string;\n network: 'evm' | 'solana';\n idempotencyKey?: string;\n }) => Promise<void>;\n /** Synchronous read of the cached signer verdicts. See {@link GuardResult}'s\n * `getSignerVerdict` for the contract. */\n getSignerVerdict?: () => SignerVerdict | undefined;\n /** Set to `true` only when the gate fail-open'd due to AgentScore-side infra failure\n * (429/5xx/network timeout). Compliance was NOT enforced this request — log/alert. */\n degraded?: boolean;\n /** Why the gate degraded — quota_exceeded / api_error / network_timeout. */\n infraReason?: FailOpenInfraReason;\n /** Per-account assess quota observability from X-Quota-* response headers. */\n quota?: GateQuotaInfo;\n },\n ctx?: TCtx,\n ) => Response | Promise<Response>,\n): (req: Request, ctx?: TCtx) => Promise<Response> {\n const guard = createAgentScoreGate(options);\n return async (req, ctx) => {\n const result = await guard(req);\n if (!result.allowed) return result.response;\n return handler(\n req,\n {\n data: result.data,\n captureWallet: result.captureWallet,\n getSignerVerdict: result.getSignerVerdict,\n ...(result.degraded ? { degraded: true, infraReason: result.infraReason } : {}),\n ...(result.quota ? { quota: result.quota } : {}),\n },\n ctx,\n );\n };\n}\n\n/** Wrap `createAgentScoreGate(...)` so it only fires when a payment credential\n * is attached. Discovery legs flow through allowed (with `data: undefined`)\n * and the handler emits a 402 with all rails; settle legs run the full gate. */\nexport function createConditionalAgentScoreGate(options: AgentScoreGateOptions): (req: Request) => Promise<GuardResult> {\n const guard = createAgentScoreGate(options);\n return async (req: Request): Promise<GuardResult> => {\n if (!hasPaymentHeader(req)) return { allowed: true };\n return guard(req);\n };\n}\n\n/** Wrapper variant matching `withAgentScoreGate(opts, handler)` that only\n * invokes the gate when a payment credential is attached. */\nexport function withConditionalAgentScoreGate<TCtx = unknown>(\n options: AgentScoreGateOptions,\n handler: Parameters<typeof withAgentScoreGate<TCtx>>[1],\n): (req: Request, ctx: TCtx) => Promise<Response> {\n const wrapped = withAgentScoreGate<TCtx>(options, handler);\n return async (req: Request, ctx: TCtx): Promise<Response> => {\n if (!hasPaymentHeader(req)) return handler(req, {}, ctx);\n return wrapped(req, ctx);\n };\n}\n\n// ---------------------------------------------------------------------------\n// AIP gate (Agentic Identity Protocol) — Web Fetch\n//\n// `createAipGate` verifies a key-bound Agent Identity Token (AIT) from a trusted IdP and\n// returns a guard result; `withAipGate` wraps a handler. Fetch-native, so it reuses\n// `verifyAitRequest` directly. Identity verification only — merchants enrich via /v1/assess.\n// ---------------------------------------------------------------------------\n\nexport type AipGuardResult =\n | { allowed: true; ait: VerifiedAit }\n | { allowed: false; response: Response };\n\nexport interface AipGateWebOptions extends AipGateOptions {\n /** Custom denial responder. Defaults to a 401/403 `application/problem+json` Response. */\n onDenied?: (req: Request, body: ReturnType<typeof buildAipErrorBody>) => Response | Promise<Response>;\n}\n\nconst defaultAipResponse = (body: ReturnType<typeof buildAipErrorBody>): Response =>\n new Response(JSON.stringify(body), { status: body.status, headers: { 'content-type': 'application/problem+json' } });\n\n/** Create a Web Fetch AIP guard: returns `{ allowed, ait }` or `{ allowed: false, response }`. */\nexport function createAipGate(options: AipGateWebOptions): (req: Request) => Promise<AipGuardResult> {\n const { onDenied, ...gateOpts } = options;\n return async (req: Request): Promise<AipGuardResult> => {\n const result = await evaluateAipRequest(req, gateOpts);\n if (result.ok) { return { allowed: true, ait: result.ait }; }\n const body = result.body;\n const response = onDenied ? await onDenied(req, body) : defaultAipResponse(body);\n return { allowed: false, response };\n };\n}\n\n/** Wrap a Web Fetch handler with the AIP gate. Denied requests return the problem+json Response. */\nexport function withAipGate<TCtx = unknown>(\n options: AipGateWebOptions,\n handler: (req: Request, gate: { ait: VerifiedAit }, ctx?: TCtx) => Response | Promise<Response>,\n): (req: Request, ctx?: TCtx) => Promise<Response> {\n const guard = createAipGate(options);\n return async (req, ctx) => {\n const result = await guard(req);\n if (!result.allowed) { return result.response; }\n return handler(req, { ait: result.ait }, ctx);\n };\n}\n\n/** Conditional variant: only runs the AIP gate when an `Agent-Identity` header is present. */\nexport function withConditionalAipGate<TCtx = unknown>(\n options: AipGateWebOptions,\n handler: (req: Request, gate: { ait?: VerifiedAit }, ctx?: TCtx) => Response | Promise<Response>,\n): (req: Request, ctx?: TCtx) => Promise<Response> {\n const guard = createAipGate(options);\n return async (req, ctx) => {\n if (!hasAgentIdentityHeader(req)) { return handler(req, {}, ctx); }\n const result = await guard(req);\n if (!result.allowed) { return result.response; }\n return handler(req, { ait: result.ait }, ctx);\n };\n}\n","/**\n * Universal denial helpers shared across every adapter.\n *\n * What lives here:\n * - `FIXABLE_DENIAL_REASONS` / `isFixableDenial` — classifier for compliance reasons that can\n * be resolved by re-completing KYC (vs sanctions / age failures which are permanent).\n * - `denialReasonStatus` — picks the right HTTP status code per denial code (401 for credential\n * problems, 503 for transient API errors, 403 for everything else).\n * - `buildSignerMismatchBody` — produces the standard 403 body for a non-pass signer_match\n * verdict (read via `getSignerVerdict`).\n * - `buildContactSupportNextSteps` — standard `next_steps.action: \"contact_support\"` shape for\n * unfixable compliance denials.\n * - `verificationAgentInstructions` — the canned `agent_instructions` block for\n * identity-verification 403s. Vendors can override individual fields.\n *\n * Adapters use `denialReasonStatus` inside their default `onDenied` so vendors get the right\n * status code for free. The body builders are exported from each adapter so vendors who write\n * a custom `onDenied` can compose them without copy-paste.\n */\n\nimport type { DenialReason, VerifyWalletSignerResult } from './core';\n\n/**\n * Compliance denial reasons that can be resolved by re-completing KYC. The API emits these\n * when KYC is missing/pending/failed; the user can re-verify and retry.\n *\n * `jurisdiction_restricted` is NOT in this set — the API only emits it AFTER KYC is verified,\n * meaning the user's KYC'd country is in the merchant's blocked list (or absent from the\n * allowed list). Re-doing KYC won't change the country, so it's permanent. Same shape as\n * `sanctions_flagged` and `age_insufficient` — surface contact_support, don't waste a\n * /v1/sessions mint.\n */\nexport const FIXABLE_DENIAL_REASONS: ReadonlySet<string> = new Set([\n 'kyc_required',\n 'kyc_pending',\n 'kyc_failed',\n]);\n\n/**\n * Returns true when a `wallet_not_trusted` denial's reasons are all fixable via KYC\n * re-verification. False when any reason is permanent (sanctions, age, jurisdiction_restricted).\n *\n * Empty reasons returns false — without a known reason we can't promise a fix, so default to\n * the bare denial path (vendors can override via custom onDenied if they want different\n * behavior on empty reasons).\n */\nexport function isFixableDenial(reasons: readonly string[] | undefined): boolean {\n if (!reasons || reasons.length === 0) return false;\n return reasons.every((r) => FIXABLE_DENIAL_REASONS.has(r));\n}\n\n/**\n * The right HTTP status code for a denial. `defaultOnDenied` in every adapter uses this so\n * vendors get correct status codes without writing per-code branches.\n *\n * - 401 for credential problems the agent can recover from (`token_expired`, `invalid_credential`)\n * - 503 for transient `api_error`\n * - 403 for everything else (identity required, compliance fail, signer mismatch, etc.)\n */\nexport function denialReasonStatus(reason: DenialReason): 401 | 403 | 503 {\n if (reason.code === 'token_expired' || reason.code === 'invalid_credential') return 401;\n if (reason.code === 'api_error') return 503;\n return 403;\n}\n\n/**\n * Standard 403 body for a non-pass signer-match verdict. Returns null for `pass` so vendors\n * can call it unconditionally:\n *\n * const verdict = getSignerVerdict(c);\n * if (verdict?.signer_match) {\n * const mismatchBody = buildSignerMismatchBody({ result: verdict.signer_match });\n * if (mismatchBody) return c.json(mismatchBody, 403);\n * }\n *\n * Body shape mirrors the gate's denial bodies: top-level error.code, all signer-match fields\n * (`claimed_operator`, `actual_signer_operator`, `expected_signer`, `actual_signer`,\n * `linked_wallets`), plus a `next_steps` action describing the recovery path.\n */\nexport function buildSignerMismatchBody({\n result,\n userMessage,\n learnMoreUrl,\n}: {\n /** Projected signer_match verdict (from `getSignerVerdict(ctx).signer_match`). Only non-pass\n * kinds produce a body. */\n result: VerifyWalletSignerResult;\n /** Optional override for the human-facing `next_steps.user_message`. */\n userMessage?: string;\n /** Optional override for `next_steps.learn_more_url`. Default: AgentScore agent-identity guide. */\n learnMoreUrl?: string;\n}): Record<string, unknown> | null {\n if (result.kind === 'pass') return null;\n\n const learnMoreUrlResolved = learnMoreUrl ?? 'https://docs.agentscore.com/guides/agent-identity';\n\n if (result.kind === 'wallet_signer_mismatch') {\n const linkedWallets = result.linkedWallets ?? [];\n const userMessageResolved = userMessage ?? (linkedWallets.length > 0\n ? `Sign the payment with one of the wallets linked to this operator: ${linkedWallets.join(', ')}. Then retry.`\n : 'Sign the payment with the same wallet you claimed via X-Wallet-Address, or switch to X-Operator-Token for rail-independent identity.');\n return {\n error: {\n code: 'wallet_signer_mismatch',\n message:\n 'Payment signer does not match the wallet claimed via X-Wallet-Address. The signer and the claimed wallet must both resolve to the same AgentScore operator.',\n },\n claimed_operator: result.claimedOperator,\n actual_signer_operator: result.actualSignerOperator ?? null,\n expected_signer: result.expectedSigner,\n actual_signer: result.actualSigner,\n linked_wallets: linkedWallets,\n next_steps: {\n action: 'regenerate_payment_from_linked_wallet',\n user_message: userMessageResolved,\n learn_more_url: learnMoreUrlResolved,\n },\n };\n }\n\n // wallet_auth_requires_wallet_signing\n return {\n error: {\n code: 'wallet_auth_requires_wallet_signing',\n message:\n 'Wallet-auth requires a payment rail that carries a wallet signature (Tempo MPP, x402). Stripe SPT and card rails have no wallet signer; switch to X-Operator-Token to use those.',\n },\n next_steps: {\n action: 'switch_to_operator_token',\n user_message:\n userMessage ??\n 'Drop the X-Wallet-Address header and retry with X-Operator-Token (works on every payment rail).',\n learn_more_url: learnMoreUrlResolved,\n },\n };\n}\n\n/**\n * Standard `next_steps` block for unfixable compliance denials (sanctions, age, etc.). Vendors\n * spread this into a 403 body alongside the usual `error`/`reasons` fields.\n *\n * return c.json({\n * error: { code: 'compliance_denied', message: '...' },\n * reasons,\n * next_steps: buildContactSupportNextSteps('support@example.com'),\n * }, 403);\n */\nexport function buildContactSupportNextSteps(\n supportEmail: string,\n message?: string,\n): { action: 'contact_support'; support_email: string; user_message: string } {\n return {\n action: 'contact_support',\n support_email: supportEmail,\n user_message:\n message ??\n `If you believe this denial is in error, contact support at ${supportEmail} with the details of your request.`,\n };\n}\n\n/**\n * The canonical `agent_instructions` block for identity-verification 403s. Tells the agent how to\n * present the verify_url, poll for the operator_token, and retry the original request. Universal\n * across every AgentScore-gated merchant — overrides let vendors add merchant-specific steps\n * (e.g. \"include order_id when retrying\").\n */\nexport function verificationAgentInstructions({\n userAction,\n retryStep,\n extraSteps,\n pollIntervalSeconds = 5,\n timeoutSeconds = 3600,\n orderTtl,\n extra,\n}: {\n /** Override the user-facing message. */\n userAction?: string;\n /** Replace the generic \"Retry the original merchant request...\" step with a merchant-specific\n * one (e.g. \"Retry POST /purchase with X-Operator-Token AND include order_id...\"). When set,\n * this REPLACES baseSteps[4] rather than appending — use it instead of `extraSteps[0]` when\n * your retry instruction is a refinement of the canonical retry, not an additional step. */\n retryStep?: string;\n /** Append additional steps after the retry step. Use this for genuinely additional steps\n * (e.g. \"After payment the same call returns 200 with the order\"), not for re-stating the\n * retry — use `retryStep` for that. */\n extraSteps?: string[];\n /** Override the poll cadence. Default 5 seconds. */\n pollIntervalSeconds?: number;\n /** Override how long the agent should keep polling. Default 3600 seconds (1 hour). */\n timeoutSeconds?: number;\n /** Optional `order_ttl` note describing how long pending orders survive. */\n orderTtl?: string;\n /** Arbitrary additional fields merged into the instructions object. */\n extra?: Record<string, unknown>;\n} = {}): {\n action: 'poll_for_credential';\n user_action: string;\n steps: string[];\n poll_interval_seconds: number;\n poll_secret_header: 'X-Poll-Secret';\n retry_token_header: 'X-Operator-Token';\n timeout_seconds: number;\n order_ttl?: string;\n [key: string]: unknown;\n} {\n const baseSteps = [\n 'Present the verify_url directly to the user — it is a complete, ready-to-open URL with the session token already embedded (e.g. https://www.agentscore.com/verify?session=sess_...). Do NOT modify or construct the URL yourself.',\n `Immediately begin polling poll_url every ${pollIntervalSeconds} seconds with header X-Poll-Secret set to poll_secret. The user will complete verification in their browser while you poll in the background.`,\n 'The user visits the URL, signs in, completes identity verification (photo ID + selfie via Stripe Identity), and closes the tab. They do NOT need to copy or paste anything back to you.',\n 'When your poll returns status \"verified\", extract operator_token from the response. This is a one-time value — save it immediately. Subsequent polls return status \"consumed\" without the token.',\n retryStep ?? 'Retry the original merchant request with header X-Operator-Token set to the operator_token value.',\n ];\n\n return {\n action: 'poll_for_credential',\n user_action:\n userAction ??\n 'The user must visit verify_url to complete identity verification before this request can proceed',\n steps: extraSteps ? [...baseSteps, ...extraSteps] : baseSteps,\n poll_interval_seconds: pollIntervalSeconds,\n poll_secret_header: 'X-Poll-Secret',\n retry_token_header: 'X-Operator-Token',\n timeout_seconds: timeoutSeconds,\n ...(orderTtl ? { order_ttl: orderTtl } : {}),\n ...(extra ?? {}),\n };\n}\n","/**\n * Shared DenialReason → response body serialization for all adapters.\n *\n * Keeps Hono / Express / Fastify / Web / Next.js defaults aligned — a field added\n * here shows up in every adapter's 403 body automatically, and there's one place\n * to test the marshaling.\n *\n * Body shape: `{ error: { code, message }, ... }` — matches the canonical AgentScore\n * error envelope so downstream agents see one consistent `error.code` +\n * `error.message` pair regardless of which layer produced the denial.\n */\n\nimport type { DenialCode, DenialReason } from './core.js';\n\n/**\n * JSON-encoded canonical agent_instructions per denial code. Auto-injected by\n * `denialReasonToBody` when the gate produces a DenialReason without explicit\n * `agent_instructions` so every denial carries a machine-readable next step.\n *\n * Codes covered:\n * - `wallet_not_trusted` — gate never stamps instructions, fallback ensures coverage\n * - `payment_required` — gate never stamps; merchant tier misconfig, contact-merchant action\n * - `identity_verification_required` — fallback when API didn't return next_steps\n * - `token_expired` — fallback when API didn't return next_steps\n * - `api_error` — `retry_with_backoff` envelope; sole retry channel (no separate\n * next_steps block emitted)\n *\n * Codes already stamped explicitly upstream in core.ts (`missing_identity`,\n * `invalid_credential`) and codes that don't go through DenialReason\n * (`wallet_signer_mismatch`, `wallet_auth_requires_wallet_signing` — handled by\n * `getSignerVerdict` + `buildSignerMismatchBody`) are not in this map.\n */\nconst WALLET_NOT_TRUSTED_INSTRUCTIONS = JSON.stringify({\n action: 'contact_support',\n steps: [\n 'The wallet\\'s operator failed an UNFIXABLE compliance check (sanctions, age, or jurisdiction). `reasons` lists which: `sanctions_flagged` / `age_insufficient` / `jurisdiction_restricted`. KYC re-verification won\\'t change the outcome — the policy denial is structural.',\n 'Surface the denial to the user with the merchant\\'s support contact. Do not retry the same merchant request; do not hand the user a verify_url (verification won\\'t fix this code path).',\n 'Fixable compliance reasons (`kyc_required`, `kyc_pending`, `kyc_failed`) do NOT land on this code — the gate auto-mints a verification session for those and returns `identity_verification_required` with poll endpoints, same shape as `missing_identity`. `jurisdiction_restricted` IS in the unfixable bucket because the API only emits it after KYC is verified (the user\\'s KYC\\'d country is in the blocked list — re-doing KYC won\\'t change the country).',\n ],\n user_message:\n 'This purchase is denied by the merchant\\'s compliance policy and cannot be resolved by re-verifying. Contact the merchant\\'s support if you believe this is in error.',\n});\n\nconst PAYMENT_REQUIRED_INSTRUCTIONS = JSON.stringify({\n action: 'contact_merchant',\n steps: [\n 'The merchant\\'s AgentScore account does not have the assess endpoint enabled, so agent identity cannot be evaluated. This is a merchant-side configuration gap — there is no agent-side recovery.',\n 'Contact the merchant (their support channel — typically listed in /llms.txt or the OpenAPI servers metadata) so they can resolve the configuration on their side.',\n ],\n user_message:\n 'This merchant\\'s identity gate is misconfigured. Contact the merchant — there\\'s nothing to fix on the agent side.',\n});\n\nconst IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({\n action: 'deliver_verify_url_and_poll',\n steps: [\n 'Share verify_url with the user — they complete identity verification on AgentScore.',\n 'If session_id + poll_secret are present in the body, poll poll_url every 5 seconds with header `X-Poll-Secret: <poll_secret>` until status=verified. The poll returns a one-time operator_token.',\n 'Retry the original request with header `X-Operator-Token: <opc_...>`.',\n ],\n user_message:\n 'Identity verification is required. Visit verify_url, then poll poll_url for the operator token and retry.',\n});\n\nconst API_ERROR_INSTRUCTIONS = JSON.stringify({\n action: 'retry_with_backoff',\n steps: [\n 'Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.',\n 'This is NOT a compliance denial — the user does not need to re-verify their identity. Send the same identity headers (X-Wallet-Address or X-Operator-Token) on retry.',\n 'If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant\\'s support contact.',\n ],\n user_message:\n 'Verification is temporarily unavailable. Please try again in a moment — this is a transient issue, not a problem with your account.',\n});\n\nexport const QUOTA_EXCEEDED_INSTRUCTIONS = JSON.stringify({\n action: 'contact_merchant',\n steps: [\n 'AgentScore identity verification is unavailable for this merchant. This is a merchant-side issue and is NOT recoverable via retry.',\n 'Do not retry: the same 503 will be returned until the merchant resolves the issue on their side.',\n 'Surface to the user with the merchant\\'s support contact. The merchant (not the agent) needs to act.',\n ],\n user_message:\n 'This merchant\\'s identity verification is temporarily unavailable. Try again later, or contact the merchant directly.',\n});\n\nconst TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({\n action: 'deliver_verify_url_and_poll',\n steps: [\n 'The operator token is expired or revoked. AgentScore auto-mints a fresh verification session — complete it to receive a new opc_...',\n 'Share verify_url with the user, then poll poll_url every 5 seconds with header `X-Poll-Secret: <poll_secret>` until status=verified. The poll returns a fresh one-time operator_token.',\n 'Retry the original request with header `X-Operator-Token: <new_opc_...>`.',\n ],\n user_message:\n 'Operator token is expired or revoked. A new verification session has been minted — visit verify_url to refresh.',\n});\n\nconst DEFAULT_AGENT_INSTRUCTIONS: Partial<Record<DenialCode, string>> = {\n api_error: API_ERROR_INSTRUCTIONS,\n wallet_not_trusted: WALLET_NOT_TRUSTED_INSTRUCTIONS,\n payment_required: PAYMENT_REQUIRED_INSTRUCTIONS,\n identity_verification_required: IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS,\n token_expired: TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS,\n};\n\nconst DEFAULT_MESSAGES: Record<DenialCode, string> = {\n missing_identity:\n 'No identity provided. Send X-Wallet-Address (wallet) or X-Operator-Token (credential).',\n identity_verification_required:\n 'Identity verification is required to access this resource. Visit verify_url to complete KYC.',\n wallet_not_trusted:\n 'The wallet does not meet the merchant compliance policy.',\n api_error:\n 'AgentScore is unreachable. This is transient — retry in a few seconds.',\n payment_required:\n 'Assess endpoint not enabled for this merchant. Contact support.',\n wallet_signer_mismatch:\n 'Payment signer does not match the wallet claimed via X-Wallet-Address. The signer and the claimed wallet must both resolve to the same AgentScore operator.',\n wallet_auth_requires_wallet_signing:\n 'X-Wallet-Address was sent with a rail that has no wallet signature (Stripe SPT / card). Switch to X-Operator-Token, or use a wallet-signing rail (Tempo MPP, x402).',\n token_expired:\n 'The operator token is expired or revoked. A fresh verification session has been minted — visit verify_url to mint a new token.',\n invalid_credential:\n 'The operator token is not recognized. Switch to a different stored token, or drop the header to bootstrap a fresh session.',\n};\n\n// Field names the gate claims authority over. Merchant-provided `extra` (from the\n// onBeforeSession hook) MUST NOT override these — a buggy or malicious hook could\n// otherwise replace `verify_url` with a phishing URL or drop agent_instructions.\nconst RESERVED_FIELDS = new Set([\n 'error',\n 'decision',\n 'reasons',\n 'verify_url',\n 'session_id',\n 'poll_secret',\n 'poll_url',\n 'agent_instructions',\n 'agent_memory',\n 'claimed_operator',\n 'actual_signer_operator',\n 'expected_signer',\n 'actual_signer',\n 'linked_wallets',\n]);\n\n/**\n * Build the canonical 4xx body shape for `identity_verification_required`.\n *\n * Every merchant maps the gate's auto-minted session fields (verify_url,\n * session_id, poll_secret, poll_url, agent_instructions) into their own\n * envelope with a merchant-specific message + error code. This collapses that\n * mapping into one call:\n *\n * ```ts\n * if (reason.code === 'identity_verification_required') {\n * return {\n * status: 403,\n * body: buildVerificationRequiredBody(reason, {\n * message: 'Identity verification is required to call this endpoint.',\n * agentInstructions: JSON.stringify(VERIFICATION_AGENT_INSTRUCTIONS),\n * }),\n * };\n * }\n * ```\n *\n * Goods merchants that surface an `order_id` (or similar) from\n * `createSessionOnMissing.onBeforeSession` get it for free via\n * `denialReasonToBody(reason)`'s `reason.extra` passthrough — but can also\n * pass `opts.extra` for fallbacks (e.g. when invoked outside the auto-mint\n * path and order_id needs to come from the validated context).\n */\nexport function buildVerificationRequiredBody(\n reason: DenialReason,\n opts: {\n /** Override the `error.message`. Defaults to the canonical copy. */\n message?: string;\n /** Replace `agent_instructions` with merchant-specific copy. When omitted,\n * the gate-supplied or default instructions ride through. */\n agentInstructions?: string;\n /** Additional fields spread into the body (e.g. fallback `order_id`). */\n extra?: Record<string, unknown>;\n } = {},\n): Record<string, unknown> {\n const body = denialReasonToBody(reason);\n body.error = {\n code: 'operator_verification_required',\n message: opts.message ?? 'Identity verification is required.',\n };\n if (opts.agentInstructions !== undefined) {\n body.agent_instructions = opts.agentInstructions;\n }\n if (opts.extra) {\n for (const [k, v] of Object.entries(opts.extra)) body[k] = v;\n }\n return body;\n}\n\nexport function denialReasonToBody(reason: DenialReason): Record<string, unknown> {\n const message = reason.message ?? DEFAULT_MESSAGES[reason.code];\n const body: Record<string, unknown> = { error: { code: reason.code, message } };\n if (reason.decision) body.decision = reason.decision;\n if (reason.reasons) body.reasons = reason.reasons;\n if (reason.verify_url) body.verify_url = reason.verify_url;\n if (reason.session_id) body.session_id = reason.session_id;\n if (reason.poll_secret) body.poll_secret = reason.poll_secret;\n if (reason.poll_url) body.poll_url = reason.poll_url;\n const instructions = reason.agent_instructions ?? DEFAULT_AGENT_INSTRUCTIONS[reason.code];\n if (instructions) body.agent_instructions = instructions;\n if (reason.agent_memory) body.agent_memory = reason.agent_memory;\n if (reason.claimed_operator) body.claimed_operator = reason.claimed_operator;\n if (reason.code === 'wallet_signer_mismatch') body.actual_signer_operator = reason.actual_signer_operator ?? null;\n if (reason.expected_signer) body.expected_signer = reason.expected_signer;\n if (reason.actual_signer) body.actual_signer = reason.actual_signer;\n if (reason.linked_wallets && reason.linked_wallets.length > 0) body.linked_wallets = reason.linked_wallets;\n if (reason.extra) {\n for (const [key, value] of Object.entries(reason.extra)) {\n if (RESERVED_FIELDS.has(key)) {\n console.warn(`[gate] onBeforeSession returned reserved field \"${key}\" — ignoring to preserve gate authority`);\n continue;\n }\n body[key] = value;\n }\n }\n return body;\n}\n","/**\n * AIP Agent Identity Token (AIT) verification pipeline — the verifier orchestrator.\n *\n * This is the function a merchant gate calls. It executes the spec's verification steps over\n * a presented request, composing the three foundation modules:\n * - {@link ./jwks} — trusted-issuer enforcement + key discovery\n * - {@link ./http-signature} — RFC 9421 proof-of-possession over the request\n * - {@link ./types} — AIT structural contract\n *\n * Steps (per spec):\n * 1. read the `Agent-Identity` header (one or more)\n * 2. decode the JWT header (`kid`) + payload; confirm AIT shape (`cnf` + `agent`)\n * 3. resolve the IdP's signing key from its JWKS (trusted-issuer + HTTPS enforced)\n * 4. verify the IdP signature on the JWT (reject `alg:none`; key is Ed25519)\n * 5. check `exp` / `iat` with skew\n * 6. extract `cnf.jwk`\n * 7. verify the RFC 9421 HTTP Message Signature with `cnf.jwk`\n * 8. confirm the signature `keyid` == JWK thumbprint of `cnf.jwk` (done inside step 7)\n *\n * On success it returns the validated, signature-checked claims. On failure it returns a\n * typed reason that maps onto AIP's wire error codes (the gate turns these into 401/403).\n */\n\nimport { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from 'jose';\nimport { verifyMessageSignature } from './http-signature';\nimport { isAitShape, validateAitPayload, type AitPayload } from './types';\nimport type { JwksCache } from './jwks';\n\n/** Header that carries the AIT JWT. */\nexport const AGENT_IDENTITY_HEADER = 'agent-identity';\n\n/** Request fields the verifier needs. Framework-agnostic; adapters map their req onto this. */\nexport interface VerifyRequestContext {\n method: string;\n authority: string;\n path: string;\n /** All `Agent-Identity` header values present on the request (one per IdP). */\n agentIdentityHeaders: string[];\n signatureInput: string | null;\n signature: string | null;\n}\n\nexport interface VerifyAitOptions {\n jwks: JwksCache;\n now?: number;\n maxSkewSeconds?: number;\n /** Max accepted AIT lifetime (`exp - iat`) in seconds. Defense-in-depth vs an external issuer\n * minting a long-lived bearer credential. The spec recommends a 60–300s window; default 300 so a\n * stolen AIT's usable window stays short even at the edge (standalone `aipGate`, no `/v1/assess`).\n * Our own mint is 300s, so first-party tokens sit exactly at the ceiling. Matches the\n * authoritative API verifier's default (the AgentScore API verifier), lowered from 3600. */\n maxLifetimeSeconds?: number;\n}\n\n/**\n * Failure reasons, aligned with AIP wire error codes. The gate maps:\n * no_token / malformed_token / invalid_signature / expired_token → 401\n * untrusted_issuer / weak_auth / invalid_claims → 403\n */\nexport type VerifyAitFailure =\n | 'no_token'\n | 'malformed_token'\n | 'untrusted_issuer'\n | 'key_unavailable'\n | 'idp_signature_invalid'\n | 'expired_token'\n | 'invalid_claims'\n | 'pop_signature_missing'\n | 'pop_signature_invalid';\n\nexport interface VerifiedAit {\n payload: AitPayload;\n /** The issuer (canonical, as presented). */\n iss: string;\n /** The agent's bound public key (`cnf.jwk`). */\n cnfJwk: AitPayload['cnf']['jwk'];\n /** The raw JWT string that verified (the winning `Agent-Identity` header value, Bearer\n * prefix stripped). Lets a gate forward the exact token to `/v1/assess` as `aip_token`. */\n token: string;\n /** The RFC 9421 signature material for this request — forwarded to `/v1/assess` as\n * `aip_signature` so the API re-verifies proof-of-possession authoritatively (the edge\n * check here is only a fail-fast filter; the API is the source of truth). */\n signatureMaterial: {\n method: string;\n authority: string;\n path: string;\n signature_input: string;\n signature: string;\n };\n}\n\nexport type VerifyAitResult =\n | { ok: true; ait: VerifiedAit }\n | { ok: false; reason: VerifyAitFailure };\n\n/**\n * Verify the AIP credential on a request. When multiple `Agent-Identity` headers are present,\n * each is tried; the first that fully verifies AND whose `cnf.jwk` matches the request's\n * RFC 9421 signature wins (all AITs on one request must share the same `cnf` key, so the PoP\n * signature is checked once against the winning key).\n */\nexport const verifyAit = async (\n ctx: VerifyRequestContext,\n opts: VerifyAitOptions,\n): Promise<VerifyAitResult> => {\n if (ctx.agentIdentityHeaders.length === 0) {\n return { ok: false, reason: 'no_token' };\n }\n if (!ctx.signatureInput || !ctx.signature) {\n return { ok: false, reason: 'pop_signature_missing' };\n }\n // Captured post-guard (string, not string|null) — reused for the local fail-fast PoP check and\n // forwarded to /v1/assess so the API can re-verify the same proof-of-possession authoritatively.\n const signatureInput = ctx.signatureInput;\n const signature = ctx.signature;\n\n let lastFailure: VerifyAitFailure = 'malformed_token';\n\n for (const raw of ctx.agentIdentityHeaders) {\n const token = stripBearer(raw);\n\n // Step 2: decode header + payload, confirm AIT shape.\n let header: { alg?: string; kid?: string };\n let payload: unknown;\n try {\n header = decodeProtectedHeader(token);\n payload = decodeJwt(token);\n } catch {\n lastFailure = 'malformed_token';\n continue;\n }\n if (header.alg === undefined || header.alg.toLowerCase() === 'none') {\n lastFailure = 'malformed_token';\n continue;\n }\n if (!isAitShape(payload)) {\n lastFailure = 'malformed_token';\n continue;\n }\n\n // Structural contract (incl. human_confirmed→amr).\n const validated = validateAitPayload(payload);\n if (!validated.ok) {\n lastFailure = 'invalid_claims';\n continue;\n }\n const claims = validated.payload;\n\n // Step 3: resolve IdP key (trusted-issuer + HTTPS enforced inside).\n const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);\n if (!keyLookup.ok) {\n // `untrusted_issuer` (not on the allowlist) and `insecure_issuer` (http:// issuer) are both\n // PERMANENT trust failures → 403, not the retryable 503 of `key_unavailable` (a transient\n // JWKS-fetch problem). Don't tell an agent to retry a config error it can't fix.\n lastFailure =\n keyLookup.reason === 'untrusted_issuer' || keyLookup.reason === 'insecure_issuer'\n ? 'untrusted_issuer'\n : 'key_unavailable';\n continue;\n }\n\n // Step 4 + 5: verify IdP signature; enforce alg match + expiry/skew. The JWT iat/exp tolerance\n // and the RFC 9421 PoP `created`/`expires` window are both 60s (the AIP spec's recommended\n // window). An explicit `maxSkewSeconds` override, when set, applies to both.\n const jwtClockTolerance = opts.maxSkewSeconds ?? 60;\n try {\n const idpKey = await importJWK(keyLookup.key, normalizeAlg(header.alg));\n await jwtVerify(token, idpKey, {\n // Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without\n // this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a\n // non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256\n // token that verifies. Matches the server-side allowlist in the AgentScore API verifier.\n algorithms: AIT_SIGNING_ALGS,\n clockTolerance: jwtClockTolerance,\n currentDate: opts.now !== undefined ? new Date(opts.now * 1000) : undefined,\n });\n } catch (err) {\n lastFailure = isExpiry(err) ? 'expired_token' : 'idp_signature_invalid';\n continue;\n }\n\n // Spec step 5 also requires `iat` not be in the future. jose's `jwtVerify` validates `exp`/`nbf`\n // but does not reject a future `iat` by default, so check it explicitly (same skew tolerance).\n const nowSec = opts.now ?? Math.floor(Date.now() / 1000);\n if (claims.iat > nowSec + jwtClockTolerance) {\n lastFailure = 'expired_token';\n continue;\n }\n\n // Defense-in-depth: reject a long-lived AIT (spec recommends 60–300s). Own mint is exactly 300s,\n // so first-party tokens pass at the ceiling; this bites a trusted EXTERNAL issuer minting a\n // longer-lived bearer credential. Lowered 3600 → 300 (matching the authoritative API verifier)\n // to keep a stolen token's usable window short, complementing the now-mandatory PoP time bound.\n if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {\n lastFailure = 'expired_token';\n continue;\n }\n\n // Step 6 + 7 + 8: PoP — verify the RFC 9421 signature against cnf.jwk.\n const popResult = await verifyMessageSignature({\n method: ctx.method,\n authority: ctx.authority,\n path: ctx.path,\n // The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is\n // transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and\n // the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.\n agentIdentity: token,\n signatureInput,\n signature,\n cnfJwk: claims.cnf.jwk,\n now: opts.now,\n maxSkewSeconds: opts.maxSkewSeconds,\n });\n if (!popResult.ok) {\n lastFailure = 'pop_signature_invalid';\n continue;\n }\n\n return {\n ok: true,\n ait: {\n payload: claims,\n iss: claims.iss,\n cnfJwk: claims.cnf.jwk,\n token,\n signatureMaterial: {\n method: ctx.method,\n authority: ctx.authority,\n path: ctx.path,\n signature_input: signatureInput,\n signature,\n },\n },\n };\n }\n\n return { ok: false, reason: lastFailure };\n};\n\n/** Strip an optional `Bearer ` prefix from a header value. */\nconst stripBearer = (value: string): string => {\n const trimmed = value.trim();\n return /^bearer\\s+/i.test(trimmed) ? trimmed.replace(/^bearer\\s+/i, '') : trimmed;\n};\n\n/** Map a JWT header `alg` to the JOSE alg name jose expects for key import. */\n/** Allowed AIT JWT signature algorithms (RFC 8725 §3.1 allowlist). EdDSA is AIP's default; ES256\n * is permitted for parity with the server-side verifier. Anything else (RS*, HS*, none) is\n * rejected at `jwtVerify`, regardless of what alg the token header claims or the resolved JWK\n * supports. */\nconst AIT_SIGNING_ALGS = ['EdDSA', 'ES256'];\n\nconst normalizeAlg = (alg: string): string => (alg.toLowerCase() === 'eddsa' ? 'EdDSA' : alg);\n\n/** jose throws JWTExpired with code 'ERR_JWT_EXPIRED' on expiry. */\nconst isExpiry = (err: unknown): boolean =>\n typeof err === 'object' && err !== null && (err as { code?: string }).code === 'ERR_JWT_EXPIRED';\n","/**\n * RFC 9421 HTTP Message Signatures — the AIP-constrained subset.\n *\n * AIP (Agentic Identity Protocol) binds an Agent Identity Token (AIT) to the\n * agent that presents it: the agent signs each HTTP request with the private key whose\n * public half is carried in the AIT's `cnf.jwk` (RFC 7800). A verifier reconstructs the\n * RFC 9421 signature base, verifies it against `cnf.jwk`, and confirms the signature's\n * `keyid` equals the JWK thumbprint (RFC 7638) of that key. A stolen AIT is then useless\n * without the bound private key.\n *\n * This module implements ONLY the shape AIP uses, not the full RFC 9421 grammar:\n *\n * - Covered components: the derived components `@method`, `@authority`, `@path`, plus the\n * `agent-identity` header field. (The AIP \"minimum required\" set.) Extra components in a\n * presented signature are accepted and covered if the caller supplies their values.\n * - One labeled signature per request, tagged `tag=\"agent-identity\"`. Web Bot Auth\n * signatures (`tag=\"web-bot-auth\"`) may coexist on the same request under a different\n * label; we select ours by tag, ignoring the rest.\n * - Algorithm: Ed25519 (EdDSA over OKP/Ed25519). AIP's default and only signing curve.\n *\n * The structured-field parsing here is deliberately narrow: it parses the AIP member of the\n * `Signature-Input` / `Signature` dictionaries (a parenthesized inner list + integer/string\n * params, and a single byte-sequence value). It is not a general RFC 8941 parser.\n */\n\nimport { calculateJwkThumbprint, importJWK, type JWK } from 'jose';\n\nconst { subtle } = globalThis.crypto;\n\n/** Runtime-agnostic base64 (standard, not base64url) codecs. The verify path runs on every AIT\n * check, including the Fetch-native web / nextjs adapters that target Cloudflare Workers / Vercel\n * Edge where the Node `Buffer` global is undefined — so decode/encode via `atob`/`btoa`, which are\n * available on every standards runtime (and Node ≥16). */\nconst b64ToBytes = (b64: string): Uint8Array => {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) { out[i] = bin.charCodeAt(i); }\n return out;\n};\n\nconst bytesToB64 = (bytes: Uint8Array): string => {\n let bin = '';\n for (let i = 0; i < bytes.length; i++) { bin += String.fromCharCode(bytes[i]!); }\n return btoa(bin);\n};\n\n/** The AIP \"minimum required\" covered components, in canonical order. */\nexport const AIP_COVERED_COMPONENTS = ['@method', '@authority', '@path', 'agent-identity'] as const;\n\n/** Tag that identifies the AIP signature among coexisting RFC 9421 signatures. */\nexport const AIP_SIGNATURE_TAG = 'agent-identity';\n\n/** Default clock-skew tolerance (seconds) for `created` / `expires`. Aligned to the AIP spec's\n * recommended 60s window (and to the JWT iat/exp tolerance) so the whole AIP check uses one value. */\nconst DEFAULT_MAX_SKEW_SECONDS = 60;\n\n/** Hard ceiling on the PoP signature's own declared lifetime (`expires - created`), in seconds.\n * Requiring `created`+`expires` bounds replay to the declared window — but with no ceiling a\n * malicious trusted-issuer agent could set `expires = created + (AIT lifetime)` and replay for the\n * full window. Cap it tightly so every accepted PoP is short-lived. First-party `pay` signs a 60s\n * window, so it passes; this only bites a signer that declares an over-long PoP. Matches the\n * authoritative API verifier's `MAX_POP_WINDOW_SECONDS` (the AgentScore API verifier) so the\n * edge (standalone `aipGate`) and the API can't drift. (Distinct from the AIT JWT's `exp - iat`\n * ceiling in verify.ts — this is the HTTP-signature layer.) */\nexport const MAX_POP_WINDOW_SECONDS = 120;\n\n/** Parameters parsed from (or used to build) a `Signature-Input` member. */\nexport interface SignatureParams {\n components: string[];\n created?: number;\n expires?: number;\n keyid?: string;\n tag?: string;\n alg?: string;\n}\n\nexport interface VerifyMessageSignatureInput {\n /** HTTP method, e.g. `POST`. Case-insensitive; normalized to upper. */\n method: string;\n /** Authority (host[:port]), e.g. `wine-merchant.com`. Lowercased; default ports dropped. */\n authority: string;\n /** Request path (no query), e.g. `/checkout`. */\n path: string;\n /** Raw value of the `Agent-Identity` header the signature covers. */\n agentIdentity: string;\n /** Raw `Signature-Input` header value. */\n signatureInput: string;\n /** Raw `Signature` header value. */\n signature: string;\n /** The agent's public key from the AIT's `cnf.jwk`. */\n cnfJwk: JWK;\n /** Wall-clock seconds; defaults to now. Injectable for tests. */\n now?: number;\n /** Skew tolerance for created/expires. Defaults to {@link DEFAULT_MAX_SKEW_SECONDS}. */\n maxSkewSeconds?: number;\n /** Extra covered-component values, keyed by component name (for components beyond the AIP minimum). */\n extraComponents?: Record<string, string>;\n}\n\nexport type VerifyFailureReason =\n | 'no_aip_signature'\n | 'malformed_signature_input'\n | 'malformed_signature'\n | 'unsupported_alg'\n | 'missing_keyid'\n | 'keyid_mismatch'\n | 'missing_covered_component'\n | 'created_missing'\n | 'expires_missing'\n | 'pop_window_too_long'\n | 'created_in_future'\n | 'expired'\n | 'unsupported_cnf_key'\n | 'signature_invalid';\n\nexport type VerifyMessageSignatureResult =\n | { ok: true; params: SignatureParams }\n | { ok: false; reason: VerifyFailureReason };\n\n/**\n * Normalize an authority for `@authority` per RFC 9421 §2.2.3: lowercase, drop the default\n * port for the scheme. We don't know the scheme here, so we drop the common defaults (80/443).\n */\nexport const normalizeAuthority = (authority: string): string => {\n const lower = authority.trim().toLowerCase();\n const colon = lower.lastIndexOf(':');\n if (colon === -1) { return lower; }\n // Guard against IPv6 literals like `[::1]` with no port.\n if (lower.includes(']') && colon < lower.indexOf(']')) { return lower; }\n const host = lower.slice(0, colon);\n const port = lower.slice(colon + 1);\n if (port === '80' || port === '443') { return host; }\n return lower;\n};\n\n/** Serialize one derived/header component value into its signature-base line value. */\nconst componentValue = (\n name: string,\n input: { method: string; authority: string; path: string; agentIdentity: string; extra?: Record<string, string> },\n): string | null => {\n switch (name) {\n case '@method':\n return input.method.toUpperCase();\n case '@authority':\n return normalizeAuthority(input.authority);\n case '@path':\n return input.path;\n case 'agent-identity':\n return input.agentIdentity.trim();\n default:\n return input.extra?.[name] ?? null;\n }\n};\n\n/** Serialize the inner-list of covered components: `(\"@method\" \"@authority\" ...)`. */\nconst serializeComponentList = (components: string[]): string =>\n `(${components.map((c) => `\"${c}\"`).join(' ')})`;\n\n/** Serialize the `;k=v` params suffix in canonical order. */\nconst serializeParams = (p: SignatureParams): string => {\n const parts: string[] = [];\n if (p.created !== undefined) { parts.push(`created=${p.created}`); }\n if (p.expires !== undefined) { parts.push(`expires=${p.expires}`); }\n if (p.keyid !== undefined) { parts.push(`keyid=\"${p.keyid}\"`); }\n if (p.alg !== undefined) { parts.push(`alg=\"${p.alg}\"`); }\n if (p.tag !== undefined) { parts.push(`tag=\"${p.tag}\"`); }\n return parts.map((s) => `;${s}`).join('');\n};\n\n/**\n * Build the RFC 9421 signature base: one line per covered component, then the\n * `@signature-params` line. Components are joined by `\\n` with no trailing newline.\n * Throws if a covered component has no available value.\n *\n * On the VERIFY path, pass `rawSignatureParams` — the member value exactly as received from\n * `Signature-Input` — so the base reproduces the signer's serialization byte-for-byte regardless\n * of the order they emitted the params in (RFC 9421 §2.3 puts no order on them). Without it the\n * line is re-serialized in our canonical order (the SIGN path), which would wrongly reject a\n * spec-legal signer that ordered params differently.\n */\nexport const buildSignatureBase = (\n params: SignatureParams,\n input: { method: string; authority: string; path: string; agentIdentity: string; extra?: Record<string, string> },\n rawSignatureParams?: string,\n): string => {\n const lines: string[] = [];\n for (const name of params.components) {\n const value = componentValue(name, input);\n if (value === null) {\n throw new MissingComponentError(name);\n }\n lines.push(`\"${name}\": ${value}`);\n }\n const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);\n lines.push(`\"@signature-params\": ${paramsValue}`);\n return lines.join('\\n');\n};\n\nclass MissingComponentError extends Error {\n constructor(public component: string) {\n super(`signature base missing covered component: ${component}`);\n this.name = 'MissingComponentError';\n }\n}\n\n/**\n * Parse a `Signature-Input` dictionary and return the member tagged `tag`. The tag is REQUIRED\n * (the AIP spec mandates `tag=\"agent-identity\"`): an untagged member is skipped like any\n * wrong-tagged member. `rawParams` is the member's value exactly as received (the inner list +\n * its parameters, byte-for-byte, trimmed of surrounding OWS only) — the verifier echoes it into\n * the `\"@signature-params\"` base line so the signer's param order is preserved.\n * Returns null if no AIP member is found or the member is malformed.\n */\nexport const parseSignatureInput = (header: string, tag = AIP_SIGNATURE_TAG): { label: string; params: SignatureParams; rawParams: string } | null => {\n const members = splitDictionary(header);\n if (members.length === 0) { return null; }\n\n const parsed = members\n .map((m) => {\n const params = parseInnerListMember(m.value);\n return params ? { label: m.label, params, rawParams: m.value } : null;\n })\n .filter((x): x is { label: string; params: SignatureParams; rawParams: string } => x !== null);\n\n if (parsed.length === 0) { return null; }\n\n return parsed.find((p) => p.params.tag === tag) ?? null;\n};\n\n/**\n * Parse a `Signature` dictionary and return the byte-sequence value for `label`.\n * RFC 8941 byte sequences are `:<base64>:`.\n */\nexport const parseSignatureValue = (header: string, label: string): Uint8Array | null => {\n const members = splitDictionary(header);\n const member = members.find((m) => m.label === label);\n if (!member) { return null; }\n const v = member.value.trim();\n if (!v.startsWith(':') || !v.endsWith(':') || v.length < 2) { return null; }\n const b64 = v.slice(1, -1);\n try {\n return b64ToBytes(b64);\n } catch {\n return null;\n }\n};\n\n/** A single `label=value` member of a structured-field dictionary. */\ninterface DictMember { label: string; value: string; }\n\n/**\n * Split a dictionary header into `label=value` members at top-level commas, respecting\n * parentheses (inner lists) and colon-delimited byte sequences so commas inside them\n * don't split. Narrow but correct for the AIP shapes we emit/consume.\n */\nconst splitDictionary = (header: string): DictMember[] => {\n const out: DictMember[] = [];\n let depth = 0;\n let inBytes = false;\n let inString = false;\n let current = '';\n for (let i = 0; i < header.length; i++) {\n const ch = header[i];\n if (inString) {\n current += ch;\n if (ch === '\"' && header[i - 1] !== '\\\\') { inString = false; }\n continue;\n }\n if (ch === '\"') { inString = true; current += ch; continue; }\n if (ch === ':') { inBytes = !inBytes; current += ch; continue; }\n if (!inBytes && ch === '(') { depth++; current += ch; continue; }\n if (!inBytes && ch === ')') { depth = Math.max(0, depth - 1); current += ch; continue; }\n if (!inBytes && depth === 0 && ch === ',') {\n pushMember(out, current);\n current = '';\n continue;\n }\n current += ch;\n }\n pushMember(out, current);\n return out;\n};\n\nconst pushMember = (out: DictMember[], raw: string): void => {\n const trimmed = raw.trim();\n if (!trimmed) { return; }\n const eq = trimmed.indexOf('=');\n if (eq === -1) { return; }\n const label = trimmed.slice(0, eq).trim();\n const value = trimmed.slice(eq + 1).trim();\n if (label) { out.push({ label, value }); }\n};\n\n/** Parse an inner-list member value: `(\"@method\" ...);created=...;keyid=\"...\";tag=\"...\"`. */\nconst parseInnerListMember = (value: string): SignatureParams | null => {\n const open = value.indexOf('(');\n const close = value.indexOf(')', open + 1);\n if (open === -1 || close === -1) { return null; }\n const listBody = value.slice(open + 1, close).trim();\n const components = listBody.length === 0\n ? []\n : (listBody.match(/\"[^\"]*\"/g) ?? []).map((s) => s.slice(1, -1));\n\n const params: SignatureParams = { components };\n const paramStr = value.slice(close + 1);\n // Match ;key=value where value is an integer or a quoted string.\n const re = /;\\s*([a-zA-Z][a-zA-Z0-9_-]*)\\s*=\\s*(\"(?:[^\"\\\\]|\\\\.)*\"|-?\\d+)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(paramStr)) !== null) {\n const key = match[1];\n const raw = match[2];\n const val = raw.startsWith('\"') ? raw.slice(1, -1) : Number(raw);\n if (key === 'created') { params.created = val as number; }\n else if (key === 'expires') { params.expires = val as number; }\n else if (key === 'keyid') { params.keyid = val as string; }\n else if (key === 'tag') { params.tag = val as string; }\n else if (key === 'alg') { params.alg = val as string; }\n }\n return params;\n};\n\n/**\n * Verify an AIP HTTP Message Signature. Performs the full check:\n * 1. select the AIP-tagged member of `Signature-Input`\n * 2. confirm the AIP minimum covered components are present\n * 3. REQUIRE both `created` and `expires`, reject an over-long declared window\n * (`expires - created` > MAX_POP_WINDOW_SECONDS → `pop_window_too_long`), then enforce them\n * against `now` with skew tolerance. Both are mandatory: an optional time bound is no time\n * bound — without `expires` a captured `(token, Signature-Input, Signature)` triple is\n * replayable for the whole AIT lifetime. A signature omitting either is rejected\n * (`created_missing` / `expires_missing`). This matches the authoritative API verifier\n * (the AgentScore API verifier) so a merchant running `aipGate` STANDALONE (the\n * crypto-identity-only deployment with no `/v1/assess`) gets the same replay defense.\n * 4. confirm `keyid` equals the RFC 7638 thumbprint of `cnf.jwk`\n * 5. reconstruct the signature base and verify Ed25519 over it\n *\n * NOTE: this is a STATELESS verifier — it bounds the replay WINDOW but does not dedupe within it.\n * A captured triple can still be replayed until `expires` (≤ MAX_POP_WINDOW_SECONDS + skew from\n * `created`). A stateful seen-signature cache (as in the authoritative API) is out of scope for the\n * SDK edge; the tight window bound is the meaningful mitigation here.\n */\nexport const verifyMessageSignature = async (\n input: VerifyMessageSignatureInput,\n): Promise<VerifyMessageSignatureResult> => {\n const selected = parseSignatureInput(input.signatureInput);\n if (!selected) { return { ok: false, reason: 'no_aip_signature' }; }\n const { label, params, rawParams } = selected;\n\n // The `alg` param is optional in RFC 9421 (the verifier derives the algorithm from the key);\n // when a signer does include it, the registered HTTP-sig label is `ed25519`. Accept that plus the\n // JWS spelling `EdDSA`, case-insensitively, so a spec-loose external signer isn't wrongly rejected\n // — the actual key type is still pinned to OKP/Ed25519 below, so this only affects the label.\n if (params.alg !== undefined && !['ed25519', 'eddsa'].includes(params.alg.toLowerCase())) {\n return { ok: false, reason: 'unsupported_alg' };\n }\n\n // All AIP-minimum components must be covered.\n for (const required of AIP_COVERED_COMPONENTS) {\n if (!params.components.includes(required)) {\n return { ok: false, reason: 'missing_covered_component' };\n }\n }\n\n // REQUIRE both `created` and `expires`. Treating them as optional leaves an unbounded replay\n // window — a captured signature with no `expires` is valid for the AIT's full lifetime. Reject\n // when either is absent so every accepted PoP carries an explicit, enforceable time bound. (Our\n // pay signer always emits both with a 60s window; this only rejects spec-loose external signers.)\n if (params.created === undefined) { return { ok: false, reason: 'created_missing' }; }\n if (params.expires === undefined) { return { ok: false, reason: 'expires_missing' }; }\n\n // Bound the PoP's own declared lifetime. created+expires alone only bound replay to whatever\n // window the SIGNER chose — a malicious trusted-issuer agent could declare a window as wide as the\n // AIT lifetime and replay for all of it. Reject an over-long window so every accepted PoP is\n // short-lived. (pay signs 60s; this only bites a signer declaring > MAX_POP_WINDOW_SECONDS.)\n // A NEGATIVE window (expires before created) is equally malformed — without the explicit check\n // it would slip under the cap (negative < 120).\n if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {\n return { ok: false, reason: 'pop_window_too_long' };\n }\n\n const now = input.now ?? Math.floor(Date.now() / 1000);\n const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;\n if (params.created > now + skew) {\n return { ok: false, reason: 'created_in_future' };\n }\n if (params.expires < now - skew) {\n return { ok: false, reason: 'expired' };\n }\n\n if (!params.keyid) { return { ok: false, reason: 'missing_keyid' }; }\n\n // The RFC 9421 proof-of-possession is verified with the agent's `cnf` key, which AIP binds as\n // Ed25519 (OKP). Validate the key shape BEFORE thumbprinting / importing: a malformed JWK\n // (missing or non-string `x`) makes `calculateJwkThumbprint` throw, and a non-OKP key (e.g. a\n // P-256 EC cnf) makes `importJWK(... 'EdDSA')` throw JOSENotSupported. Neither call site below\n // catches, so an unguarded throw would crash the gate — reject with a typed failure instead.\n // (Note: the JWT alg allowlist permits ES256 for the IDP *issuer* signing key, a different key.)\n const cnf = input.cnfJwk as { kty?: unknown; crv?: unknown; x?: unknown };\n if (cnf.kty !== 'OKP' || cnf.crv !== 'Ed25519' || typeof cnf.x !== 'string' || cnf.x.length === 0) {\n return { ok: false, reason: 'unsupported_cnf_key' };\n }\n\n let thumbprint: string;\n try {\n thumbprint = await calculateJwkThumbprint(input.cnfJwk, 'sha256');\n } catch {\n return { ok: false, reason: 'unsupported_cnf_key' };\n }\n if (params.keyid !== thumbprint) { return { ok: false, reason: 'keyid_mismatch' }; }\n\n const sig = parseSignatureValue(input.signature, label);\n if (!sig) { return { ok: false, reason: 'malformed_signature' }; }\n\n let base: string;\n try {\n base = buildSignatureBase(params, {\n method: input.method,\n authority: input.authority,\n path: input.path,\n agentIdentity: input.agentIdentity,\n extra: input.extraComponents,\n }, rawParams);\n } catch (err) {\n if (err instanceof MissingComponentError) { return { ok: false, reason: 'missing_covered_component' }; }\n throw err;\n }\n\n // cnf key shape (OKP/Ed25519 with a string `x`) was validated above, before thumbprinting.\n let valid: boolean;\n try {\n const key = await importJWK(input.cnfJwk, 'EdDSA');\n if (!(key instanceof CryptoKey)) {\n // jose returns a Uint8Array for symmetric keys; Ed25519 public is always a CryptoKey.\n return { ok: false, reason: 'signature_invalid' };\n }\n valid = await subtle.verify(\n { name: 'Ed25519' },\n key,\n sig as unknown as ArrayBuffer,\n new TextEncoder().encode(base) as unknown as ArrayBuffer,\n );\n } catch {\n // Any crypto/import failure is a verification failure, never an uncaught throw.\n return { ok: false, reason: 'signature_invalid' };\n }\n return valid ? { ok: true, params } : { ok: false, reason: 'signature_invalid' };\n};\n\nexport interface SignMessageInput {\n method: string;\n authority: string;\n path: string;\n agentIdentity: string;\n /** Agent private key (Ed25519 JWK with `d`). */\n privateJwk: JWK;\n /** Agent public key; used to derive `keyid` (thumbprint). */\n publicJwk: JWK;\n created?: number;\n expires?: number;\n /** Signature dictionary label. Defaults to `ait`. */\n label?: string;\n components?: string[];\n extraComponents?: Record<string, string>;\n}\n\n/** Build the `Signature-Input` and `Signature` header values for an AIP request. */\nexport const signMessage = async (\n input: SignMessageInput,\n): Promise<{ signatureInput: string; signature: string }> => {\n const label = input.label ?? 'ait';\n const components = input.components ?? [...AIP_COVERED_COMPONENTS];\n const created = input.created ?? Math.floor(Date.now() / 1000);\n const keyid = await calculateJwkThumbprint(input.publicJwk, 'sha256');\n\n const params: SignatureParams = {\n components,\n created,\n expires: input.expires,\n keyid,\n tag: AIP_SIGNATURE_TAG,\n };\n\n const base = buildSignatureBase(params, {\n method: input.method,\n authority: input.authority,\n path: input.path,\n agentIdentity: input.agentIdentity,\n extra: input.extraComponents,\n });\n\n const key = await importJWK(input.privateJwk, 'EdDSA');\n if (!(key instanceof CryptoKey)) {\n throw new Error('signMessage: expected an Ed25519 private CryptoKey');\n }\n const sigBytes = await subtle.sign(\n 'Ed25519',\n key,\n new TextEncoder().encode(base) as unknown as ArrayBuffer,\n );\n const b64 = bytesToB64(new Uint8Array(sigBytes));\n\n const signatureInput = `${label}=${serializeComponentList(components)}${serializeParams(params)}`;\n const signature = `${label}=:${b64}:`;\n return { signatureInput, signature };\n};\n","/**\n * AIP (Agentic Identity Protocol) token types and the claim contract.\n *\n * An Agent Identity Token (AIT) is a JWT signed by an Identity Provider (IdP). It binds a\n * verified human's identity to the specific agent presenting it (via `cnf`, RFC 7800) and\n * carries the trust level, authentication method, optional intent, and optional identity\n * claims the IdP attests to.\n *\n * This module is the single source of truth for the claim shape on the verifier side. It\n * encodes the spec's required / recommended / optional claims plus the AgentScore extension\n * claims (sanctions, jurisdiction, structured id-verification, cross-merchant graph, payment\n * signer) we carry when we act as a compliance IdP.\n *\n * Extensibility contract (per spec): the `identity` object is open. If a claim is present,\n * the IdP attests to it; verifiers ignore claims they don't recognize. Absence is the\n * \"unknown\" signal — IdPs do not ship `null` for \"not checked\".\n */\n\nimport type { JWK } from 'jose';\n\n/** Degree of human involvement in issuing this specific AIT. */\nexport type TrustLevel = 'autonomous' | 'human_present' | 'human_confirmed';\n\n/**\n * Authentication Method Reference values (RFC 8176 / IANA AMR registry). Open set — these\n * are the values relevant to agent identity; others are valid and pass through.\n */\nexport type AmrValue = 'face' | 'fpt' | 'hwk' | 'otp' | 'pin' | 'pwd' | 'sms' | 'swk' | 'user' | 'mfa';\n\n/** RFC 7800 confirmation claim: binds the AIT to the agent's signing key. */\ninterface CnfClaim {\n jwk: JWK;\n}\n\n/** Agent metadata. `provider` is required; `instance` is recommended. */\ninterface AgentClaim {\n provider: string;\n instance?: string;\n}\n\n/** How the user authorized THIS AIT (not prior authentication history). */\ninterface AuthClaim {\n amr?: AmrValue[] | string[];\n /** When the user authenticated for this token (Unix seconds). Mirrors OIDC `auth_time`. */\n time?: number;\n}\n\n/** What the agent intends to do. Optional; verifiers may require it for non-read actions. */\nexport interface IntentClaim {\n actions?: string[];\n description?: string;\n}\n\n/** AgentScore wallet-binding extension (orthogonal to `cnf`, which binds the agent key). */\ninterface PaymentSignerClaim {\n address: string;\n network: 'evm' | 'solana';\n /** Relationship the IdP attests between signer and the operator graph. */\n match?: 'linked_operator' | 'claimed_operator';\n}\n\ninterface PaymentClaim {\n signer?: PaymentSignerClaim;\n}\n\n/**\n * Identity claims (presence == IdP attestation). Spec-defined fields plus AgentScore\n * compliance extension claims. Open by contract — unknown fields are allowed and ignored.\n */\nexport interface IdentityClaim {\n email?: string;\n email_verified?: boolean;\n name?: string;\n phone?: string;\n phone_verified?: boolean;\n age_over_18?: boolean;\n age_over_21?: boolean;\n id_verified?: boolean;\n\n // --- AgentScore compliance extensions ---\n id_verification?: {\n provider?: string;\n method?: string;\n document_type?: string;\n verified_at?: number;\n };\n /** ISO 3166-1 alpha-2, optionally with ISO 3166-2 subdivision (e.g. \"US-CA\"). */\n jurisdiction?: string;\n sanctions_clear?: boolean;\n sanctions_checked_at?: number;\n sanctions_providers?: string[];\n linked_wallets?: Array<{ address: string; network: 'evm' | 'solana' }>;\n merchants_paid?: number;\n first_seen?: number;\n\n // Open extension space.\n [claim: string]: unknown;\n}\n\n/** The decoded AIT JWT payload. */\nexport interface AitPayload {\n aip_version: string;\n iss: string;\n sub: string;\n iat: number;\n exp: number;\n cnf: CnfClaim;\n agent: AgentClaim;\n trust_level?: TrustLevel;\n auth?: AuthClaim;\n intent?: IntentClaim;\n identity?: IdentityClaim;\n payment?: PaymentClaim;\n [claim: string]: unknown;\n}\n\n/** The decoded AIT JWT header. */\nexport interface AitHeader {\n alg: string;\n typ?: string;\n kid?: string;\n [param: string]: unknown;\n}\n\n/**\n * Structural validation of a decoded AIT payload. Confirms the required claims are present\n * and well-typed, and enforces the one normative conditional in the spec: a\n * `human_confirmed` token MUST carry at least one `auth.amr` value.\n *\n * This is shape/contract validation only — it does NOT verify signatures (that's the\n * verifier pipeline) and does NOT apply trust policy (that's the gate / `/v1/assess`).\n */\nexport type AitValidationResult =\n | { ok: true; payload: AitPayload }\n | { ok: false; reason: AitValidationFailure };\n\ntype AitValidationFailure =\n | 'not_an_object'\n | 'missing_aip_version'\n | 'missing_iss'\n | 'missing_sub'\n | 'missing_iat'\n | 'missing_exp'\n | 'missing_cnf'\n | 'missing_agent_provider'\n | 'human_confirmed_without_amr';\n\nconst isObject = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.length > 0;\n\n/**\n * Detect whether a decoded JWT payload is an AIT: per spec, an AIT is discriminated by the\n * presence of `cnf` + `agent` claims (not the `typ` header).\n */\nexport const isAitShape = (payload: unknown): boolean =>\n isObject(payload) && isObject(payload.cnf) && isObject(payload.agent);\n\n/** Validate the structural contract of a decoded AIT payload. */\nexport const validateAitPayload = (payload: unknown): AitValidationResult => {\n if (!isObject(payload)) { return { ok: false, reason: 'not_an_object' }; }\n if (!isNonEmptyString(payload.aip_version)) { return { ok: false, reason: 'missing_aip_version' }; }\n if (!isNonEmptyString(payload.iss)) { return { ok: false, reason: 'missing_iss' }; }\n if (!isNonEmptyString(payload.sub)) { return { ok: false, reason: 'missing_sub' }; }\n if (typeof payload.iat !== 'number') { return { ok: false, reason: 'missing_iat' }; }\n if (typeof payload.exp !== 'number') { return { ok: false, reason: 'missing_exp' }; }\n if (!isObject(payload.cnf) || !isObject((payload.cnf as Record<string, unknown>).jwk)) {\n return { ok: false, reason: 'missing_cnf' };\n }\n if (!isObject(payload.agent) || !isNonEmptyString((payload.agent as Record<string, unknown>).provider)) {\n return { ok: false, reason: 'missing_agent_provider' };\n }\n\n // Normative conditional: human_confirmed requires auth.amr with at least one value.\n if (payload.trust_level === 'human_confirmed') {\n const auth = payload.auth;\n const amr = isObject(auth) ? auth.amr : undefined;\n if (!Array.isArray(amr) || amr.length === 0) {\n return { ok: false, reason: 'human_confirmed_without_amr' };\n }\n }\n\n return { ok: true, payload: payload as AitPayload };\n};\n","/**\n * Build an AIP {@link VerifyRequestContext} from a standard WHATWG `Request`.\n *\n * Every framework adapter ultimately has (or can produce) a `Request`: Hono exposes\n * `c.req.raw`, Next.js / Web Fetch hand you one directly, and Express/Fastify can be shimmed.\n * This helper centralizes the header + URL extraction so adapters stay thin and the parsing\n * rules (authority derivation, multiple `Agent-Identity` headers) live in one place.\n */\n\nimport { AGENT_IDENTITY_HEADER, type VerifyRequestContext } from './verify';\n\n/**\n * Read all values of a possibly-repeated header. The Fetch `Headers` object folds repeated\n * headers into a single comma-joined value; for `Agent-Identity` we must split them back out\n * because each AIT is an independent JWT. JWTs are base64url dot-separated and never contain a\n * bare comma, so splitting on `,` is safe.\n */\nconst readAgentIdentityHeaders = (headers: Headers): string[] => {\n const raw = headers.get(AGENT_IDENTITY_HEADER);\n if (!raw) { return []; }\n return raw\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n};\n\n/**\n * Derive `@authority` for RFC 9421. Prefer the `Host` header (what the client addressed);\n * fall back to the URL host. Returned as-is; {@link normalizeAuthority} canonicalizes during\n * signature-base construction.\n */\nconst deriveAuthority = (req: Request, url: URL): string => req.headers.get('host') ?? url.host;\n\n/** Build the framework-agnostic verify context from a standard `Request`. A configured\n * `authority` pin (e.g. `AipGateOptions.authority`) wins over the inbound `Host` header. */\nexport const buildVerifyContextFromRequest = (req: Request, authority?: string): VerifyRequestContext => {\n const url = new URL(req.url);\n return {\n method: req.method,\n authority: authority ?? deriveAuthority(req, url),\n path: url.pathname,\n agentIdentityHeaders: readAgentIdentityHeaders(req.headers),\n signatureInput: req.headers.get('signature-input'),\n signature: req.headers.get('signature'),\n };\n};\n\n/** True when the request carries an AIP credential (at least one `Agent-Identity` header). */\nexport const hasAgentIdentityHeader = (req: Request): boolean =>\n readAgentIdentityHeaders(req.headers).length > 0;\n\n/** Read a header from a Node-style header map (value may be string | string[] | undefined). */\nconst readNodeHeader = (\n headers: Record<string, string | string[] | undefined>,\n name: string,\n): string | undefined => {\n const v = headers[name] ?? headers[name.toLowerCase()];\n if (v === undefined) { return undefined; }\n return Array.isArray(v) ? v.join(', ') : v;\n};\n\n/** True when a Node-style header map carries an `Agent-Identity` header. */\nexport const hasAgentIdentityHeaderNode = (\n headers: Record<string, string | string[] | undefined>,\n): boolean => {\n const raw = readNodeHeader(headers, 'agent-identity');\n return raw !== undefined && raw.split(',').some((s) => s.trim().length > 0);\n};\n\n/**\n * Build the verify context from Express/Fastify-style parts (Node header map + method + URL).\n * These frameworks don't expose a Fetch `Request`, so adapters pass raw pieces here.\n */\nexport const buildVerifyContextFromParts = (parts: {\n method: string;\n /** Full request URL, or just the path. Used to derive `@path`. */\n url: string;\n /** Node header map. */\n headers: Record<string, string | string[] | undefined>;\n /** Authority override; falls back to the `host` header. */\n authority?: string;\n}): VerifyRequestContext => {\n const agentIdentityRaw = readNodeHeader(parts.headers, 'agent-identity');\n const agentIdentityHeaders = agentIdentityRaw\n ? agentIdentityRaw.split(',').map((s) => s.trim()).filter((s) => s.length > 0)\n : [];\n const host = parts.authority ?? readNodeHeader(parts.headers, 'host') ?? '';\n // url may be an absolute URL or an origin-form target (\"/checkout?...\", possibly \"//x\"). Build\n // the URL by APPENDING the target to the origin (not resolving it as a reference) so a leading\n // \"//\" is treated as PATH — `new URL('//x', base)` would mis-read \"//x\" as a protocol-relative\n // authority and drop it, diverging from the signer's `URL.pathname` and failing PoP.\n // Always assigned in both branches below, so no initializer (avoids a dead assignment).\n let path: string;\n try {\n if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(parts.url)) {\n path = new URL(parts.url).pathname;\n } else {\n const target = parts.url.startsWith('/') ? parts.url : `/${parts.url}`;\n path = new URL(`http://${host || 'localhost'}${target}`).pathname;\n }\n } catch {\n const q = parts.url.indexOf('?');\n path = q === -1 ? parts.url : parts.url.slice(0, q);\n }\n return {\n method: parts.method,\n authority: host,\n path,\n agentIdentityHeaders,\n signatureInput: readNodeHeader(parts.headers, 'signature-input') ?? null,\n signature: readNodeHeader(parts.headers, 'signature') ?? null,\n };\n};\n","/**\n * Framework-agnostic AIP gate orchestration.\n *\n * `verifyAitRequest` is the one call a framework adapter makes: hand it a standard `Request`\n * plus a {@link JwksCache}, and it returns the verified AIT claims or a typed failure. The\n * helpers here also map that failure onto the AIP wire contract — HTTP status + error code +\n * an RFC 9457 problem-details body — so every adapter renders denials identically.\n *\n * This layer does identity *verification* only (is this a real, key-bound AIT from a trusted\n * IdP?). Policy enrichment — sanctions, jurisdiction, cross-merchant graph — happens when the\n * merchant additionally feeds the verified claims to `/v1/assess`; that's the gate's choice,\n * not something this module forces.\n */\n\nimport { buildVerifyContextFromParts, buildVerifyContextFromRequest } from './request';\nimport { verifyAit, type VerifiedAit, type VerifyAitFailure, type VerifyRequestContext } from './verify';\nimport type { JwksCache } from './jwks';\nimport type { TrustLevel } from './types';\n\nexport interface AipGateOptions {\n jwks: JwksCache;\n now?: number;\n maxSkewSeconds?: number;\n /** Expected `@authority` (public hostname) the RFC 9421 signature must cover. When set, the\n * verifier binds the signature to this value instead of trusting the inbound `Host` header —\n * pin it to your real public host (e.g. `'wine.example.com'`) when behind a proxy or\n * multi-vhost listener that does not normalize `Host`, to prevent a captured AIT+signature\n * from being replayed to a different virtual host on the same origin. Same semantics as\n * Checkout's `AipGateConfig.authority`. */\n authority?: string;\n /** Minimum `trust_level` (autonomous < human_present < human_confirmed) the AIT must assert —\n * the spec's human-presence gate. Insufficient → 403 weak_auth with `required_trust_level`.\n * Enforced by {@link evaluateAipRequest} / {@link evaluateAipParts}. Unset = any trust level. */\n requireTrustLevel?: TrustLevel;\n /** Acceptable `auth.amr` methods (RFC 8176); the AIT must carry ≥1. Insufficient → 403 weak_auth\n * with `required_amr`. Unset = not enforced. */\n requireAmr?: string[];\n /** Identity claims the endpoint needs — surfaced as `required_claims` on insufficient_claims\n * denials so the agent can self-correct. Advisory only (enforce by feeding the verified claims\n * to your own policy / `/v1/assess`; this gate does identity + trust_level/amr). */\n requiredClaims?: string[];\n /** Trusted issuer URLs surfaced as `trusted_issuers` on untrusted_issuer denials. */\n trustedIssuers?: string[];\n}\n\nexport type AipGateResult =\n | { ok: true; ait: VerifiedAit }\n | { ok: false; failure: VerifyAitFailure };\n\n/** Verify the AIP credential from a pre-built context. Shared by all adapter entry points. */\nconst verifyFromContext = async (ctx: VerifyRequestContext, opts: AipGateOptions): Promise<AipGateResult> => {\n const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });\n return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };\n};\n\n/** Apply the gate's configured `authority` pin to a parts object: an explicit per-call\n * `parts.authority` (e.g. Checkout's) wins, then the gate option, then the inbound `Host`. */\nconst partsWithAuthority = (\n parts: { method: string; url: string; headers: Record<string, string | string[] | undefined>; authority?: string },\n opts: AipGateOptions,\n): typeof parts => {\n const authority = parts.authority ?? opts.authority;\n return authority !== undefined ? { ...parts, authority } : parts;\n};\n\n/** Verify the AIP credential on a standard Fetch `Request` (Hono / Web / Next.js). */\nexport const verifyAitRequest = (req: Request, opts: AipGateOptions): Promise<AipGateResult> =>\n verifyFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);\n\n/** Verify the AIP credential from Express/Fastify-style parts (Node header map + method + url). */\nexport const verifyAitParts = (\n parts: { method: string; url: string; headers: Record<string, string | string[] | undefined>; authority?: string },\n opts: AipGateOptions,\n): Promise<AipGateResult> => verifyFromContext(buildVerifyContextFromParts(partsWithAuthority(parts, opts)), opts);\n\n/** Map an internal verify failure to the AIP wire error code (per spec error taxonomy). */\nexport const aipErrorCode = (failure: VerifyAitFailure): string => {\n switch (failure) {\n case 'no_token':\n case 'pop_signature_missing':\n return 'agent_identity_required';\n case 'untrusted_issuer':\n return 'untrusted_issuer';\n case 'expired_token':\n return 'expired_token';\n case 'invalid_claims':\n return 'insufficient_claims';\n case 'key_unavailable':\n // The IdP's JWKS could not be fetched/resolved — our infra couldn't reach a trusted\n // issuer, not a client-side auth failure. Distinct code so agents back off + retry\n // rather than uselessly re-signing.\n return 'idp_unavailable';\n case 'malformed_token':\n case 'idp_signature_invalid':\n case 'pop_signature_invalid':\n return 'invalid_signature';\n default:\n return 'invalid_signature';\n }\n};\n\n/** HTTP status for an AIP verify failure: 503 when our infra couldn't reach the IdP (retryable),\n * 403 for trust/claims, 401 for auth-presence/signature. */\nexport const aipErrorStatus = (failure: VerifyAitFailure): 401 | 403 | 503 => {\n switch (failure) {\n case 'key_unavailable':\n return 503;\n case 'untrusted_issuer':\n case 'invalid_claims':\n return 403;\n default:\n return 401;\n }\n};\n\n/** Human-readable detail for the failure, for the problem-details body. */\nconst aipErrorDetail = (failure: VerifyAitFailure): string => {\n switch (failure) {\n case 'no_token':\n return 'No Agent-Identity token was presented.';\n case 'pop_signature_missing':\n return 'The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.';\n case 'untrusted_issuer':\n return \"The token's issuer is not in this service's trusted-issuer list.\";\n case 'expired_token':\n return 'The Agent Identity Token has expired.';\n case 'invalid_claims':\n return 'The token is missing required claims for this endpoint.';\n case 'malformed_token':\n return 'The Agent-Identity header could not be parsed as an Agent Identity Token.';\n case 'idp_signature_invalid':\n return \"The identity provider's signature on the token failed verification.\";\n case 'pop_signature_invalid':\n return 'The request signature did not match the key bound to the token.';\n case 'key_unavailable':\n return \"The identity provider's signing key could not be resolved.\";\n default:\n return 'Token verification failed.';\n }\n};\n\n/** RFC 9457 problem-details body for an AIP denial. Known fields are typed; `required_*` /\n * `trusted_issuers` escalation extensions ride in the index signature. */\nexport type AipErrorBody = { type: string; title: string; status: number; detail: string; [k: string]: unknown };\n\n/** Merchant requirements attached to an AIP escalation body so the agent can self-correct. */\nexport interface AipErrorRequirements {\n trustedIssuers?: string[];\n requiredClaims?: string[];\n requiredTrustLevel?: TrustLevel;\n requiredAmr?: string[];\n}\n\n/**\n * Build an RFC 9457 problem-details body for an AIP verify failure. Adapters serialize this as\n * `application/problem+json` with {@link aipErrorStatus}. Optionally carries the merchant's\n * requirements — `trusted_issuers` on untrusted_issuer; `required_claims` / `required_trust_level` /\n * `required_amr` on insufficient_claims — so the agent learns what would satisfy the gate.\n */\nexport const buildAipErrorBody = (failure: VerifyAitFailure, requirements?: AipErrorRequirements): AipErrorBody => {\n const code = aipErrorCode(failure);\n const body: AipErrorBody = {\n type: `urn:aip:error:${code}`,\n title: code.replace(/_/g, ' '),\n status: aipErrorStatus(failure),\n detail: aipErrorDetail(failure),\n };\n if (requirements) {\n if (code === 'untrusted_issuer' && requirements.trustedIssuers?.length) {\n body.trusted_issuers = requirements.trustedIssuers;\n }\n if (code === 'insufficient_claims') {\n if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;\n if (requirements.requiredTrustLevel !== undefined) body.required_trust_level = requirements.requiredTrustLevel;\n if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;\n }\n }\n return body;\n};\n\n/**\n * Map an AgentScore *policy-deny* code (a `/v1/assess` decision, NOT a verify failure) to its\n * spec AIP error code + HTTP status. This is the policy-side counterpart to {@link aipErrorCode}\n * (which maps the verify-FAILURE taxonomy). On the AIT-input path a denied `/v1/assess` decision\n * surfaces as one of these AgentScore codes; the spec's fixed error set expresses each as:\n * - `token_expired` → `expired_token` (401)\n * - `invalid_credential` → `invalid_signature` (401)\n * - `api_error` → `idp_unavailable` (503, transient — the claims couldn't be evaluated)\n * - everything else (compliance: `wallet_not_trusted` + `sanctions_flagged` / `age_insufficient`\n * / `jurisdiction_restricted` / `kyc_*`) → `insufficient_claims` (403): the AIT did not attest\n * (or attested a failing value for) the required compliance claim.\n */\nconst aipPolicyDenyCode = (code: string): { code: string; status: 401 | 403 | 503 } => {\n switch (code) {\n case 'token_expired':\n return { code: 'expired_token', status: 401 };\n case 'invalid_credential':\n return { code: 'invalid_signature', status: 401 };\n case 'api_error':\n return { code: 'idp_unavailable', status: 503 };\n default:\n return { code: 'insufficient_claims', status: 403 };\n }\n};\n\n/**\n * Wrap an AgentScore AIT-path denial body in the RFC 9457 + AIP-spec superset.\n *\n * Reuses {@link buildAipErrorBody}'s SHAPE convention (`type`/`title`/`status`/`detail` +\n * escalation extensions) but for the *policy-deny* case — a verified AIT that `/v1/assess` then\n * denied — which carries an AgentScore compliance/credential code, not a verify-failure reason.\n *\n * The result is a SUPERSET: the canonical `{ error, agent_instructions, ... }` body is spread in\n * verbatim (so existing consumers keep parsing `error.code`), with the RFC 9457 envelope layered\n * on top. `detail` names the precise AgentScore reason(s); `error.code` stays the AgentScore code.\n * Escalation fields (`required_claims` / `required_trust_level` / `required_amr` on\n * insufficient_claims, `trusted_issuers` on untrusted_issuer) ride along when known.\n */\nexport const buildAipPolicyDenyBody = (\n code: string,\n reasons: string[] | undefined,\n body: Record<string, unknown>,\n requirements?: AipErrorRequirements,\n): Record<string, unknown> => {\n const spec = aipPolicyDenyCode(code);\n const reasonList = reasons ?? [];\n const detail =\n spec.code === 'insufficient_claims'\n ? reasonList.length > 0\n ? `The Agent Identity Token did not attest a passing value for the required compliance claim(s). AgentScore decision: ${code} (${reasonList.join(', ')}).`\n : `The Agent Identity Token did not satisfy the merchant's compliance policy. AgentScore decision: ${code}.`\n : `AgentScore decision: ${code}.`;\n const superset: Record<string, unknown> = {\n type: `urn:aip:error:${spec.code}`,\n title: spec.code.replace(/_/g, ' '),\n status: spec.status,\n detail,\n };\n // Escalation extensions, scoped exactly as the spec mandates: `required_claims` /\n // `required_trust_level` / `required_amr` on insufficient_claims. `trusted_issuers` belongs to\n // untrusted_issuer — a VERIFY failure that never reaches the policy-deny path — so it is not\n // emitted here (the edge-deny `buildAipErrorBody` owns that one).\n if (requirements && spec.code === 'insufficient_claims') {\n if (requirements.requiredClaims?.length) superset.required_claims = requirements.requiredClaims;\n if (requirements.requiredTrustLevel !== undefined) superset.required_trust_level = requirements.requiredTrustLevel;\n if (requirements.requiredAmr?.length) superset.required_amr = requirements.requiredAmr;\n }\n // Spread the canonical body LAST so `error` / `agent_instructions` / `reasons` win verbatim —\n // the RFC 9457 fields are additive and never clobber the rich AgentScore scheme. The envelope\n // fields themselves (`type` / `title` / `status` / `detail`) are RESERVED the other way: the\n // canonical body never carries them legitimately, but a merchant `onBeforeSession` hook's\n // `extra` rides through `denialReasonToBody` unfiltered — strip them so a smuggled `status`\n // can't rewrite the problem+json envelope (or the HTTP status Checkout derives from it).\n const { type: _type, title: _title, status: _status, detail: _detail, ...rest } = body;\n return { ...superset, ...rest };\n};\n\n/** Trust-level ordering: a token satisfies a requirement when its level ≥ the required level. */\nconst TRUST_RANK: Record<string, number> = { autonomous: 0, human_present: 1, human_confirmed: 2 };\n\n/**\n * Check a verified AIT against the gate's `trust_level` / `auth.amr` requirements (the spec's\n * human-presence gate). Returns a detail string when insufficient (→ weak_auth), else null.\n */\nexport const checkTrustRequirements = (\n payload: { trust_level?: string | undefined; auth?: { amr?: string[] | undefined } | undefined },\n requiredTrustLevel?: TrustLevel,\n requiredAmr?: string[],\n): string | null => {\n if (requiredTrustLevel !== undefined) {\n const have = TRUST_RANK[payload.trust_level ?? 'autonomous'] ?? 0;\n const need = TRUST_RANK[requiredTrustLevel] ?? 0;\n if (have < need) {\n 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).`;\n }\n }\n if (requiredAmr !== undefined && requiredAmr.length > 0) {\n const amr = Array.isArray(payload.auth?.amr) ? payload.auth!.amr! : [];\n if (!amr.some((m) => requiredAmr.includes(m))) {\n return `This endpoint requires an authentication method in [${requiredAmr.join(', ')}]; the token carries [${amr.join(', ') || 'none'}].`;\n }\n }\n return null;\n};\n\n/** Build an RFC 9457 `weak_auth` body for a token that failed the trust_level / auth.amr gate. */\nexport const buildAipWeakAuthBody = (opts: {\n detail: string;\n requiredTrustLevel?: TrustLevel;\n requiredAmr?: string[];\n trustedIssuers?: string[];\n}): AipErrorBody => ({\n type: 'urn:aip:error:weak_auth',\n title: 'weak auth',\n status: 403,\n detail: opts.detail,\n ...(opts.requiredTrustLevel !== undefined && { required_trust_level: opts.requiredTrustLevel }),\n ...(opts.requiredAmr !== undefined && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr }),\n ...(opts.trustedIssuers !== undefined && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }),\n});\n\n/** A verified AIT, or a ready-to-render RFC 9457 denial body (HTTP status on `body.status`). */\nexport type AipGateEvaluation =\n | { ok: true; ait: VerifiedAit }\n | { ok: false; body: AipErrorBody };\n\n/** Collect the merchant's requirements from gate options, for attaching to denial bodies. */\nconst requirementsFromOptions = (opts: AipGateOptions): AipErrorRequirements => ({\n ...(opts.trustedIssuers !== undefined && { trustedIssuers: opts.trustedIssuers }),\n ...(opts.requiredClaims !== undefined && { requiredClaims: opts.requiredClaims }),\n ...(opts.requireTrustLevel !== undefined && { requiredTrustLevel: opts.requireTrustLevel }),\n ...(opts.requireAmr !== undefined && { requiredAmr: opts.requireAmr }),\n});\n\n/**\n * Verify the AIP credential AND enforce the gate's trust_level / auth.amr requirement in one call —\n * the standalone-adapter counterpart to {@link verifyAitRequest}. Returns the verified AIT, or an\n * RFC 9457 denial body (a verify failure → its wire code; trust insufficient → weak_auth) carrying\n * the merchant's `required_*` / `trusted_issuers` so the agent can self-correct.\n */\nconst evaluateFromContext = async (ctx: VerifyRequestContext, opts: AipGateOptions): Promise<AipGateEvaluation> => {\n const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });\n if (!result.ok) {\n return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };\n }\n const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);\n if (weak !== null) {\n return {\n ok: false,\n body: buildAipWeakAuthBody({\n detail: weak,\n ...(opts.requireTrustLevel !== undefined && { requiredTrustLevel: opts.requireTrustLevel }),\n ...(opts.requireAmr !== undefined && { requiredAmr: opts.requireAmr }),\n ...(opts.trustedIssuers !== undefined && { trustedIssuers: opts.trustedIssuers }),\n }),\n };\n }\n return { ok: true, ait: result.ait };\n};\n\n/** Verify + trust-enforce on a standard Fetch `Request` (Hono / Web / Next.js adapters). */\nexport const evaluateAipRequest = (req: Request, opts: AipGateOptions): Promise<AipGateEvaluation> =>\n evaluateFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);\n\n/** Verify + trust-enforce from Express/Fastify-style parts (Node header map + method + url). */\nexport const evaluateAipParts = (\n parts: { method: string; url: string; headers: Record<string, string | string[] | undefined>; authority?: string },\n opts: AipGateOptions,\n): Promise<AipGateEvaluation> => evaluateFromContext(buildVerifyContextFromParts(partsWithAuthority(parts, opts)), opts);\n","import { createHash } from 'node:crypto';\nimport {\n AgentScore,\n type AipSignatureMaterial,\n InvalidCredentialError,\n PaymentRequiredError,\n QuotaExceededError,\n TimeoutError as SdkTimeoutError,\n TokenExpiredError,\n} from '@agent-score/sdk';\nimport { isFixableDenial } from './_denial';\nimport { QUOTA_EXCEEDED_INSTRUCTIONS } from './_response';\nimport { normalizeAddress } from './address';\nimport { TTLCache } from './cache';\nimport type { PaymentSigner } from './signer';\n\n// Character-based trim avoids a CodeQL polynomial-redos false positive on\n// `/\\/+$/` patterns that report library-input strings.\nfunction stripTrailingSlashes(s: string): string {\n let end = s.length;\n while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) end--;\n return end === s.length ? s : s.slice(0, end);\n}\n\ndeclare const __VERSION__: string;\n\n// ---------------------------------------------------------------------------\n// Public types (framework-agnostic)\n// ---------------------------------------------------------------------------\n\nexport interface AgentIdentity {\n address?: string;\n operatorToken?: string;\n /** Raw AIP Agent Identity Token (a JWT). When set, the gate has verified the token's RFC 9421\n * proof-of-possession at the edge as a fail-fast filter; `evaluate` forwards it to `/v1/assess`\n * as `aip_token` (with {@link aipSignature}) for AUTHORITATIVE server-side re-verification of the\n * IdP signature + proof-of-possession + policy. */\n aipToken?: string;\n /** RFC 9421 signature material accompanying {@link aipToken}, forwarded to `/v1/assess` as\n * `aip_signature` so the API re-verifies proof-of-possession itself (the edge is not trusted as\n * the authority). Always set together with `aipToken`. */\n aipSignature?: AipSignatureMaterial;\n}\n\n/**\n * Session metadata returned from `POST /v1/sessions`. Surfaced to the `onBeforeSession`\n * hook so merchants can correlate an AgentScore session with their own resume token\n * (e.g. a pending-order id).\n */\nexport interface SessionMetadata {\n session_id: string;\n verify_url: string;\n poll_secret: string;\n poll_url: string;\n expires_at?: string;\n}\n\n/**\n * Configuration for auto-creating a verification session when no identity is present.\n *\n * The static `context` / `productName` options are sent on every session request. For\n * per-request context (e.g. the specific product the agent was trying to buy), pass\n * a `getSessionOptions` callback that returns dynamic values; its return is merged\n * over the static defaults.\n *\n * `onBeforeSession` is a side-effect hook that runs after the session is minted but\n * before the 403 is built. Use it to pre-create a reservation/draft/pending-order\n * row in your DB so agents can resume via a merchant-specific id. Return value is\n * merged into `DenialReason.extra`, so it surfaces in both the default 403 body and\n * in a custom `onDenied` handler.\n */\nexport interface CreateSessionOnMissing<TCtx = unknown> {\n apiKey: string;\n baseUrl?: string;\n context?: string;\n productName?: string;\n /** Per-request override of `context` / `productName`. Invoked with the framework context. */\n getSessionOptions?: (ctx: TCtx) => Promise<{ context?: string; productName?: string }>\n | { context?: string; productName?: string };\n /** Side-effect hook that runs after the session is minted. Return value is merged\n * into `DenialReason.extra` so custom `onDenied` handlers can include merchant-specific\n * fields (e.g. `order_id`) in the 403 response. Hook errors are logged and swallowed —\n * a failing side effect should not block the 403 from reaching the agent. */\n onBeforeSession?: (ctx: TCtx, session: SessionMetadata) => Promise<Record<string, unknown>>\n | Record<string, unknown>;\n}\n\nexport interface AgentScoreCoreOptions {\n /** AgentScore API key. Required. */\n apiKey: string;\n /** Require KYC verification. */\n requireKyc?: boolean;\n /** Require operator to be clear of sanctions. */\n requireSanctionsClear?: boolean;\n /** Minimum operator age bracket (18 or 21). */\n minAge?: number;\n /** List of blocked jurisdictions (blocklist). */\n blockedJurisdictions?: string[];\n /** List of allowed jurisdictions (allowlist — only these pass). */\n allowedJurisdictions?: string[];\n /** If true, allow the request through when the API is unreachable. Defaults to false. */\n failOpen?: boolean;\n /** How long to cache results, in seconds. Defaults to 300. */\n cacheSeconds?: number;\n /** AgentScore API base URL. Defaults to \"https://api.agentscore.com\". */\n baseUrl?: string;\n /** Optional chain to filter scoring to. */\n chain?: string;\n /** Prepended to the default User-Agent as `\"{userAgent} (@agent-score/commerce@{version})\"`. Use to attribute API calls to your app. */\n userAgent?: string;\n /** When set and no identity is found, create a verification session instead of denying immediately. */\n createSessionOnMissing?: CreateSessionOnMissing;\n /** Issuers whose AIP Agent Identity Tokens this gate accepts. When set, the missing-identity\n * recovery instructions and the `agent_memory` hint advertise the AIT path so agents holding\n * one can present it. Set by Checkout from `gate.aip.trustedIssuers`; the actual AIT\n * verification happens at the edge (Checkout) before `evaluate`. */\n aipTrustedIssuers?: string[];\n}\n\nexport type DenialCode =\n | 'wallet_not_trusted'\n | 'missing_identity'\n | 'api_error'\n | 'payment_required'\n | 'identity_verification_required'\n // Wallet-signer binding: claimed X-Wallet-Address must resolve to the same operator as\n // the payment signer; wallet-auth is rejected on rails with no wallet signer.\n | 'wallet_signer_mismatch'\n | 'wallet_auth_requires_wallet_signing'\n // Granular credential-state denials passed through from /v1/assess.\n // - `token_expired`: revoked + TTL-expired (the API unifies these). The 401 body carries\n // an auto-minted session, forwarded into DenialReason for one-shot recovery.\n // - `invalid_credential`: the token doesn't exist at all (typo, never minted, fabricated).\n // No auto-session is minted by the API for this case — agents should switch to a\n // different stored token or drop the header to bootstrap a fresh session.\n | 'token_expired'\n | 'invalid_credential';\n\n/**\n * Cross-merchant pattern hint emitted on bootstrap denials and session-create responses.\n * LLM-hosted agents should persist this to long-term memory so future AgentScore encounters skip\n * the cold-start session flow. Contents are the pattern, not secrets.\n */\nexport interface AgentMemoryHint {\n save_for_future_agentscore_gates: true;\n pattern_summary: string;\n quickstart: string;\n identity_check_endpoint: string;\n list_wallets_endpoint?: string;\n identity_paths: { wallet: string; operator_token: string; agent_identity?: string };\n /** Issuers whose AIP Agent Identity Tokens this merchant accepts. Present only when the\n * merchant opted into AIP; an agent holding an AIT from one of these can present it via an\n * `Agent-Identity` header + RFC 9421 signature instead of bootstrapping a fresh credential. */\n aip_trusted_issuers?: string[];\n bootstrap: string;\n do_not_persist_in_memory: string[];\n persist_in_credential_store: string[];\n}\n\nexport interface DenialReason {\n code: DenialCode;\n /** Human-readable explanation. When omitted, `denialReasonToBody` substitutes a per-code default. */\n message?: string;\n decision?: string;\n reasons?: string[];\n verify_url?: string;\n session_id?: string;\n poll_secret?: string;\n poll_url?: string;\n agent_instructions?: string;\n /** Cross-merchant memory hint. Emitted on bootstrap denials only by default. */\n agent_memory?: AgentMemoryHint;\n /** Full assess response when the denial came from `/v1/assess`. Lets consumers access fields\n * not promoted to first-class DenialReason properties (e.g., `policy_result`). Undefined for\n * denials that did not originate from an assess call (missing_identity, api_error,\n * payment_required, identity_verification_required). */\n data?: AssessResult;\n /** Extra fields returned from the `createSessionOnMissing.onBeforeSession` hook. Merged\n * into the default 403 body; custom `onDenied` handlers can spread these into their own\n * response shape (e.g. to include a merchant-minted `order_id`). */\n extra?: Record<string, unknown>;\n // ---------------------------------------------------------------------------\n // Wallet-signer-match fields — populated for wallet_signer_mismatch only.\n // ---------------------------------------------------------------------------\n /** Operator id resolved from `X-Wallet-Address`. */\n claimed_operator?: string;\n /** Operator id the actual payment signer resolves to. `null` when the signer wallet isn't\n * linked to any operator (treat as a different identity). */\n actual_signer_operator?: string | null;\n /** The wallet the agent claimed via header. Echoed back for self-correction. */\n expected_signer?: string;\n /** The wallet that actually signed the payment. */\n actual_signer?: string;\n /** Wallets the claimed operator could sign with (if enumerable). Present when non-empty. */\n linked_wallets?: string[];\n}\n\n/** Operator verification details from the assess response. */\nexport interface OperatorVerification {\n level: string;\n operator_type: string | null;\n verified_at: string | null;\n}\n\n/** Account-level KYC facts that apply to every operator under the same account.\n * Populated when the API returns account_verification (post-KYC operator). */\nexport interface AccountVerification {\n kyc_level?: string;\n sanctions_clear?: boolean;\n age_bracket?: string;\n jurisdiction?: string;\n verified_at?: string | null;\n}\n\n/** A single policy check from the assess response. */\nexport interface PolicyCheck {\n rule: string;\n passed: boolean;\n required?: unknown;\n actual?: unknown;\n}\n\n/** Policy evaluation result from the assess response. */\nexport interface PolicyResult {\n all_passed: boolean;\n checks: PolicyCheck[];\n}\n\nexport interface AssessResult {\n decision: string | null;\n decision_reasons: string[];\n identity_method?: string;\n operator_verification?: OperatorVerification;\n account_verification?: AccountVerification;\n resolved_operator?: string | null;\n /** Wallets linked to the same operator as the resolved identity. Capped at 100 entries\n * by the API. Useful for advertising in 402 challenges so wallet-auth agents know which\n * alt-signers will satisfy `wallet_signer_mismatch`. */\n linked_wallets?: string[];\n verify_url?: string;\n policy_result?: PolicyResult | null;\n /** IdP provenance, present only when `identity_method === 'aip_token'` — which issuer attested\n * the identity and the trust level it asserted. Mirrors the SDK's `AssessResponse.aip`. */\n aip?: {\n issuer: string;\n subject: string;\n trust_level?: 'autonomous' | 'human_present' | 'human_confirmed';\n agent_provider?: string;\n /** True when /v1/assess re-verified the RFC 9421 proof-of-possession (always true on success). */\n pop_verified?: boolean;\n };\n}\n\n/**\n * Reason a failOpen allow short-circuited an evaluate call due to AgentScore-side\n * infrastructure issues. Surfaced on `EvaluateOutcome` so merchants can log/alert when\n * their gate is running in degraded mode (compliance not actually enforced this request).\n *\n * - `quota_exceeded` — AgentScore returned 429\n * - `api_error` — AgentScore returned 5xx or non-2xx that isn't 429\n * - `network_timeout` — request to /v1/assess timed out or failed at the network layer\n */\nexport type FailOpenInfraReason = 'quota_exceeded' | 'api_error' | 'network_timeout';\n\n/** Per-account assess quota observability, captured from `X-Quota-*` response headers\n * on the success path. Mirrors the SDK's `QuotaInfo` shape — re-exported from gate state\n * so merchants can monitor approach-to-cap proactively (warn at 80%, alert at 95%). */\nexport interface GateQuotaInfo {\n limit: number | null;\n used: number | null;\n /** ISO-8601 timestamp, or the literal string `\"never\"` for unlimited tiers. */\n reset: string | null;\n}\n\n/**\n * Outcome from `AgentScoreCore.evaluate()`. Adapters map this to framework-specific responses.\n *\n * - `{ kind: 'allow', data }` — the request passed the policy. `data` is present on a normal\n * allow; `undefined` when fail-open short-circuited (identity missing, API unreachable,\n * timeout, or 402 paid-tier required).\n * - When `failOpen: true` and the allow was the result of an AgentScore-side infrastructure\n * failure (429/5xx/timeout), the result also carries `degraded: true` + `infraReason` so\n * merchants can alert/log without parsing console output.\n * - `quota` propagates the SDK's per-request quota observability when the API emits the\n * `X-Quota-*` headers. Optional; absent on Enterprise / unlimited tiers.\n * - `signerVerdict` carries the per-request wallet-signer verdicts (signer_match + signer_sanctions)\n * composed by this evaluate's assess call. It rides on the RETURN VALUE (not a shared slot on the\n * core) so concurrent same-wallet/different-signer requests can't read each other's verdict —\n * the adapter stashes it on its per-request state for `getSignerVerdict(ctx)` to read back.\n * Present only on wallet-only identity when the response carried either signer block; `undefined`\n * otherwise (operator-token / AIT paths, discovery legs with no signer).\n * - `{ kind: 'deny', reason }` — the request was denied. Adapters should render a 403 with the\n * reason, or invoke the caller's custom denial handler.\n */\nexport type EvaluateOutcome =\n | { kind: 'allow'; data?: AssessResult; degraded?: boolean; infraReason?: FailOpenInfraReason; quota?: GateQuotaInfo; signerVerdict?: SignerVerdict }\n | { kind: 'deny'; reason: DenialReason; signerVerdict?: SignerVerdict };\n\ninterface CaptureWalletOptions {\n /** Operator credential (`opc_...`) that the agent authenticated with. */\n operatorToken: string;\n /** Signer wallet recovered from the payment payload. */\n walletAddress: string;\n /** Key-derivation family — `\"evm\"` for any EVM chain, `\"solana\"` for Solana. */\n network: 'evm' | 'solana';\n /** Optional stable key for the logical payment (e.g., payment intent id, tx hash). When the\n * same key is seen again for the same (credential, wallet, network), the server no-ops —\n * prevents agent retries from inflating transaction_count. */\n idempotencyKey?: string;\n}\n\n/** Combined wallet-signer verdict surfaced by `getSignerVerdict(c)` — both verdicts come\n * through the gate's primary `/v1/assess` call (single round trip). `signer_match` describes\n * the wallet-binding (claimed wallet's operator ≡ signer wallet's operator); `signer_sanctions`\n * describes the OFAC SDN wallet-address check.\n *\n * `signer_match` is projected to the gate's camelCase `VerifyWalletSignerResult` shape so\n * existing `buildSignerMismatchBody(...)` helpers consume it unchanged. `signer_sanctions`\n * passes through in the API's wire shape (already short and stable). Returned `undefined`\n * from `getSignerVerdict` when the gate didn't run with a signer (operator-token-only\n * paths, discovery legs with no payment header). */\nexport interface SignerVerdict {\n signer_match: VerifyWalletSignerResult | null;\n signer_sanctions:\n | { status: 'clear' }\n | { sanctioned: true; ofac_label: string; sdn_uid: string; listed_at: string | null }\n | { status: 'unavailable' }\n | null;\n}\n\nexport type VerifyWalletSignerResult =\n | { kind: 'pass'; claimedOperator: string | null; signerOperator: string | null }\n | {\n kind: 'wallet_signer_mismatch';\n claimedOperator: string | null;\n actualSignerOperator: string | null;\n expectedSigner: string;\n actualSigner: string;\n linkedWallets: string[];\n /** JSON-encoded action copy (action + steps + user_message). Spread into the 403 body\n * verbatim so agents get a concrete recovery path inside the denial response itself. */\n agentInstructions: string;\n }\n | {\n kind: 'wallet_auth_requires_wallet_signing';\n claimedWallet: string;\n agentInstructions: string;\n };\n\nexport interface AgentScoreCore {\n /**\n * Evaluate the request's identity against the configured policy.\n * @param identity - extracted identity (wallet address and/or operator token)\n * @param ctx - optional framework-specific context (Hono c, Express req, etc.) passed\n * through to `createSessionOnMissing` hooks. Opaque to core.\n */\n evaluate(\n identity: AgentIdentity | undefined,\n ctx?: unknown,\n /** Pre-extracted payment signer from the inbound request (the adapter middleware\n * extracts it via `extractPaymentSigner`). When provided, the assess call carries\n * it and the response includes `signer_match` + `signer_sanctions` verdicts in one\n * round trip. */\n signer?: PaymentSigner | null,\n ): Promise<EvaluateOutcome>;\n /** Report a wallet seen paying under an operator credential. Fire-and-forget; silently\n * swallows non-fatal errors because capture is informational, not on the critical path. */\n captureWallet(options: CaptureWalletOptions): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Internal cache entry for the gate's per-`(identity, policy)` assess result memo.\n * Distinct from the public `AssessResult` interface (the typed `/v1/assess` response\n * shape returned to merchants); this carries the cached decision plus the per-signer\n * wallet-match sub-cache. */\ninterface CachedAssessResult {\n allow: boolean;\n decision?: string;\n reasons?: string[];\n raw?: unknown;\n}\n\n/**\n * Build the cross-merchant memory hint emitted on bootstrap denials. Base URLs are\n * derived from the gate's AgentScore API base so self-hosted / staging deployments get\n * correct pointers. Contents describe the AgentScore identity substrate in transferable\n * terms; merchant-specific context lives in other `agent_instructions` fields.\n */\n// Canonical production AgentScore API — used as the authoritative source for endpoint pointers\n// emitted to agent memory regardless of how a given merchant configured their gate's baseUrl.\nconst CANONICAL_AGENTSCORE_API = 'https://api.agentscore.com';\n\n// JSON-encoded action copy emitted on wallet-signer-match denials. Spread into 403 bodies\n// by merchants so agents get a concrete recovery path inside the denial response itself —\n// no discovery-doc round trip required.\nconst WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({\n action: 'resign_or_switch_to_operator_token',\n steps: [\n 'Preferred: re-submit the payment signed by expected_signer (or any entry in linked_wallets — same-operator wallets are fungible) and retry with the same X-Wallet-Address.',\n 'Alternative: drop X-Wallet-Address and retry with X-Operator-Token. Use a stored opc_... if you have one; otherwise retry this request with NO identity header — the merchant will mint a verification session in the 403 body (verify_url + poll_secret). Share verify_url with the user, poll, receive a fresh opc_...',\n ],\n user_message:\n 'The payment signer resolves to a different operator than X-Wallet-Address. Re-sign from expected_signer or any linked_wallets entry, or switch to X-Operator-Token.',\n});\n\nconst WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS = JSON.stringify({\n action: 'switch_to_operator_token',\n steps: [\n 'This payment rail (Stripe SPT, card) carries no wallet signature — X-Wallet-Address cannot be verified against the payment.',\n 'Drop X-Wallet-Address and retry with X-Operator-Token. If you do not have a stored opc_..., retry with no identity header to receive a verification session.',\n ],\n user_message:\n 'Wallet-address identity is only supported on wallet-signing rails (Tempo MPP, x402). On Stripe or card, use X-Operator-Token instead.',\n});\n\n// `invalid_credential` is permanent — the token doesn't exist (typo, never minted, fabricated).\n// Distinct from `token_expired` (which carries an auto-session for one-shot recovery): the\n// API doesn't auto-mint a session here because the client may simply have a different valid\n// token to try. Agents should switch tokens or drop the header to bootstrap a session.\nconst INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({\n action: 'switch_token_or_restart_session',\n steps: [\n 'The X-Operator-Token you sent does not match any credential. This is a permanent state — retrying with the same token will keep failing.',\n 'If you have other stored opc_... credentials, retry with one of them.',\n 'Otherwise drop X-Operator-Token and retry with no identity header — the merchant will mint a fresh verification session in the 403 body (verify_url + poll_secret) so the user can re-verify and you can poll for a new operator_token.',\n ],\n user_message:\n 'The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one.',\n});\n\nexport function buildAgentMemoryHint(aipTrustedIssuers?: string[]): AgentMemoryHint {\n // Memory pointers always point at the canonical production API — merchants must not be\n // able to redirect the cross-merchant memory surface, since that would be a phishing\n // vector for the verify URL.\n const api = CANONICAL_AGENTSCORE_API;\n const acceptsAip = aipTrustedIssuers !== undefined && aipTrustedIssuers.length > 0;\n return {\n save_for_future_agentscore_gates: true,\n pattern_summary:\n 'AgentScore is a cross-merchant identity substrate for agent commerce. Any endpoint that ' +\n 'returns 403 missing_identity / identity_verification_required or 402 challenges referencing AgentScore uses ' +\n 'the same identity system. One KYC works across all AgentScore merchants — no re-verification ' +\n 'per site. Save this pattern (and the endpoints below) to persistent memory so future ' +\n 'AgentScore encounters skip the cold-start session flow.',\n quickstart: 'https://docs.agentscore.com/guides/agent-identity',\n identity_check_endpoint: `${api}/v1/credentials`,\n identity_paths: {\n wallet:\n 'If paying from a crypto wallet you have used before on any AgentScore merchant, send ' +\n '`X-Wallet-Address: 0x...`. Shortest path; no token lifecycle to manage.',\n operator_token:\n 'For any rail (Stripe SPT, card, or a wallet you have not linked yet), send ' +\n '`X-Operator-Token: opc_...`. Reusable across merchants until the token expires.',\n ...(acceptsAip && {\n agent_identity:\n 'If you hold an AIP Agent Identity Token from a trusted issuer (see aip_trusted_issuers), ' +\n 'present it: send the JWT in an `Agent-Identity` header plus an RFC 9421 HTTP Message ' +\n 'Signature (Signature-Input + Signature over @method @authority @path agent-identity, ' +\n 'tag=\"agent-identity\") signed with the token-bound cnf key. The merchant verifies it and ' +\n 'applies its policy — no separate AgentScore credential needed.',\n }),\n },\n ...(acceptsAip && { aip_trusted_issuers: aipTrustedIssuers }),\n bootstrap:\n 'If you have neither a linked wallet nor a valid operator_token, follow the session/verify ' +\n 'flow in the per-request `agent_instructions` block. This happens at most once per agent ' +\n 'identity — after first verification, the operator_token and any subsequently used wallet ' +\n 'are reusable everywhere.',\n do_not_persist_in_memory: ['operator_token', 'poll_secret'],\n persist_in_credential_store: ['operator_token'],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Core factory\n// ---------------------------------------------------------------------------\n\nexport function createAgentScoreCore(options: AgentScoreCoreOptions): AgentScoreCore {\n if (!options.apiKey) {\n throw new Error('AgentScore API key is required. Get one at https://www.agentscore.com/sign-up');\n }\n\n const {\n apiKey,\n requireKyc,\n requireSanctionsClear,\n minAge,\n blockedJurisdictions,\n allowedJurisdictions,\n failOpen = false,\n cacheSeconds = 300,\n baseUrl: rawBaseUrl = 'https://api.agentscore.com',\n chain: gateChain,\n userAgent,\n createSessionOnMissing,\n aipTrustedIssuers,\n } = options;\n\n const baseUrl = stripTrailingSlashes(rawBaseUrl);\n const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);\n\n const defaultUa = `@agent-score/commerce@${__VERSION__}`;\n const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;\n\n // Single shared SDK instance for every API call this gate makes (assess, sessions,\n // credentials/wallets, telemetry). Connection pooling + typed-error classification +\n // X-Quota-* header capture all flow through here. The SDK owns the transport layer\n // (timeouts, retry-on-429); the gate adds policy semantics on top. Pass the\n // merchant-prefixed UA — SDK appends its own default to produce a chain like\n // `<merchant-app> (@agent-score/commerce@<v>) (@agent-score/sdk@<v>)`.\n const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });\n\n // createSessionOnMissing can carry its own apiKey + baseUrl (merchants sometimes wire\n // a session-only key for this hook). Lazily build a separate SDK instance keyed on\n // (apiKey, baseUrl) so we don't construct a new client per request.\n const sessionSdkCache = new Map<string, AgentScore>();\n function getSessionSdk(sessionApiKey: string, sessionBaseUrl?: string): AgentScore {\n const key = `${sessionApiKey}|${sessionBaseUrl ?? ''}`;\n let s = sessionSdkCache.get(key);\n if (!s) {\n s = new AgentScore({\n apiKey: sessionApiKey,\n baseUrl: sessionBaseUrl ?? baseUrl,\n userAgent: userAgentHeader,\n });\n sessionSdkCache.set(key, s);\n }\n return s;\n }\n\n const cache = new TTLCache<CachedAssessResult>(cacheSeconds * 1000);\n\n // Mint a verification session via /v1/sessions and return the resulting\n // identity_verification_required DenialReason — or undefined if the mint failed (network\n // error, non-2xx, missing fields). Used for both the missing-identity path and the\n // fixable-wallet bootstrap path: in both cases the UX is identical (agent polls the\n // returned poll_url until it gets a fresh opc_... and retries).\n async function tryMintSessionDenial(ctx: unknown): Promise<DenialReason | undefined> {\n if (!createSessionOnMissing) return undefined;\n try {\n const sessionBody: { context?: string; product_name?: string } = {};\n if (createSessionOnMissing.context != null) sessionBody.context = createSessionOnMissing.context;\n if (createSessionOnMissing.productName != null) sessionBody.product_name = createSessionOnMissing.productName;\n\n if (createSessionOnMissing.getSessionOptions && ctx !== undefined) {\n try {\n const dynamic = await createSessionOnMissing.getSessionOptions(ctx);\n if (dynamic?.context != null) sessionBody.context = dynamic.context;\n if (dynamic?.productName != null) sessionBody.product_name = dynamic.productName;\n } catch (err) {\n console.warn('[gate] createSessionOnMissing.getSessionOptions hook failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // createSessionOnMissing.apiKey may differ from the gate's apiKey (e.g. merchant\n // wires a session-only key for this hook). Build a per-config SDK lazily.\n const sessionSdk = getSessionSdk(createSessionOnMissing.apiKey, createSessionOnMissing.baseUrl);\n const data = (await sessionSdk.createSession({\n ...(sessionBody.context !== undefined ? { context: sessionBody.context } : {}),\n ...(sessionBody.product_name !== undefined ? { product_name: sessionBody.product_name } : {}),\n })) as unknown as Record<string, unknown>;\n\n // Validate required fields before trusting the response. A misbehaving (or mocked-wrong)\n // API could 200 without session_id/poll_secret/verify_url, which would propagate\n // `undefined` into the 403 body and leave the agent stuck — treat as session-create\n // failure and fall back to the caller's bare denial.\n if (\n typeof data.session_id !== 'string' ||\n typeof data.poll_secret !== 'string' ||\n typeof data.verify_url !== 'string'\n ) {\n console.warn('[gate] /v1/sessions returned 200 without required fields — falling back to bare denial');\n return undefined;\n }\n\n // Run onBeforeSession side-effect hook. Errors are swallowed — a failing DB write\n // (e.g. can't insert pending order) should not block the 403.\n let extra: Record<string, unknown> | undefined;\n if (createSessionOnMissing.onBeforeSession && ctx !== undefined) {\n try {\n const sessionMeta = {\n session_id: data.session_id as string,\n verify_url: data.verify_url as string,\n poll_secret: data.poll_secret as string,\n poll_url: data.poll_url as string,\n expires_at: data.expires_at as string | undefined,\n };\n const result = await createSessionOnMissing.onBeforeSession(ctx, sessionMeta);\n if (result && typeof result === 'object') extra = result;\n } catch (err) {\n console.warn('[gate] createSessionOnMissing.onBeforeSession hook failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // The API emits `next_steps` (structured object) on /v1/sessions success. Stringify it\n // into the gate's `agent_instructions` contract so merchants get the same JSON-encoded\n // {action, steps, user_message} envelope as every other gate-emitted denial.\n const apiNextSteps = data.next_steps as Record<string, unknown> | undefined;\n return {\n code: 'identity_verification_required',\n verify_url: data.verify_url as string,\n session_id: data.session_id as string,\n poll_secret: data.poll_secret as string,\n poll_url: data.poll_url as string | undefined,\n agent_instructions: apiNextSteps ? JSON.stringify(apiNextSteps) : undefined,\n agent_memory: agentMemoryHint,\n ...(extra && { extra }),\n };\n } catch (err) {\n // Session-mint failed (network, /v1/sessions returned non-2xx, body parse error,\n // onBeforeSession threw inside the inner try). Caller falls back to a bare denial —\n // agents still get a 403 with a probe-strategy hint. Log loudly so a persistent\n // /v1/sessions outage isn't masked.\n console.warn('[gate] createSessionOnMissing path failed — falling back to bare denial:', err instanceof Error ? err.message : err);\n return undefined;\n }\n }\n\n async function evaluate(\n identity: AgentIdentity | undefined,\n ctx?: unknown,\n signer?: PaymentSigner | null,\n ): Promise<EvaluateOutcome> {\n // Treat \"returned identity object with no usable fields\" the same as \"no identity at all\" —\n // otherwise a misbehaving custom extractIdentity would send an empty body to /v1/assess.\n if (!identity || (!identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim())) {\n // failOpen short-circuits BEFORE the session mint. This branch isn't an infra failure\n // (no AgentScore call has been made yet) so we don't mark the gate state as degraded —\n // missing identity + failOpen is the explicit opt-in pass-through behavior, not a\n // graceful-degradation event. Merchants who need identity-or-deny on a failOpen gate\n // should add a guard at the handler that checks for X-Wallet-Address / X-Operator-Token\n // before reading the gate state.\n if (failOpen) return { kind: 'allow' };\n\n const sessionReason = await tryMintSessionDenial(ctx);\n if (sessionReason) return { kind: 'deny', reason: sessionReason };\n\n // Bare missing-identity denial (no session was auto-created). Describe the probe\n // strategy so agents without memory can recover: try wallet first on signing rails,\n // fall back to stored opc_..., fall back to session flow (noting that only\n // auto-session merchants return verify_url + poll data on the retry).\n const acceptsAip = aipTrustedIssuers !== undefined && aipTrustedIssuers.length > 0;\n const aipStep = acceptsAip\n ? [\n `If you hold an AIP Agent Identity Token from a trusted issuer (${aipTrustedIssuers.join(', ')}): 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. This satisfies identity in one round trip without an AgentScore credential.`,\n ]\n : [];\n const missingIdentityInstructions = JSON.stringify({\n action: 'probe_identity_then_session',\n steps: [\n ...aipStep,\n 'If you have a wallet AND this merchant accepts a wallet-signing rail (Tempo MPP or x402 — 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 — share it with the user to claim the wallet + complete KYC, then retry.',\n 'If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.',\n '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 — 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 — 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.',\n ],\n user_message:\n '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.',\n });\n return {\n kind: 'deny',\n reason: {\n code: 'missing_identity',\n agent_instructions: missingIdentityInstructions,\n agent_memory: agentMemoryHint,\n },\n };\n }\n\n // operator_token is opaque + ASCII-only — lowercasing is safe. Wallet addresses go\n // through normalizeAddress because Solana base58 is case-sensitive and lowercasing\n // would corrupt the cache key (a Solana cache miss every time, plus collision risk\n // with mixed-case variants of the same operator).\n // AIT cache key: hash the raw token so the (short-lived) JWT isn't held verbatim as a\n // Map key. AITs are seconds-to-minutes TTL anyway; this just dedupes repeated presents\n // within the cache window. Falls through to operator_token / address otherwise.\n const identityKey = identity.aipToken\n ? `aip:${createHash('sha256').update(identity.aipToken).digest('hex')}`\n : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : '');\n\n // The assess response carries per-request, signer-derived verdicts (signer_match +\n // signer_sanctions). The signer is NOT part of the identity, so it must be folded into the\n // response cache key: otherwise a 2nd request with the SAME claimed identity but a DIFFERENT\n // payment signer would hit the cached decision and return the first signer's stale\n // signer_match/signer_sanctions — bypassing wallet-signer binding AND the unconditional OFAC\n // signer screen (a sanctioned 2nd signer would settle on a cached `clear`). Appending the\n // normalized signer (network + address) makes a different signer a cache MISS, forcing a fresh\n // assess that re-screens it. Requests with no signer keep the identity-only key (no behavior\n // change for operator-token / discovery legs).\n //\n // The key is a JSON-encoded parts array, NOT string concatenation: the wallet-path identityKey\n // passes arbitrary (invalid) claimed addresses through lowercased, so a delimiter-bearing\n // X-Wallet-Address could otherwise be crafted to collide with a real (identity, signer) key.\n // JSON escaping + distinct arity make every part injection-proof.\n const cacheKey = signer\n ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)])\n : JSON.stringify([identityKey]);\n\n const cached = cache.get(cacheKey);\n if (cached) {\n // Recompute the per-request verdict from the cached response. The cache key folds in the\n // signer, so a cache hit is the SAME (identity, signer) pair — the cached signer blocks are\n // this request's verdict. Riding it on the return value (vs a shared slot) is what makes\n // concurrent same-wallet/different-signer reads race-free.\n const cachedVerdict = cached.raw\n ? buildSignerVerdict(identity, cached.raw as Record<string, unknown>)\n : undefined;\n if (cached.allow) {\n const cachedRaw = cached.raw as Record<string, unknown> | undefined;\n const cachedQuota = cachedRaw?.quota as GateQuotaInfo | undefined;\n return {\n kind: 'allow',\n data: cachedRaw as unknown as AssessResult,\n ...(cachedQuota !== undefined && { quota: cachedQuota }),\n ...(cachedVerdict !== undefined && { signerVerdict: cachedVerdict }),\n };\n }\n // Fixable compliance denials (kyc_required, kyc_pending, kyc_failed) get the\n // same UX as missing_identity: mint a fresh verification session, agent polls\n // until status=verified, gets a fresh opc_..., retries. Unfixable reasons\n // (sanctions_flagged, age_insufficient, jurisdiction_restricted) keep the bare\n // wallet_not_trusted denial. `jurisdiction_restricted` is unfixable: the API\n // only emits it after KYC is verified (the user's KYC'd country is in the\n // blocked list — re-doing KYC won't change the country).\n if (isFixableDenial(cached.reasons)) {\n const sessionReason = await tryMintSessionDenial(ctx);\n if (sessionReason) {\n return { kind: 'deny', reason: sessionReason, ...(cachedVerdict !== undefined && { signerVerdict: cachedVerdict }) };\n }\n }\n return {\n kind: 'deny',\n reason: {\n code: 'wallet_not_trusted',\n decision: cached.decision,\n reasons: cached.reasons,\n verify_url: (cached.raw as Record<string, unknown> | undefined)?.verify_url as string | undefined,\n data: cached.raw as AssessResult | undefined,\n },\n ...(cachedVerdict !== undefined && { signerVerdict: cachedVerdict }),\n };\n }\n\n const policy: Record<string, unknown> = {};\n if (requireKyc != null) policy.require_kyc = requireKyc;\n if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;\n if (minAge != null) policy.min_age = minAge;\n if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;\n if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;\n\n let data: Record<string, unknown>;\n try {\n // Single SDK call: typed-error subclasses (PaymentRequiredError / TokenExpiredError /\n // InvalidCredentialError / QuotaExceededError / TimeoutError) flow through the\n // catch below; success path captures `quota` from X-Quota-* headers automatically.\n const opts = {\n chain: gateChain,\n ...(Object.keys(policy).length > 0 ? { policy: policy as never } : {}),\n // Pre-extracted payment signer (by the adapter middleware). When present, the API\n // composes BOTH signer_match (wallet-binding) and signer_sanctions (OFAC SDN wallet\n // check) verdicts on the response in one round trip. Wallet-OFAC enforcement on the\n // signer block is unconditional — a signer_sanctions hit flips decision -> deny\n // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).\n ...(signer && { signer: { address: signer.address, network: signer.network } }),\n };\n // SDK has overloads — narrow by which identity is set so TS picks the right one.\n // AIT takes precedence: when present it's the sole identity input. The edge already\n // PoP-verified as a fail-fast filter; we forward the token + signature material so the API\n // re-verifies the IdP signature AND the proof-of-possession authoritatively. Checkout always\n // sets both together; a hand-rolled evaluate() with aipToken but no aipSignature is a caller\n // error — fail loudly rather than silently misrouting to the operator-token branch.\n if (identity.aipToken !== undefined && identity.aipSignature === undefined) {\n throw new Error('AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).');\n }\n const result = identity.aipToken !== undefined && identity.aipSignature !== undefined\n ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken, aipSignature: identity.aipSignature })\n : identity.address\n ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken })\n : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken! });\n data = result as unknown as Record<string, unknown>;\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n if (failOpen) return { kind: 'allow' };\n return { kind: 'deny', reason: { code: 'payment_required' } };\n }\n if (err instanceof TokenExpiredError) {\n // SDK extracts the auto-minted session fields onto the error instance — no body\n // re-parsing needed here.\n return {\n kind: 'deny',\n reason: {\n code: 'token_expired',\n data: err.details as unknown as AssessResult,\n ...(err.verifyUrl ? { verify_url: err.verifyUrl } : {}),\n ...(err.sessionId ? { session_id: err.sessionId } : {}),\n ...(err.pollSecret ? { poll_secret: err.pollSecret } : {}),\n ...(err.pollUrl ? { poll_url: err.pollUrl } : {}),\n ...(err.nextSteps ? { agent_instructions: JSON.stringify(err.nextSteps) } : {}),\n ...(err.agentMemory ? { agent_memory: err.agentMemory as AgentMemoryHint } : {}),\n },\n };\n }\n if (err instanceof InvalidCredentialError) {\n // Permanent — no auto-session, agent should switch tokens or restart.\n return {\n kind: 'deny',\n reason: {\n code: 'invalid_credential',\n agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,\n agent_memory: agentMemoryHint,\n },\n };\n }\n if (err instanceof QuotaExceededError) {\n console.warn('[gate] /v1/assess returned 429 quota_exceeded');\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'quota_exceeded' };\n return {\n kind: 'deny',\n reason: { code: 'api_error', agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS },\n };\n }\n if (err instanceof SdkTimeoutError) {\n console.warn('[gate] /v1/assess timed out:', err.message);\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'network_timeout' };\n return { kind: 'deny', reason: { code: 'api_error' } };\n }\n // Status-based fallbacks for AgentScoreError instances the SDK couldn't classify\n // into a typed subclass (e.g. 429 with body that lacked error.code, or a fetch\n // rejection whose .name doesn't match AbortError but whose status code is set).\n // The real API always emits error.code on 429, so this is purely defensive.\n const status = (err as { status?: number } | null)?.status;\n const errName = err instanceof Error ? err.name : '';\n if (status === 429) {\n console.warn('[gate] /v1/assess returned 429 (untyped — defensive)');\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'quota_exceeded' };\n return {\n kind: 'deny',\n reason: { code: 'api_error', agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS },\n };\n }\n if (errName === 'TimeoutError' || errName === 'AbortError') {\n console.warn('[gate] /v1/assess timed out (by Error.name):', err instanceof Error ? err.message : err);\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'network_timeout' };\n return { kind: 'deny', reason: { code: 'api_error' } };\n }\n // Generic AgentScoreError (rate_limited, 5xx, network_error, body parse, unknown 4xx)\n // or any non-AgentScoreError unexpected throw — surface as api_error.\n // Include the SDK-classified error code (when available) so ops/dev see\n // schema-drift cases like a new 401 error.code rather than a silent 503.\n const errCode = (err as { code?: string } | null)?.code;\n const msg = err instanceof Error ? err.message : String(err);\n const detail = errCode ? `${errCode}: ${msg}` : msg;\n console.warn(`[gate] /v1/assess call failed — surfacing as api_error: ${detail}`);\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'api_error' };\n return { kind: 'deny', reason: { code: 'api_error' } };\n }\n\n const decision = data.decision as string | null | undefined;\n const decisionReasons = (data.decision_reasons as string[]) ?? [];\n const allow = decision === 'allow' || decision == null;\n\n cache.set(cacheKey, { allow, decision: decision ?? undefined, reasons: decisionReasons, raw: data });\n\n // Compose the per-request signer verdicts and ride them on the RETURN VALUE so the adapter can\n // stash them on its per-request state (NOT a shared slot — see buildSignerVerdict). guard:\n // wallet-only identity (operator-token / AIT win and signer-match is deliberately not enforced).\n const signerVerdict = buildSignerVerdict(identity, data);\n\n if (allow) {\n // SDK populates `quota` on the assess response from X-Quota-* headers when the\n // API emits them. Surface up to the adapter so merchants can monitor approach-to-cap.\n const quota = data.quota as GateQuotaInfo | undefined;\n return {\n kind: 'allow',\n data: data as unknown as AssessResult,\n ...(quota !== undefined && { quota }),\n ...(signerVerdict !== undefined && { signerVerdict }),\n };\n }\n\n // Fixable compliance denials (kyc_required, kyc_pending, kyc_failed) get the\n // same UX as missing_identity: mint a fresh verification session, agent polls\n // until status=verified, gets a fresh opc_..., retries. Unfixable reasons\n // (sanctions_flagged, age_insufficient, jurisdiction_restricted) keep the bare\n // wallet_not_trusted denial. `jurisdiction_restricted` is unfixable: the API\n // only emits it after KYC is verified (the user's KYC'd country is in the\n // blocked list — re-doing KYC won't change the country).\n if (isFixableDenial(decisionReasons)) {\n const sessionReason = await tryMintSessionDenial(ctx);\n if (sessionReason) {\n return { kind: 'deny', reason: sessionReason, ...(signerVerdict !== undefined && { signerVerdict }) };\n }\n }\n\n return {\n kind: 'deny',\n reason: {\n code: 'wallet_not_trusted',\n decision: decision ?? undefined,\n reasons: decisionReasons,\n verify_url: data.verify_url as string | undefined,\n data: data as unknown as AssessResult,\n },\n ...(signerVerdict !== undefined && { signerVerdict }),\n };\n }\n\n async function captureWallet(options: CaptureWalletOptions): Promise<void> {\n try {\n await sdk.associateWallet({\n operatorToken: options.operatorToken,\n walletAddress: options.walletAddress,\n network: options.network,\n ...(options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}),\n });\n } catch (err) {\n // Fire-and-forget: don't throw. Log so a persistent capture outage is visible\n // to merchant ops — otherwise wallet↔operator linkage silently stops.\n console.warn('[agentscore-commerce] captureWallet failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // Project the API's signer_match block onto the gate's VerifyWalletSignerResult shape.\n // The API authors agent_instructions, claimed/signer operators, and the linked-wallet\n // set (deny-guarded server-side); the gate just shapes those fields into camelCase.\n function projectSignerMatch(\n sm: Record<string, unknown>,\n claimedNorm: string,\n signerNorm: string,\n ): VerifyWalletSignerResult {\n const kind = sm.kind as string;\n if (kind === 'pass') {\n return {\n kind: 'pass',\n claimedOperator: (sm.claimed_operator as string | null | undefined) ?? null,\n signerOperator: (sm.signer_operator as string | null | undefined) ?? null,\n };\n }\n if (kind === 'wallet_auth_requires_wallet_signing') {\n return {\n kind: 'wallet_auth_requires_wallet_signing',\n claimedWallet: (sm.claimed_wallet as string | undefined) ?? claimedNorm,\n agentInstructions:\n (sm.agent_instructions as string | undefined) ?? WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS,\n };\n }\n // Default: wallet_signer_mismatch\n const linked = sm.linked_wallets;\n return {\n kind: 'wallet_signer_mismatch',\n claimedOperator: (sm.claimed_operator as string | null | undefined) ?? null,\n actualSignerOperator: (sm.signer_operator as string | null | undefined) ?? null,\n expectedSigner: (sm.expected_signer as string | undefined) ?? claimedNorm,\n actualSigner: (sm.actual_signer as string | undefined) ?? signerNorm,\n linkedWallets: Array.isArray(linked)\n ? (linked as unknown[]).filter((w): w is string => typeof w === 'string')\n : [],\n agentInstructions:\n (sm.agent_instructions as string | undefined) ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS,\n };\n }\n\n /**\n * Build the per-request signer verdicts (signer_match + signer_sanctions) from an assess\n * response. Returns `undefined` unless the wallet is the EFFECTIVE identity (no operator_token,\n * no AIT — operator-token / AIT wins and signer-match is deliberately NOT enforced) AND the\n * response carried at least one signer block.\n *\n * The verdict is returned on the `EvaluateOutcome` and stashed by each adapter on its\n * PER-REQUEST state (Hono `c`, Express/Fastify `request`, web closure), NOT on a shared slot —\n * so concurrent same-wallet/different-signer requests can never read each other's verdict.\n */\n function buildSignerVerdict(\n identity: AgentIdentity,\n raw: Record<string, unknown>,\n ): SignerVerdict | undefined {\n if (\n identity.address === undefined ||\n identity.operatorToken !== undefined ||\n identity.aipToken !== undefined\n ) {\n return undefined;\n }\n const rawMatch = raw.signer_match as Record<string, unknown> | undefined;\n const rawSanctions = raw.signer_sanctions as SignerVerdict['signer_sanctions'] | undefined;\n if (!rawMatch && !rawSanctions) return undefined;\n const claimedNorm = normalizeAddress(identity.address);\n // The API's signer_match has the actual signer wallet baked in (actual_signer); pass it as\n // signerNorm so the projected shape is consistent.\n const signerNorm = (rawMatch?.actual_signer as string | undefined) ?? claimedNorm;\n return {\n signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,\n signer_sanctions: rawSanctions ?? null,\n };\n }\n\n return { evaluate, captureWallet };\n}\n","// Network-aware address normalization. EVM addresses (0x + 40 hex) are\n// case-insensitive in the protocol — we lowercase them so DB lookups against\n// `address_lower`-style columns work. Solana addresses are base58 and are\n// case-sensitive — we MUST preserve the input verbatim, never lowercase.\n//\n// Must produce the same normalization the AgentScore API applies, so the gate, API,\n// and merchants resolve wallets the same way. If they drift, captured wallets won't\n// resolve and signer-match silently breaks.\n\nconst SOLANA_BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\nconst EVM_RE = /^0x[0-9a-fA-F]{40}$/;\n\nexport const isValidEvmAddress = (address: string): boolean => EVM_RE.test(address);\n\nexport const isSolanaAddress = (address: string): boolean =>\n SOLANA_BASE58_RE.test(address) && !address.startsWith('0x');\n\nexport const isValidAddress = (address: string): boolean =>\n isValidEvmAddress(address) || isSolanaAddress(address);\n\nexport const normalizeAddress = (address: string): string => {\n if (isSolanaAddress(address)) { return address; }\n return address.toLowerCase();\n};\n","export class TTLCache<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n private maxSize: number;\n\n constructor(private defaultTtlMs: number, maxSize = 10000) {\n this.maxSize = maxSize;\n }\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.value;\n }\n\n set(key: string, value: T, ttlMs?: number): void {\n if (this.store.size >= this.maxSize) {\n this.sweep();\n }\n if (this.store.size >= this.maxSize) {\n this.evictOldest(this.store.size - this.maxSize + 1);\n }\n this.store.set(key, {\n value,\n expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs),\n });\n }\n\n /** Remove all expired entries. */\n private sweep(): void {\n const now = Date.now();\n for (const [k, v] of this.store) {\n if (now > v.expiresAt) {\n this.store.delete(k);\n }\n }\n }\n\n /** Evict the oldest `count` entries by insertion order. */\n private evictOldest(count: number): void {\n let removed = 0;\n for (const key of this.store.keys()) {\n if (removed >= count) break;\n this.store.delete(key);\n removed++;\n }\n }\n}\n","/** Detects whether a request is a \"settle leg\" (carries a payment credential)\n * vs a \"discovery leg\" (no payment credential, expects a 402).\n *\n * Used by the gate-conditional mount pattern documented in CLAUDE.md: mount\n * `agentscoreGate` on a route only when payment is being attempted, so the\n * discovery leg flows through unauthenticated and gets a 402 with all rails.\n *\n * Three credential channels are checked:\n * - `Payment-Signature` — MPP credentials (Tempo, Solana, Stripe SPT)\n * - `X-Payment` — x402 v1 EIP-3009 credentials\n * - `Authorization: Payment <jwt>` — x402 v2 / paymentauth.org credentials\n */\n\ntype WebHeaders = { get(name: string): string | null };\ntype RecordHeaders = Record<string, string | string[] | undefined>;\nexport type HeadersLike = WebHeaders | RecordHeaders | Headers;\n\nfunction toTitleCase(name: string): string {\n return name.replace(/(^|-)([a-z])/g, (_m, sep: string, c: string) => sep + c.toUpperCase());\n}\n\nexport function readHeader(headers: HeadersLike, name: string): string | null {\n if (typeof (headers as Partial<WebHeaders>).get === 'function') {\n return (headers as WebHeaders).get(name);\n }\n const rec = headers as RecordHeaders;\n const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];\n if (typeof v === 'string') return v;\n if (Array.isArray(v) && typeof v[0] === 'string') return v[0];\n return null;\n}\n\nexport function asHeaders(input: Request | HeadersLike): HeadersLike {\n return typeof (input as Partial<Request>).headers === 'object' && input instanceof Request\n ? input.headers\n : (input as HeadersLike);\n}\n\n/** True when the request carries any of the payment-credential headers we\n * recognize. Accepts a Web Fetch `Headers`, a Web Fetch `Request` (uses\n * `request.headers`), or a plain header record (Express/Fastify-shaped).\n *\n * Use this to gate the `agentscoreGate` middleware so anonymous discovery\n * legs flow through and get a 402 with all rails. See CLAUDE.md\n * \"Anonymous discovery\" pattern.\n */\nexport function hasPaymentHeader(input: Request | HeadersLike): boolean {\n const headers = asHeaders(input);\n return Boolean(\n readHeader(headers, 'payment-signature') ||\n readHeader(headers, 'x-payment') ||\n readHeader(headers, 'authorization')?.startsWith('Payment '),\n );\n}\n\n/** True when the request carries an x402 payment credential (`X-Payment` or\n * `Payment-Signature`). Use to dispatch to the x402 settle path. */\nexport function hasX402Header(input: Request | HeadersLike): boolean {\n const headers = asHeaders(input);\n return Boolean(readHeader(headers, 'payment-signature') || readHeader(headers, 'x-payment'));\n}\n\n/** True when the request carries an mppx payment credential\n * (`Authorization: Payment <jwt>`). Use to dispatch to the MPP settle path. */\nexport function hasMppxHeader(input: Request | HeadersLike): boolean {\n const headers = asHeaders(input);\n return Boolean(readHeader(headers, 'authorization')?.startsWith('Payment '));\n}\n","/**\n * Payment-signer extraction.\n *\n * Shared between merchants and the gate. Three paths recover a wallet signer:\n *\n * - **Tempo MPP** — `Authorization: Payment <base64>`; credential `source` is a DID of the\n * form `did:pkh:eip155:<chain>:<address>`.\n * - **Solana MPP `solana/charge`** — `Authorization: Payment <base64>`; recovery via either\n * a `did:pkh:solana:<genesis>:<address>` source (when set by the client) or by decoding\n * the credential's signed-tx payload and reading the SPL `TransferChecked` authority\n * (pull mode only — `payload.type === 'transaction'`).\n * - **x402 EIP-3009 (EVM, e.g. Base/Sepolia)** — `payment-signature` / `x-payment`;\n * decoded payload carries `payload.authorization.from`.\n *\n * Optional peer deps: `mppx` for MPP credentials, `@solana/kit` for the Solana tx-decode\n * fallback. Both dynamic-imported; merchants who don't accept that rail don't need them.\n */\n\nimport { normalizeHeadersToLowercase } from './_headers';\n\nexport type SignerNetwork = 'evm' | 'solana';\n\nconst TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';\nconst TOKEN_2022_PROGRAM = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';\nconst TRANSFER_CHECKED_DISCRIMINATOR = 12;\n\ninterface SolanaKitMinimal {\n getBase64Codec: () => { encode: (s: string) => Uint8Array };\n getTransactionDecoder: () => { decode: (b: Uint8Array) => { messageBytes: Uint8Array } };\n getCompiledTransactionMessageDecoder: () => {\n decode: (b: Uint8Array) => {\n staticAccounts: ReadonlyArray<string>;\n instructions: ReadonlyArray<{\n programAddressIndex: number;\n accountIndices?: number[];\n data?: Uint8Array;\n }>;\n };\n };\n}\n\n/**\n * Decode a Solana MPP `solana/charge` credential's `payload.transaction` (base64-encoded\n * signed Solana tx) and return the SPL `TransferChecked` authority — the source-ATA owner,\n * which is the buyer's wallet. Pull mode only (`payload.type === 'transaction'`); push mode\n * (`payload.type === 'signature'`) returns null because recovery would require an RPC fetch.\n */\nasync function extractSolanaSignerFromCredential(credential: unknown): Promise<string | null> {\n const payload = (credential as { payload?: { transaction?: string; type?: string } }).payload;\n if (!payload?.transaction || payload.type !== 'transaction') return null;\n\n const moduleName = '@solana/kit';\n const kit = (await import(moduleName).catch(() => null)) as SolanaKitMinimal | null;\n if (!kit?.getBase64Codec || !kit.getTransactionDecoder || !kit.getCompiledTransactionMessageDecoder) {\n return null;\n }\n\n try {\n const txBytes = kit.getBase64Codec().encode(payload.transaction);\n const decoded = kit.getTransactionDecoder().decode(txBytes);\n const message = kit.getCompiledTransactionMessageDecoder().decode(decoded.messageBytes);\n\n // SPL TransferChecked accounts: [source ATA, mint, destination ATA, authority, ...signers].\n // Returns the FIRST matched authority. For multi-recipient `splits` txs, the buyer\n // signs ONE tx with N TransferChecked instructions all sharing the same authority,\n // so first-match is correct; if a tx ever surfaces with mismatched authorities the\n // first one wins (acceptable since both belong to whoever signed the tx).\n for (const ix of message.instructions) {\n const programId = message.staticAccounts[ix.programAddressIndex];\n if (programId !== TOKEN_PROGRAM && programId !== TOKEN_2022_PROGRAM) continue;\n const data = ix.data;\n if (!data || data.length === 0 || data[0] !== TRANSFER_CHECKED_DISCRIMINATOR) continue;\n const accountIndices = ix.accountIndices ?? [];\n const authorityIndex = accountIndices[3];\n if (authorityIndex === undefined) continue;\n // v0 transactions can carry account indices that resolve via address lookup tables;\n // staticAccounts only holds the static set. If the index is out of range, the\n // authority sits in a lookup table we'd need RPC to resolve. Skip cleanly with a\n // warning rather than returning the wrong address.\n if (authorityIndex >= message.staticAccounts.length) {\n console.warn(\n '[gate] Solana TransferChecked authority resolves through an address lookup table; ' +\n 'signer-match recovery requires the static-account form. Skipping.',\n );\n continue;\n }\n const authority = message.staticAccounts[authorityIndex];\n if (authority) return authority;\n }\n return null;\n } catch (err) {\n console.warn('[gate] Solana credential decode failed:', err instanceof Error ? err.message : err);\n return null;\n }\n}\n\nexport interface PaymentSigner {\n /** Recovered wallet address (EVM lowercased; Solana base58 preserved verbatim). */\n address: string;\n /** Network family — used by `captureWallet` and downstream cross-chain attribution. */\n network: SignerNetwork;\n}\n\n/**\n * Recover the signer wallet from the incoming payment credential, including the network\n * family. Returns `null` when no wallet signature is present (e.g. Stripe SPT, card-only\n * payments, or no credential yet).\n *\n * @param request - the inbound `Request`\n * @param x402PaymentHeader - the value of `payment-signature` or `x-payment` header, if any.\n * Extracted separately because some frameworks (Express) don't expose a web `Request` object.\n */\nexport async function extractPaymentSigner(\n request: Request,\n x402PaymentHeader?: string,\n): Promise<PaymentSigner | null> {\n // x402 — base64 JSON, EIP-3009 only. EVM `payload.authorization.from` is the signer.\n // Tried before the MPP path so a request carrying both header families resolves the\n // x402 signer first, consistent with `extractSignerForPrecheck`.\n if (x402PaymentHeader) {\n try {\n const decoded = atob(x402PaymentHeader);\n const parsed = JSON.parse(decoded) as {\n payload?: { authorization?: { from?: string } };\n };\n const from = parsed?.payload?.authorization?.from;\n if (typeof from === 'string' && /^0x[0-9a-fA-F]{40}$/.test(from)) {\n return { address: from.toLowerCase(), network: 'evm' };\n }\n } catch (err) {\n console.warn('[gate] x402 signer extraction failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // MPP — Authorization: Payment <base64>\n const authHeader = request.headers.get('authorization');\n if (authHeader) {\n try {\n const moduleName = 'mppx';\n const mppx = (await import(moduleName).catch(() => null)) as {\n Credential?: {\n extractPaymentScheme: (h: string) => unknown;\n fromRequest: (r: Request) => unknown;\n };\n } | null;\n if (mppx?.Credential?.extractPaymentScheme(authHeader)) {\n const credential = mppx.Credential.fromRequest(request);\n const source = (credential as { source?: string }).source;\n const evmMatch = source?.match(/^did:pkh:eip155:\\d+:(0x[0-9a-fA-F]{40})$/);\n if (evmMatch) return { address: evmMatch[1]!.toLowerCase(), network: 'evm' };\n // Solana CAIP-10: did:pkh:solana:<genesis-base58>:<address-base58>\n const solMatch = source?.match(/^did:pkh:solana:[1-9A-HJ-NP-Za-km-z]{32,44}:([1-9A-HJ-NP-Za-km-z]{32,44})$/);\n if (solMatch) return { address: solMatch[1]!, network: 'solana' };\n // Fallback: source not set by upstream client. Decode the credential's signed-tx\n // payload to find the SPL TransferChecked authority (= source-ATA owner = buyer\n // wallet). Pull mode only.\n const solanaFromTx = await extractSolanaSignerFromCredential(credential);\n if (solanaFromTx) return { address: solanaFromTx, network: 'solana' };\n }\n } catch (err) {\n console.warn('[gate] MPP signer extraction failed:', err instanceof Error ? err.message : err);\n }\n }\n\n return null;\n}\n\n/**\n * Headers-only variant for adapters that don't natively expose a Web Fetch `Request`\n * (Express, Fastify, ASGI-bridged frameworks). Constructs a synthetic Request carrying\n * only the `authorization` header and delegates to {@link extractPaymentSigner}. Works\n * because the MPP and x402 paths only read `request.headers.get('authorization')` and\n * the explicit `x402PaymentHeader` arg — no body, query, or method semantics needed.\n */\nexport async function extractPaymentSignerFromAuth(\n authHeader: string | null | undefined,\n x402PaymentHeader?: string,\n): Promise<PaymentSigner | null> {\n const request = new Request('http://internal.gate/', {\n headers: authHeader ? { authorization: authHeader } : {},\n });\n return extractPaymentSigner(request, x402PaymentHeader);\n}\n\n/**\n * Read the x402 payment header from a `Request`, matching the alternate names merchants might\n * use. Falls back to reading either header directly.\n */\nexport function readX402PaymentHeader(request: Request): string | undefined {\n return (\n request.headers.get('payment-signature') ??\n request.headers.get('x-payment') ??\n undefined\n );\n}\n\n/**\n * One-call signer extraction across both supported credential formats.\n *\n * Tries the x402 `payment-signature` / `x-payment` header first (EIP-3009\n * `payload.authorization.from`), then falls back to the MPP\n * `Authorization: Payment` header DID. Returns the first one that resolves,\n * or `null`.\n *\n * Use this for wallet-cap prechecks and other \"did the agent claim to sign as\n * X?\" checks where you need the signer BEFORE invoking Checkout. Checkout's\n * own settle path runs verification separately and surfaces the verified\n * signer on `SettleOutcome.signerAddress`.\n *\n * Accepts a plain headers dict so it works regardless of which framework the\n * merchant uses (the gate adapters all serialize headers down to a dict by\n * the time they reach the merchant's hooks).\n */\nexport async function extractSignerForPrecheck(\n headers: Record<string, string>,\n): Promise<PaymentSigner | null> {\n const lower = normalizeHeadersToLowercase(headers);\n const x402 = lower['payment-signature'] ?? lower['x-payment'];\n if (x402) {\n const signer = await extractPaymentSignerFromAuth(undefined, x402);\n if (signer !== null) return signer;\n }\n const authorization = lower['authorization'];\n if (authorization && authorization.toLowerCase().startsWith('payment ')) {\n return await extractPaymentSignerFromAuth(authorization);\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgCO,IAAM,yBAA8C,oBAAI,IAAI;AAAA,EACjE;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAUM,SAAS,gBAAgB,SAAiD;AAC/E,MAAI,CAAC,WAAW,QAAQ,WAAW,EAAG,QAAO;AAC7C,SAAO,QAAQ,MAAM,CAAC,MAAM,uBAAuB,IAAI,CAAC,CAAC;AAC3D;AAUO,SAAS,mBAAmB,QAAuC;AACxE,MAAI,OAAO,SAAS,mBAAmB,OAAO,SAAS,qBAAsB,QAAO;AACpF,MAAI,OAAO,SAAS,YAAa,QAAO;AACxC,SAAO;AACT;;;AC/BA,IAAM,kCAAkC,KAAK,UAAU;AAAA,EACrD,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAED,IAAM,gCAAgC,KAAK,UAAU;AAAA,EACnD,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAED,IAAM,uDAAuD,KAAK,UAAU;AAAA,EAC1E,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAED,IAAM,yBAAyB,KAAK,UAAU;AAAA,EAC5C,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAEM,IAAM,8BAA8B,KAAK,UAAU;AAAA,EACxD,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAED,IAAM,sCAAsC,KAAK,UAAU;AAAA,EACzD,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAED,IAAM,6BAAkE;AAAA,EACtE,WAAW;AAAA,EACX,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,gCAAgC;AAAA,EAChC,eAAe;AACjB;AAEA,IAAM,mBAA+C;AAAA,EACnD,kBACE;AAAA,EACF,gCACE;AAAA,EACF,oBACE;AAAA,EACF,WACE;AAAA,EACF,kBACE;AAAA,EACF,wBACE;AAAA,EACF,qCACE;AAAA,EACF,eACE;AAAA,EACF,oBACE;AACJ;AAKA,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAsDM,SAAS,mBAAmB,QAA+C;AAChF,QAAM,UAAU,OAAO,WAAW,iBAAiB,OAAO,IAAI;AAC9D,QAAM,OAAgC,EAAE,OAAO,EAAE,MAAM,OAAO,MAAM,QAAQ,EAAE;AAC9E,MAAI,OAAO,SAAU,MAAK,WAAW,OAAO;AAC5C,MAAI,OAAO,QAAS,MAAK,UAAU,OAAO;AAC1C,MAAI,OAAO,WAAY,MAAK,aAAa,OAAO;AAChD,MAAI,OAAO,WAAY,MAAK,aAAa,OAAO;AAChD,MAAI,OAAO,YAAa,MAAK,cAAc,OAAO;AAClD,MAAI,OAAO,SAAU,MAAK,WAAW,OAAO;AAC5C,QAAM,eAAe,OAAO,sBAAsB,2BAA2B,OAAO,IAAI;AACxF,MAAI,aAAc,MAAK,qBAAqB;AAC5C,MAAI,OAAO,aAAc,MAAK,eAAe,OAAO;AACpD,MAAI,OAAO,iBAAkB,MAAK,mBAAmB,OAAO;AAC5D,MAAI,OAAO,SAAS,yBAA0B,MAAK,yBAAyB,OAAO,0BAA0B;AAC7G,MAAI,OAAO,gBAAiB,MAAK,kBAAkB,OAAO;AAC1D,MAAI,OAAO,cAAe,MAAK,gBAAgB,OAAO;AACtD,MAAI,OAAO,kBAAkB,OAAO,eAAe,SAAS,EAAG,MAAK,iBAAiB,OAAO;AAC5F,MAAI,OAAO,OAAO;AAChB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,KAAK,GAAG;AACvD,UAAI,gBAAgB,IAAI,GAAG,GAAG;AAC5B,gBAAQ,KAAK,mDAAmD,GAAG,8CAAyC;AAC5G;AAAA,MACF;AACA,WAAK,GAAG,IAAI;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;;;AC1MA,IAAAA,eAAuE;;;ACEvE,kBAA4D;AAE5D,IAAM,EAAE,OAAO,IAAI,WAAW;AAM9B,IAAM,aAAa,CAAC,QAA4B;AAC9C,QAAM,MAAM,KAAK,GAAG;AACpB,QAAM,MAAM,IAAI,WAAW,IAAI,MAAM;AACrC,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AAAE,QAAI,CAAC,IAAI,IAAI,WAAW,CAAC;AAAA,EAAG;AACnE,SAAO;AACT;AASO,IAAM,yBAAyB,CAAC,WAAW,cAAc,SAAS,gBAAgB;AAGlF,IAAM,oBAAoB;AAIjC,IAAM,2BAA2B;AAU1B,IAAM,yBAAyB;AA2D/B,IAAM,qBAAqB,CAAC,cAA8B;AAC/D,QAAM,QAAQ,UAAU,KAAK,EAAE,YAAY;AAC3C,QAAM,QAAQ,MAAM,YAAY,GAAG;AACnC,MAAI,UAAU,IAAI;AAAE,WAAO;AAAA,EAAO;AAElC,MAAI,MAAM,SAAS,GAAG,KAAK,QAAQ,MAAM,QAAQ,GAAG,GAAG;AAAE,WAAO;AAAA,EAAO;AACvE,QAAM,OAAO,MAAM,MAAM,GAAG,KAAK;AACjC,QAAM,OAAO,MAAM,MAAM,QAAQ,CAAC;AAClC,MAAI,SAAS,QAAQ,SAAS,OAAO;AAAE,WAAO;AAAA,EAAM;AACpD,SAAO;AACT;AAGA,IAAM,iBAAiB,CACrB,MACA,UACkB;AAClB,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,MAAM,OAAO,YAAY;AAAA,IAClC,KAAK;AACH,aAAO,mBAAmB,MAAM,SAAS;AAAA,IAC3C,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AACH,aAAO,MAAM,cAAc,KAAK;AAAA,IAClC;AACE,aAAO,MAAM,QAAQ,IAAI,KAAK;AAAA,EAClC;AACF;AAGA,IAAM,yBAAyB,CAAC,eAC9B,IAAI,WAAW,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC;AAG/C,IAAM,kBAAkB,CAAC,MAA+B;AACtD,QAAM,QAAkB,CAAC;AACzB,MAAI,EAAE,YAAY,QAAW;AAAE,UAAM,KAAK,WAAW,EAAE,OAAO,EAAE;AAAA,EAAG;AACnE,MAAI,EAAE,YAAY,QAAW;AAAE,UAAM,KAAK,WAAW,EAAE,OAAO,EAAE;AAAA,EAAG;AACnE,MAAI,EAAE,UAAU,QAAW;AAAE,UAAM,KAAK,UAAU,EAAE,KAAK,GAAG;AAAA,EAAG;AAC/D,MAAI,EAAE,QAAQ,QAAW;AAAE,UAAM,KAAK,QAAQ,EAAE,GAAG,GAAG;AAAA,EAAG;AACzD,MAAI,EAAE,QAAQ,QAAW;AAAE,UAAM,KAAK,QAAQ,EAAE,GAAG,GAAG;AAAA,EAAG;AACzD,SAAO,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE;AAC1C;AAaO,IAAM,qBAAqB,CAChC,QACA,OACA,uBACW;AACX,QAAM,QAAkB,CAAC;AACzB,aAAW,QAAQ,OAAO,YAAY;AACpC,UAAM,QAAQ,eAAe,MAAM,KAAK;AACxC,QAAI,UAAU,MAAM;AAClB,YAAM,IAAI,sBAAsB,IAAI;AAAA,IACtC;AACA,UAAM,KAAK,IAAI,IAAI,MAAM,KAAK,EAAE;AAAA,EAClC;AACA,QAAM,cAAc,sBAAsB,uBAAuB,OAAO,UAAU,IAAI,gBAAgB,MAAM;AAC5G,QAAM,KAAK,wBAAwB,WAAW,EAAE;AAChD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,IAAM,wBAAN,cAAoC,MAAM;AAAA,EACxC,YAAmB,WAAmB;AACpC,UAAM,6CAA6C,SAAS,EAAE;AAD7C;AAEjB,SAAK,OAAO;AAAA,EACd;AAAA,EAHmB;AAIrB;AAUO,IAAM,sBAAsB,CAAC,QAAgB,MAAM,sBAA4F;AACpJ,QAAM,UAAU,gBAAgB,MAAM;AACtC,MAAI,QAAQ,WAAW,GAAG;AAAE,WAAO;AAAA,EAAM;AAEzC,QAAM,SAAS,QACZ,IAAI,CAAC,MAAM;AACV,UAAM,SAAS,qBAAqB,EAAE,KAAK;AAC3C,WAAO,SAAS,EAAE,OAAO,EAAE,OAAO,QAAQ,WAAW,EAAE,MAAM,IAAI;AAAA,EACnE,CAAC,EACA,OAAO,CAAC,MAA0E,MAAM,IAAI;AAE/F,MAAI,OAAO,WAAW,GAAG;AAAE,WAAO;AAAA,EAAM;AAExC,SAAO,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ,GAAG,KAAK;AACrD;AAMO,IAAM,sBAAsB,CAAC,QAAgB,UAAqC;AACvF,QAAM,UAAU,gBAAgB,MAAM;AACtC,QAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK;AACpD,MAAI,CAAC,QAAQ;AAAE,WAAO;AAAA,EAAM;AAC5B,QAAM,IAAI,OAAO,MAAM,KAAK;AAC5B,MAAI,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,EAAE,SAAS,GAAG;AAAE,WAAO;AAAA,EAAM;AAC3E,QAAM,MAAM,EAAE,MAAM,GAAG,EAAE;AACzB,MAAI;AACF,WAAO,WAAW,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUA,IAAM,kBAAkB,CAAC,WAAiC;AACxD,QAAM,MAAoB,CAAC;AAC3B,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,UAAU;AACd,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,KAAK,OAAO,CAAC;AACnB,QAAI,UAAU;AACZ,iBAAW;AACX,UAAI,OAAO,OAAO,OAAO,IAAI,CAAC,MAAM,MAAM;AAAE,mBAAW;AAAA,MAAO;AAC9D;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AAAE,iBAAW;AAAM,iBAAW;AAAI;AAAA,IAAU;AAC5D,QAAI,OAAO,KAAK;AAAE,gBAAU,CAAC;AAAS,iBAAW;AAAI;AAAA,IAAU;AAC/D,QAAI,CAAC,WAAW,OAAO,KAAK;AAAE;AAAS,iBAAW;AAAI;AAAA,IAAU;AAChE,QAAI,CAAC,WAAW,OAAO,KAAK;AAAE,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAG,iBAAW;AAAI;AAAA,IAAU;AACvF,QAAI,CAAC,WAAW,UAAU,KAAK,OAAO,KAAK;AACzC,iBAAW,KAAK,OAAO;AACvB,gBAAU;AACV;AAAA,IACF;AACA,eAAW;AAAA,EACb;AACA,aAAW,KAAK,OAAO;AACvB,SAAO;AACT;AAEA,IAAM,aAAa,CAAC,KAAmB,QAAsB;AAC3D,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,CAAC,SAAS;AAAE;AAAA,EAAQ;AACxB,QAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,MAAI,OAAO,IAAI;AAAE;AAAA,EAAQ;AACzB,QAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK;AACxC,QAAM,QAAQ,QAAQ,MAAM,KAAK,CAAC,EAAE,KAAK;AACzC,MAAI,OAAO;AAAE,QAAI,KAAK,EAAE,OAAO,MAAM,CAAC;AAAA,EAAG;AAC3C;AAGA,IAAM,uBAAuB,CAAC,UAA0C;AACtE,QAAM,OAAO,MAAM,QAAQ,GAAG;AAC9B,QAAM,QAAQ,MAAM,QAAQ,KAAK,OAAO,CAAC;AACzC,MAAI,SAAS,MAAM,UAAU,IAAI;AAAE,WAAO;AAAA,EAAM;AAChD,QAAM,WAAW,MAAM,MAAM,OAAO,GAAG,KAAK,EAAE,KAAK;AACnD,QAAM,aAAa,SAAS,WAAW,IACnC,CAAC,KACA,SAAS,MAAM,UAAU,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC;AAEhE,QAAM,SAA0B,EAAE,WAAW;AAC7C,QAAM,WAAW,MAAM,MAAM,QAAQ,CAAC;AAEtC,QAAM,KAAK;AACX,MAAI;AACJ,UAAQ,QAAQ,GAAG,KAAK,QAAQ,OAAO,MAAM;AAC3C,UAAM,MAAM,MAAM,CAAC;AACnB,UAAM,MAAM,MAAM,CAAC;AACnB,UAAM,MAAM,IAAI,WAAW,GAAG,IAAI,IAAI,MAAM,GAAG,EAAE,IAAI,OAAO,GAAG;AAC/D,QAAI,QAAQ,WAAW;AAAE,aAAO,UAAU;AAAA,IAAe,WAChD,QAAQ,WAAW;AAAE,aAAO,UAAU;AAAA,IAAe,WACrD,QAAQ,SAAS;AAAE,aAAO,QAAQ;AAAA,IAAe,WACjD,QAAQ,OAAO;AAAE,aAAO,MAAM;AAAA,IAAe,WAC7C,QAAQ,OAAO;AAAE,aAAO,MAAM;AAAA,IAAe;AAAA,EACxD;AACA,SAAO;AACT;AAsBO,IAAM,yBAAyB,OACpC,UAC0C;AAC1C,QAAM,WAAW,oBAAoB,MAAM,cAAc;AACzD,MAAI,CAAC,UAAU;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,mBAAmB;AAAA,EAAG;AACnE,QAAM,EAAE,OAAO,QAAQ,UAAU,IAAI;AAMrC,MAAI,OAAO,QAAQ,UAAa,CAAC,CAAC,WAAW,OAAO,EAAE,SAAS,OAAO,IAAI,YAAY,CAAC,GAAG;AACxF,WAAO,EAAE,IAAI,OAAO,QAAQ,kBAAkB;AAAA,EAChD;AAGA,aAAW,YAAY,wBAAwB;AAC7C,QAAI,CAAC,OAAO,WAAW,SAAS,QAAQ,GAAG;AACzC,aAAO,EAAE,IAAI,OAAO,QAAQ,4BAA4B;AAAA,IAC1D;AAAA,EACF;AAMA,MAAI,OAAO,YAAY,QAAW;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,kBAAkB;AAAA,EAAG;AACrF,MAAI,OAAO,YAAY,QAAW;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,kBAAkB;AAAA,EAAG;AAQrF,MAAI,OAAO,UAAU,OAAO,WAAW,OAAO,UAAU,OAAO,UAAU,wBAAwB;AAC/F,WAAO,EAAE,IAAI,OAAO,QAAQ,sBAAsB;AAAA,EACpD;AAEA,QAAM,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACrD,QAAM,OAAO,MAAM,kBAAkB;AACrC,MAAI,OAAO,UAAU,MAAM,MAAM;AAC/B,WAAO,EAAE,IAAI,OAAO,QAAQ,oBAAoB;AAAA,EAClD;AACA,MAAI,OAAO,UAAU,MAAM,MAAM;AAC/B,WAAO,EAAE,IAAI,OAAO,QAAQ,UAAU;AAAA,EACxC;AAEA,MAAI,CAAC,OAAO,OAAO;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,gBAAgB;AAAA,EAAG;AAQpE,QAAM,MAAM,MAAM;AAClB,MAAI,IAAI,QAAQ,SAAS,IAAI,QAAQ,aAAa,OAAO,IAAI,MAAM,YAAY,IAAI,EAAE,WAAW,GAAG;AACjG,WAAO,EAAE,IAAI,OAAO,QAAQ,sBAAsB;AAAA,EACpD;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,UAAM,oCAAuB,MAAM,QAAQ,QAAQ;AAAA,EAClE,QAAQ;AACN,WAAO,EAAE,IAAI,OAAO,QAAQ,sBAAsB;AAAA,EACpD;AACA,MAAI,OAAO,UAAU,YAAY;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,iBAAiB;AAAA,EAAG;AAEnF,QAAM,MAAM,oBAAoB,MAAM,WAAW,KAAK;AACtD,MAAI,CAAC,KAAK;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,sBAAsB;AAAA,EAAG;AAEjE,MAAI;AACJ,MAAI;AACF,WAAO,mBAAmB,QAAQ;AAAA,MAChC,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,eAAe,MAAM;AAAA,MACrB,OAAO,MAAM;AAAA,IACf,GAAG,SAAS;AAAA,EACd,SAAS,KAAK;AACZ,QAAI,eAAe,uBAAuB;AAAE,aAAO,EAAE,IAAI,OAAO,QAAQ,4BAA4B;AAAA,IAAG;AACvG,UAAM;AAAA,EACR;AAGA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,UAAM,uBAAU,MAAM,QAAQ,OAAO;AACjD,QAAI,EAAE,eAAe,YAAY;AAE/B,aAAO,EAAE,IAAI,OAAO,QAAQ,oBAAoB;AAAA,IAClD;AACA,YAAQ,MAAM,OAAO;AAAA,MACnB,EAAE,MAAM,UAAU;AAAA,MAClB;AAAA,MACA;AAAA,MACA,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA,IAC/B;AAAA,EACF,QAAQ;AAEN,WAAO,EAAE,IAAI,OAAO,QAAQ,oBAAoB;AAAA,EAClD;AACA,SAAO,QAAQ,EAAE,IAAI,MAAM,OAAO,IAAI,EAAE,IAAI,OAAO,QAAQ,oBAAoB;AACjF;;;AC3SA,IAAM,WAAW,CAAC,MAChB,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAEzD,IAAM,mBAAmB,CAAC,MAA4B,OAAO,MAAM,YAAY,EAAE,SAAS;AAMnF,IAAM,aAAa,CAAC,YACzB,SAAS,OAAO,KAAK,SAAS,QAAQ,GAAG,KAAK,SAAS,QAAQ,KAAK;AAG/D,IAAM,qBAAqB,CAAC,YAA0C;AAC3E,MAAI,CAAC,SAAS,OAAO,GAAG;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,gBAAgB;AAAA,EAAG;AACzE,MAAI,CAAC,iBAAiB,QAAQ,WAAW,GAAG;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,sBAAsB;AAAA,EAAG;AACnG,MAAI,CAAC,iBAAiB,QAAQ,GAAG,GAAG;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAAG;AACnF,MAAI,CAAC,iBAAiB,QAAQ,GAAG,GAAG;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAAG;AACnF,MAAI,OAAO,QAAQ,QAAQ,UAAU;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAAG;AACpF,MAAI,OAAO,QAAQ,QAAQ,UAAU;AAAE,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAAG;AACpF,MAAI,CAAC,SAAS,QAAQ,GAAG,KAAK,CAAC,SAAU,QAAQ,IAAgC,GAAG,GAAG;AACrF,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAC5C;AACA,MAAI,CAAC,SAAS,QAAQ,KAAK,KAAK,CAAC,iBAAkB,QAAQ,MAAkC,QAAQ,GAAG;AACtG,WAAO,EAAE,IAAI,OAAO,QAAQ,yBAAyB;AAAA,EACvD;AAGA,MAAI,QAAQ,gBAAgB,mBAAmB;AAC7C,UAAM,OAAO,QAAQ;AACrB,UAAM,MAAM,SAAS,IAAI,IAAI,KAAK,MAAM;AACxC,QAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,WAAW,GAAG;AAC3C,aAAO,EAAE,IAAI,OAAO,QAAQ,8BAA8B;AAAA,IAC5D;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,MAAM,QAA+B;AACpD;;;AF3JO,IAAM,wBAAwB;AAwE9B,IAAM,YAAY,OACvB,KACA,SAC6B;AAC7B,MAAI,IAAI,qBAAqB,WAAW,GAAG;AACzC,WAAO,EAAE,IAAI,OAAO,QAAQ,WAAW;AAAA,EACzC;AACA,MAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,WAAW;AACzC,WAAO,EAAE,IAAI,OAAO,QAAQ,wBAAwB;AAAA,EACtD;AAGA,QAAM,iBAAiB,IAAI;AAC3B,QAAM,YAAY,IAAI;AAEtB,MAAI,cAAgC;AAEpC,aAAW,OAAO,IAAI,sBAAsB;AAC1C,UAAM,QAAQ,YAAY,GAAG;AAG7B,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,mBAAS,oCAAsB,KAAK;AACpC,oBAAU,wBAAU,KAAK;AAAA,IAC3B,QAAQ;AACN,oBAAc;AACd;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,UAAa,OAAO,IAAI,YAAY,MAAM,QAAQ;AACnE,oBAAc;AACd;AAAA,IACF;AACA,QAAI,CAAC,WAAW,OAAO,GAAG;AACxB,oBAAc;AACd;AAAA,IACF;AAGA,UAAM,YAAY,mBAAmB,OAAO;AAC5C,QAAI,CAAC,UAAU,IAAI;AACjB,oBAAc;AACd;AAAA,IACF;AACA,UAAM,SAAS,UAAU;AAGzB,UAAM,YAAY,MAAM,KAAK,KAAK,OAAO,OAAO,KAAK,OAAO,GAAG;AAC/D,QAAI,CAAC,UAAU,IAAI;AAIjB,oBACE,UAAU,WAAW,sBAAsB,UAAU,WAAW,oBAC5D,qBACA;AACN;AAAA,IACF;AAKA,UAAM,oBAAoB,KAAK,kBAAkB;AACjD,QAAI;AACF,YAAM,SAAS,UAAM,wBAAU,UAAU,KAAK,aAAa,OAAO,GAAG,CAAC;AACtE,gBAAM,wBAAU,OAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,QAK7B,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,aAAa,KAAK,QAAQ,SAAY,IAAI,KAAK,KAAK,MAAM,GAAI,IAAI;AAAA,MACpE,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,oBAAc,SAAS,GAAG,IAAI,kBAAkB;AAChD;AAAA,IACF;AAIA,UAAM,SAAS,KAAK,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACvD,QAAI,OAAO,MAAM,SAAS,mBAAmB;AAC3C,oBAAc;AACd;AAAA,IACF;AAMA,QAAI,OAAO,MAAM,OAAO,OAAO,KAAK,sBAAsB,MAAM;AAC9D,oBAAc;AACd;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,uBAAuB;AAAA,MAC7C,QAAQ,IAAI;AAAA,MACZ,WAAW,IAAI;AAAA,MACf,MAAM,IAAI;AAAA;AAAA;AAAA;AAAA,MAIV,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA,QAAQ,OAAO,IAAI;AAAA,MACnB,KAAK,KAAK;AAAA,MACV,gBAAgB,KAAK;AAAA,IACvB,CAAC;AACD,QAAI,CAAC,UAAU,IAAI;AACjB,oBAAc;AACd;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,KAAK;AAAA,QACH,SAAS;AAAA,QACT,KAAK,OAAO;AAAA,QACZ,QAAQ,OAAO,IAAI;AAAA,QACnB;AAAA,QACA,mBAAmB;AAAA,UACjB,QAAQ,IAAI;AAAA,UACZ,WAAW,IAAI;AAAA,UACf,MAAM,IAAI;AAAA,UACV,iBAAiB;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,OAAO,QAAQ,YAAY;AAC1C;AAGA,IAAM,cAAc,CAAC,UAA0B;AAC7C,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,cAAc,KAAK,OAAO,IAAI,QAAQ,QAAQ,eAAe,EAAE,IAAI;AAC5E;AAOA,IAAM,mBAAmB,CAAC,SAAS,OAAO;AAE1C,IAAM,eAAe,CAAC,QAAyB,IAAI,YAAY,MAAM,UAAU,UAAU;AAGzF,IAAM,WAAW,CAAC,QAChB,OAAO,QAAQ,YAAY,QAAQ,QAAS,IAA0B,SAAS;;;AG/OjF,IAAM,2BAA2B,CAAC,YAA+B;AAC/D,QAAM,MAAM,QAAQ,IAAI,qBAAqB;AAC7C,MAAI,CAAC,KAAK;AAAE,WAAO,CAAC;AAAA,EAAG;AACvB,SAAO,IACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC/B;AAOA,IAAM,kBAAkB,CAAC,KAAc,QAAqB,IAAI,QAAQ,IAAI,MAAM,KAAK,IAAI;AAIpF,IAAM,gCAAgC,CAAC,KAAc,cAA6C;AACvG,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,SAAO;AAAA,IACL,QAAQ,IAAI;AAAA,IACZ,WAAW,aAAa,gBAAgB,KAAK,GAAG;AAAA,IAChD,MAAM,IAAI;AAAA,IACV,sBAAsB,yBAAyB,IAAI,OAAO;AAAA,IAC1D,gBAAgB,IAAI,QAAQ,IAAI,iBAAiB;AAAA,IACjD,WAAW,IAAI,QAAQ,IAAI,WAAW;AAAA,EACxC;AACF;AAGO,IAAM,yBAAyB,CAAC,QACrC,yBAAyB,IAAI,OAAO,EAAE,SAAS;;;AC2B1C,IAAM,eAAe,CAAC,YAAsC;AACjE,UAAQ,SAAS;AAAA,IACf,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAIH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAIO,IAAM,iBAAiB,CAAC,YAA+C;AAC5E,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAGA,IAAM,iBAAiB,CAAC,YAAsC;AAC5D,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAoBO,IAAM,oBAAoB,CAAC,SAA2B,iBAAsD;AACjH,QAAM,OAAO,aAAa,OAAO;AACjC,QAAM,OAAqB;AAAA,IACzB,MAAM,iBAAiB,IAAI;AAAA,IAC3B,OAAO,KAAK,QAAQ,MAAM,GAAG;AAAA,IAC7B,QAAQ,eAAe,OAAO;AAAA,IAC9B,QAAQ,eAAe,OAAO;AAAA,EAChC;AACA,MAAI,cAAc;AAChB,QAAI,SAAS,sBAAsB,aAAa,gBAAgB,QAAQ;AACtE,WAAK,kBAAkB,aAAa;AAAA,IACtC;AACA,QAAI,SAAS,uBAAuB;AAClC,UAAI,aAAa,gBAAgB,OAAQ,MAAK,kBAAkB,aAAa;AAC7E,UAAI,aAAa,uBAAuB,OAAW,MAAK,uBAAuB,aAAa;AAC5F,UAAI,aAAa,aAAa,OAAQ,MAAK,eAAe,aAAa;AAAA,IACzE;AAAA,EACF;AACA,SAAO;AACT;AAgFA,IAAM,aAAqC,EAAE,YAAY,GAAG,eAAe,GAAG,iBAAiB,EAAE;AAM1F,IAAM,yBAAyB,CACpC,SACA,oBACA,gBACkB;AAClB,MAAI,uBAAuB,QAAW;AACpC,UAAM,OAAO,WAAW,QAAQ,eAAe,YAAY,KAAK;AAChE,UAAM,OAAO,WAAW,kBAAkB,KAAK;AAC/C,QAAI,OAAO,MAAM;AACf,aAAO,uCAAuC,kBAAkB,yBAAyB,QAAQ,eAAe,YAAY;AAAA,IAC9H;AAAA,EACF;AACA,MAAI,gBAAgB,UAAa,YAAY,SAAS,GAAG;AACvD,UAAM,MAAM,MAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,QAAQ,KAAM,MAAO,CAAC;AACrE,QAAI,CAAC,IAAI,KAAK,CAAC,MAAM,YAAY,SAAS,CAAC,CAAC,GAAG;AAC7C,aAAO,uDAAuD,YAAY,KAAK,IAAI,CAAC,yBAAyB,IAAI,KAAK,IAAI,KAAK,MAAM;AAAA,IACvI;AAAA,EACF;AACA,SAAO;AACT;AAGO,IAAM,uBAAuB,CAAC,UAKhB;AAAA,EACnB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ,KAAK;AAAA,EACb,GAAI,KAAK,uBAAuB,UAAa,EAAE,sBAAsB,KAAK,mBAAmB;AAAA,EAC7F,GAAI,KAAK,gBAAgB,UAAa,KAAK,YAAY,SAAS,KAAK,EAAE,cAAc,KAAK,YAAY;AAAA,EACtG,GAAI,KAAK,mBAAmB,UAAa,KAAK,eAAe,SAAS,KAAK,EAAE,iBAAiB,KAAK,eAAe;AACpH;AAQA,IAAM,0BAA0B,CAAC,UAAgD;AAAA,EAC/E,GAAI,KAAK,mBAAmB,UAAa,EAAE,gBAAgB,KAAK,eAAe;AAAA,EAC/E,GAAI,KAAK,mBAAmB,UAAa,EAAE,gBAAgB,KAAK,eAAe;AAAA,EAC/E,GAAI,KAAK,sBAAsB,UAAa,EAAE,oBAAoB,KAAK,kBAAkB;AAAA,EACzF,GAAI,KAAK,eAAe,UAAa,EAAE,aAAa,KAAK,WAAW;AACtE;AAQA,IAAM,sBAAsB,OAAO,KAA2B,SAAqD;AACjH,QAAM,SAAS,MAAM,UAAU,KAAK,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,KAAK,gBAAgB,KAAK,eAAe,CAAC;AAC3G,MAAI,CAAC,OAAO,IAAI;AACd,WAAO,EAAE,IAAI,OAAO,MAAM,kBAAkB,OAAO,QAAQ,wBAAwB,IAAI,CAAC,EAAE;AAAA,EAC5F;AACA,QAAM,OAAO,uBAAuB,OAAO,IAAI,SAAS,KAAK,mBAAmB,KAAK,UAAU;AAC/F,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,qBAAqB;AAAA,QACzB,QAAQ;AAAA,QACR,GAAI,KAAK,sBAAsB,UAAa,EAAE,oBAAoB,KAAK,kBAAkB;AAAA,QACzF,GAAI,KAAK,eAAe,UAAa,EAAE,aAAa,KAAK,WAAW;AAAA,QACpE,GAAI,KAAK,mBAAmB,UAAa,EAAE,gBAAgB,KAAK,eAAe;AAAA,MACjF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,EAAE,IAAI,MAAM,KAAK,OAAO,IAAI;AACrC;AAGO,IAAM,qBAAqB,CAAC,KAAc,SAC/C,oBAAoB,8BAA8B,KAAK,KAAK,SAAS,GAAG,IAAI;;;ACtV9E,yBAA2B;AAC3B,iBAQO;;;ACAP,IAAM,mBAAmB;AAKlB,IAAM,kBAAkB,CAAC,YAC9B,iBAAiB,KAAK,OAAO,KAAK,CAAC,QAAQ,WAAW,IAAI;AAKrD,IAAM,mBAAmB,CAAC,YAA4B;AAC3D,MAAI,gBAAgB,OAAO,GAAG;AAAE,WAAO;AAAA,EAAS;AAChD,SAAO,QAAQ,YAAY;AAC7B;;;ACvBO,IAAM,WAAN,MAAkB;AAAA,EAIvB,YAAoB,cAAsB,UAAU,KAAO;AAAvC;AAClB,SAAK,UAAU;AAAA,EACjB;AAAA,EAFoB;AAAA,EAHZ,QAAQ,oBAAI,IAA6C;AAAA,EACzD;AAAA,EAMR,IAAI,KAA4B;AAC9B,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AAChC,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AACA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,KAAa,OAAU,OAAsB;AAC/C,QAAI,KAAK,MAAM,QAAQ,KAAK,SAAS;AACnC,WAAK,MAAM;AAAA,IACb;AACA,QAAI,KAAK,MAAM,QAAQ,KAAK,SAAS;AACnC,WAAK,YAAY,KAAK,MAAM,OAAO,KAAK,UAAU,CAAC;AAAA,IACrD;AACA,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB;AAAA,MACA,WAAW,KAAK,IAAI,KAAK,SAAS,KAAK;AAAA,IACzC,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,QAAc;AACpB,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,GAAG,CAAC,KAAK,KAAK,OAAO;AAC/B,UAAI,MAAM,EAAE,WAAW;AACrB,aAAK,MAAM,OAAO,CAAC;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,YAAY,OAAqB;AACvC,QAAI,UAAU;AACd,eAAW,OAAO,KAAK,MAAM,KAAK,GAAG;AACnC,UAAI,WAAW,MAAO;AACtB,WAAK,MAAM,OAAO,GAAG;AACrB;AAAA,IACF;AAAA,EACF;AACF;;;AFhCA,SAAS,qBAAqB,GAAmB;AAC/C,MAAI,MAAM,EAAE;AACZ,SAAO,MAAM,KAAK,EAAE,WAAW,MAAM,CAAC,MAAM,GAAc;AAC1D,SAAO,QAAQ,EAAE,SAAS,IAAI,EAAE,MAAM,GAAG,GAAG;AAC9C;AAmXA,IAAM,2BAA2B;AAKjC,IAAM,sCAAsC,KAAK,UAAU;AAAA,EACzD,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAED,IAAM,mDAAmD,KAAK,UAAU;AAAA,EACtE,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAMD,IAAM,kCAAkC,KAAK,UAAU;AAAA,EACrD,QAAQ;AAAA,EACR,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cACE;AACJ,CAAC;AAEM,SAAS,qBAAqB,mBAA+C;AAIlF,QAAM,MAAM;AACZ,QAAM,aAAa,sBAAsB,UAAa,kBAAkB,SAAS;AACjF,SAAO;AAAA,IACL,kCAAkC;AAAA,IAClC,iBACE;AAAA,IAKF,YAAY;AAAA,IACZ,yBAAyB,GAAG,GAAG;AAAA,IAC/B,gBAAgB;AAAA,MACd,QACE;AAAA,MAEF,gBACE;AAAA,MAEF,GAAI,cAAc;AAAA,QAChB,gBACE;AAAA,MAKJ;AAAA,IACF;AAAA,IACA,GAAI,cAAc,EAAE,qBAAqB,kBAAkB;AAAA,IAC3D,WACE;AAAA,IAIF,0BAA0B,CAAC,kBAAkB,aAAa;AAAA,IAC1D,6BAA6B,CAAC,gBAAgB;AAAA,EAChD;AACF;AAMO,SAAS,qBAAqB,SAAgD;AACnF,MAAI,CAAC,QAAQ,QAAQ;AACnB,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AAEA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,eAAe;AAAA,IACf,SAAS,aAAa;AAAA,IACtB,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,UAAU,qBAAqB,UAAU;AAC/C,QAAM,kBAAkB,qBAAqB,iBAAiB;AAE9D,QAAM,YAAY,yBAAyB,OAAW;AACtD,QAAM,kBAAkB,YAAY,GAAG,SAAS,KAAK,SAAS,MAAM;AAQpE,QAAM,MAAM,IAAI,sBAAW,EAAE,QAAQ,SAAS,WAAW,gBAAgB,CAAC;AAK1E,QAAM,kBAAkB,oBAAI,IAAwB;AACpD,WAAS,cAAc,eAAuB,gBAAqC;AACjF,UAAM,MAAM,GAAG,aAAa,IAAI,kBAAkB,EAAE;AACpD,QAAI,IAAI,gBAAgB,IAAI,GAAG;AAC/B,QAAI,CAAC,GAAG;AACN,UAAI,IAAI,sBAAW;AAAA,QACjB,QAAQ;AAAA,QACR,SAAS,kBAAkB;AAAA,QAC3B,WAAW;AAAA,MACb,CAAC;AACD,sBAAgB,IAAI,KAAK,CAAC;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,IAAI,SAA6B,eAAe,GAAI;AAOlE,iBAAe,qBAAqB,KAAiD;AACnF,QAAI,CAAC,uBAAwB,QAAO;AACpC,QAAI;AACF,YAAM,cAA2D,CAAC;AAClE,UAAI,uBAAuB,WAAW,KAAM,aAAY,UAAU,uBAAuB;AACzF,UAAI,uBAAuB,eAAe,KAAM,aAAY,eAAe,uBAAuB;AAElG,UAAI,uBAAuB,qBAAqB,QAAQ,QAAW;AACjE,YAAI;AACF,gBAAM,UAAU,MAAM,uBAAuB,kBAAkB,GAAG;AAClE,cAAI,SAAS,WAAW,KAAM,aAAY,UAAU,QAAQ;AAC5D,cAAI,SAAS,eAAe,KAAM,aAAY,eAAe,QAAQ;AAAA,QACvE,SAAS,KAAK;AACZ,kBAAQ,KAAK,gEAAgE,eAAe,QAAQ,IAAI,UAAU,GAAG;AAAA,QACvH;AAAA,MACF;AAIA,YAAM,aAAa,cAAc,uBAAuB,QAAQ,uBAAuB,OAAO;AAC9F,YAAM,OAAQ,MAAM,WAAW,cAAc;AAAA,QAC3C,GAAI,YAAY,YAAY,SAAY,EAAE,SAAS,YAAY,QAAQ,IAAI,CAAC;AAAA,QAC5E,GAAI,YAAY,iBAAiB,SAAY,EAAE,cAAc,YAAY,aAAa,IAAI,CAAC;AAAA,MAC7F,CAAC;AAMD,UACE,OAAO,KAAK,eAAe,YAC3B,OAAO,KAAK,gBAAgB,YAC5B,OAAO,KAAK,eAAe,UAC3B;AACA,gBAAQ,KAAK,6FAAwF;AACrG,eAAO;AAAA,MACT;AAIA,UAAI;AACJ,UAAI,uBAAuB,mBAAmB,QAAQ,QAAW;AAC/D,YAAI;AACF,gBAAM,cAAc;AAAA,YAClB,YAAY,KAAK;AAAA,YACjB,YAAY,KAAK;AAAA,YACjB,aAAa,KAAK;AAAA,YAClB,UAAU,KAAK;AAAA,YACf,YAAY,KAAK;AAAA,UACnB;AACA,gBAAM,SAAS,MAAM,uBAAuB,gBAAgB,KAAK,WAAW;AAC5E,cAAI,UAAU,OAAO,WAAW,SAAU,SAAQ;AAAA,QACpD,SAAS,KAAK;AACZ,kBAAQ,KAAK,8DAA8D,eAAe,QAAQ,IAAI,UAAU,GAAG;AAAA,QACrH;AAAA,MACF;AAKA,YAAM,eAAe,KAAK;AAC1B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,YAAY,KAAK;AAAA,QACjB,aAAa,KAAK;AAAA,QAClB,UAAU,KAAK;AAAA,QACf,oBAAoB,eAAe,KAAK,UAAU,YAAY,IAAI;AAAA,QAClE,cAAc;AAAA,QACd,GAAI,SAAS,EAAE,MAAM;AAAA,MACvB;AAAA,IACF,SAAS,KAAK;AAKZ,cAAQ,KAAK,iFAA4E,eAAe,QAAQ,IAAI,UAAU,GAAG;AACjI,aAAO;AAAA,IACT;AAAA,EACF;AAEA,iBAAe,SACb,UACA,KACA,QAC0B;AAG1B,QAAI,CAAC,YAAa,CAAC,SAAS,SAAS,KAAK,KAAK,CAAC,SAAS,eAAe,KAAK,KAAK,CAAC,SAAS,UAAU,KAAK,GAAI;AAO7G,UAAI,SAAU,QAAO,EAAE,MAAM,QAAQ;AAErC,YAAM,gBAAgB,MAAM,qBAAqB,GAAG;AACpD,UAAI,cAAe,QAAO,EAAE,MAAM,QAAQ,QAAQ,cAAc;AAMhE,YAAM,aAAa,sBAAsB,UAAa,kBAAkB,SAAS;AACjF,YAAM,UAAU,aACZ;AAAA,QACE,kEAAkE,kBAAkB,KAAK,IAAI,CAAC;AAAA,MAChG,IACA,CAAC;AACL,YAAM,8BAA8B,KAAK,UAAU;AAAA,QACjD,QAAQ;AAAA,QACR,OAAO;AAAA,UACL,GAAG;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,cACE;AAAA,MACJ,CAAC;AACD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,oBAAoB;AAAA,UACpB,cAAc;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AASA,UAAM,cAAc,SAAS,WACzB,WAAO,+BAAW,QAAQ,EAAE,OAAO,SAAS,QAAQ,EAAE,OAAO,KAAK,CAAC,KACnE,SAAS,eAAe,YAAY,MAAM,SAAS,UAAU,iBAAiB,SAAS,OAAO,IAAI;AAgBtG,UAAM,WAAW,SACb,KAAK,UAAU,CAAC,aAAa,OAAO,SAAS,iBAAiB,OAAO,OAAO,CAAC,CAAC,IAC9E,KAAK,UAAU,CAAC,WAAW,CAAC;AAEhC,UAAM,SAAS,MAAM,IAAI,QAAQ;AACjC,QAAI,QAAQ;AAKV,YAAM,gBAAgB,OAAO,MACzB,mBAAmB,UAAU,OAAO,GAA8B,IAClE;AACJ,UAAI,OAAO,OAAO;AAChB,cAAM,YAAY,OAAO;AACzB,cAAM,cAAc,WAAW;AAC/B,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAM;AAAA,UACN,GAAI,gBAAgB,UAAa,EAAE,OAAO,YAAY;AAAA,UACtD,GAAI,kBAAkB,UAAa,EAAE,eAAe,cAAc;AAAA,QACpE;AAAA,MACF;AAQA,UAAI,gBAAgB,OAAO,OAAO,GAAG;AACnC,cAAM,gBAAgB,MAAM,qBAAqB,GAAG;AACpD,YAAI,eAAe;AACjB,iBAAO,EAAE,MAAM,QAAQ,QAAQ,eAAe,GAAI,kBAAkB,UAAa,EAAE,eAAe,cAAc,EAAG;AAAA,QACrH;AAAA,MACF;AACA,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,UAAU,OAAO;AAAA,UACjB,SAAS,OAAO;AAAA,UAChB,YAAa,OAAO,KAA6C;AAAA,UACjE,MAAM,OAAO;AAAA,QACf;AAAA,QACA,GAAI,kBAAkB,UAAa,EAAE,eAAe,cAAc;AAAA,MACpE;AAAA,IACF;AAEA,UAAM,SAAkC,CAAC;AACzC,QAAI,cAAc,KAAM,QAAO,cAAc;AAC7C,QAAI,yBAAyB,KAAM,QAAO,0BAA0B;AACpE,QAAI,UAAU,KAAM,QAAO,UAAU;AACrC,QAAI,wBAAwB,KAAM,QAAO,wBAAwB;AACjE,QAAI,wBAAwB,KAAM,QAAO,wBAAwB;AAEjE,QAAI;AACJ,QAAI;AAIF,YAAM,OAAO;AAAA,QACX,OAAO;AAAA,QACP,GAAI,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,EAAE,OAAwB,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMpE,GAAI,UAAU,EAAE,QAAQ,EAAE,SAAS,OAAO,SAAS,SAAS,OAAO,QAAQ,EAAE;AAAA,MAC/E;AAOA,UAAI,SAAS,aAAa,UAAa,SAAS,iBAAiB,QAAW;AAC1E,cAAM,IAAI,MAAM,kGAAkG;AAAA,MACpH;AACA,YAAM,SAAS,SAAS,aAAa,UAAa,SAAS,iBAAiB,SACxE,MAAM,IAAI,OAAO,MAAM,EAAE,GAAG,MAAM,UAAU,SAAS,UAAU,cAAc,SAAS,aAAa,CAAC,IACpG,SAAS,UACP,MAAM,IAAI,OAAO,SAAS,SAAS,EAAE,GAAG,MAAM,eAAe,SAAS,cAAc,CAAC,IACrF,MAAM,IAAI,OAAO,MAAM,EAAE,GAAG,MAAM,eAAe,SAAS,cAAe,CAAC;AAChF,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,eAAe,iCAAsB;AACvC,YAAI,SAAU,QAAO,EAAE,MAAM,QAAQ;AACrC,eAAO,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,mBAAmB,EAAE;AAAA,MAC9D;AACA,UAAI,eAAe,8BAAmB;AAGpC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,MAAM,IAAI;AAAA,YACV,GAAI,IAAI,YAAY,EAAE,YAAY,IAAI,UAAU,IAAI,CAAC;AAAA,YACrD,GAAI,IAAI,YAAY,EAAE,YAAY,IAAI,UAAU,IAAI,CAAC;AAAA,YACrD,GAAI,IAAI,aAAa,EAAE,aAAa,IAAI,WAAW,IAAI,CAAC;AAAA,YACxD,GAAI,IAAI,UAAU,EAAE,UAAU,IAAI,QAAQ,IAAI,CAAC;AAAA,YAC/C,GAAI,IAAI,YAAY,EAAE,oBAAoB,KAAK,UAAU,IAAI,SAAS,EAAE,IAAI,CAAC;AAAA,YAC7E,GAAI,IAAI,cAAc,EAAE,cAAc,IAAI,YAA+B,IAAI,CAAC;AAAA,UAChF;AAAA,QACF;AAAA,MACF;AACA,UAAI,eAAe,mCAAwB;AAEzC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,oBAAoB;AAAA,YACpB,cAAc;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AACA,UAAI,eAAe,+BAAoB;AACrC,gBAAQ,KAAK,+CAA+C;AAC5D,YAAI,SAAU,QAAO,EAAE,MAAM,SAAS,UAAU,MAAM,aAAa,iBAAiB;AACpF,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ,EAAE,MAAM,aAAa,oBAAoB,4BAA4B;AAAA,QAC/E;AAAA,MACF;AACA,UAAI,eAAe,WAAAC,cAAiB;AAClC,gBAAQ,KAAK,gCAAgC,IAAI,OAAO;AACxD,YAAI,SAAU,QAAO,EAAE,MAAM,SAAS,UAAU,MAAM,aAAa,kBAAkB;AACrF,eAAO,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,YAAY,EAAE;AAAA,MACvD;AAKA,YAAM,SAAU,KAAoC;AACpD,YAAM,UAAU,eAAe,QAAQ,IAAI,OAAO;AAClD,UAAI,WAAW,KAAK;AAClB,gBAAQ,KAAK,2DAAsD;AACnE,YAAI,SAAU,QAAO,EAAE,MAAM,SAAS,UAAU,MAAM,aAAa,iBAAiB;AACpF,eAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQ,EAAE,MAAM,aAAa,oBAAoB,4BAA4B;AAAA,QAC/E;AAAA,MACF;AACA,UAAI,YAAY,kBAAkB,YAAY,cAAc;AAC1D,gBAAQ,KAAK,gDAAgD,eAAe,QAAQ,IAAI,UAAU,GAAG;AACrG,YAAI,SAAU,QAAO,EAAE,MAAM,SAAS,UAAU,MAAM,aAAa,kBAAkB;AACrF,eAAO,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,YAAY,EAAE;AAAA,MACvD;AAKA,YAAM,UAAW,KAAkC;AACnD,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,SAAS,UAAU,GAAG,OAAO,KAAK,GAAG,KAAK;AAChD,cAAQ,KAAK,gEAA2D,MAAM,EAAE;AAChF,UAAI,SAAU,QAAO,EAAE,MAAM,SAAS,UAAU,MAAM,aAAa,YAAY;AAC/E,aAAO,EAAE,MAAM,QAAQ,QAAQ,EAAE,MAAM,YAAY,EAAE;AAAA,IACvD;AAEA,UAAM,WAAW,KAAK;AACtB,UAAM,kBAAmB,KAAK,oBAAiC,CAAC;AAChE,UAAM,QAAQ,aAAa,WAAW,YAAY;AAElD,UAAM,IAAI,UAAU,EAAE,OAAO,UAAU,YAAY,QAAW,SAAS,iBAAiB,KAAK,KAAK,CAAC;AAKnG,UAAM,gBAAgB,mBAAmB,UAAU,IAAI;AAEvD,QAAI,OAAO;AAGT,YAAM,QAAQ,KAAK;AACnB,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,QACnC,GAAI,kBAAkB,UAAa,EAAE,cAAc;AAAA,MACrD;AAAA,IACF;AASA,QAAI,gBAAgB,eAAe,GAAG;AACpC,YAAM,gBAAgB,MAAM,qBAAqB,GAAG;AACpD,UAAI,eAAe;AACjB,eAAO,EAAE,MAAM,QAAQ,QAAQ,eAAe,GAAI,kBAAkB,UAAa,EAAE,cAAc,EAAG;AAAA,MACtG;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,UAAU,YAAY;AAAA,QACtB,SAAS;AAAA,QACT,YAAY,KAAK;AAAA,QACjB;AAAA,MACF;AAAA,MACA,GAAI,kBAAkB,UAAa,EAAE,cAAc;AAAA,IACrD;AAAA,EACF;AAEA,iBAAe,cAAcC,UAA8C;AACzE,QAAI;AACF,YAAM,IAAI,gBAAgB;AAAA,QACxB,eAAeA,SAAQ;AAAA,QACvB,eAAeA,SAAQ;AAAA,QACvB,SAASA,SAAQ;AAAA,QACjB,GAAIA,SAAQ,iBAAiB,EAAE,gBAAgBA,SAAQ,eAAe,IAAI,CAAC;AAAA,MAC7E,CAAC;AAAA,IACH,SAAS,KAAK;AAGZ,cAAQ,KAAK,+CAA+C,eAAe,QAAQ,IAAI,UAAU,GAAG;AAAA,IACtG;AAAA,EACF;AAKA,WAAS,mBACP,IACA,aACA,YAC0B;AAC1B,UAAM,OAAO,GAAG;AAChB,QAAI,SAAS,QAAQ;AACnB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,iBAAkB,GAAG,oBAAkD;AAAA,QACvE,gBAAiB,GAAG,mBAAiD;AAAA,MACvE;AAAA,IACF;AACA,QAAI,SAAS,uCAAuC;AAClD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,eAAgB,GAAG,kBAAyC;AAAA,QAC5D,mBACG,GAAG,sBAA6C;AAAA,MACrD;AAAA,IACF;AAEA,UAAM,SAAS,GAAG;AAClB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,iBAAkB,GAAG,oBAAkD;AAAA,MACvE,sBAAuB,GAAG,mBAAiD;AAAA,MAC3E,gBAAiB,GAAG,mBAA0C;AAAA,MAC9D,cAAe,GAAG,iBAAwC;AAAA,MAC1D,eAAe,MAAM,QAAQ,MAAM,IAC9B,OAAqB,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IACtE,CAAC;AAAA,MACL,mBACG,GAAG,sBAA6C;AAAA,IACrD;AAAA,EACF;AAYA,WAAS,mBACP,UACA,KAC2B;AAC3B,QACE,SAAS,YAAY,UACrB,SAAS,kBAAkB,UAC3B,SAAS,aAAa,QACtB;AACA,aAAO;AAAA,IACT;AACA,UAAM,WAAW,IAAI;AACrB,UAAM,eAAe,IAAI;AACzB,QAAI,CAAC,YAAY,CAAC,aAAc,QAAO;AACvC,UAAM,cAAc,iBAAiB,SAAS,OAAO;AAGrD,UAAM,aAAc,UAAU,iBAAwC;AACtE,WAAO;AAAA,MACL,cAAc,WAAW,mBAAmB,UAAU,aAAa,UAAU,IAAI;AAAA,MACjF,kBAAkB,gBAAgB;AAAA,IACpC;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,cAAc;AACnC;;;AGt9BA,SAAS,YAAY,MAAsB;AACzC,SAAO,KAAK,QAAQ,iBAAiB,CAAC,IAAI,KAAa,MAAc,MAAM,EAAE,YAAY,CAAC;AAC5F;AAEO,SAAS,WAAW,SAAsB,MAA6B;AAC5E,MAAI,OAAQ,QAAgC,QAAQ,YAAY;AAC9D,WAAQ,QAAuB,IAAI,IAAI;AAAA,EACzC;AACA,QAAM,MAAM;AACZ,QAAM,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,YAAY,CAAC,KAAK,IAAI,YAAY,IAAI,CAAC;AACvE,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,QAAQ,CAAC,KAAK,OAAO,EAAE,CAAC,MAAM,SAAU,QAAO,EAAE,CAAC;AAC5D,SAAO;AACT;AAEO,SAAS,UAAU,OAA2C;AACnE,SAAO,OAAQ,MAA2B,YAAY,YAAY,iBAAiB,UAC/E,MAAM,UACL;AACP;AAUO,SAAS,iBAAiB,OAAuC;AACtE,QAAM,UAAU,UAAU,KAAK;AAC/B,SAAO;AAAA,IACL,WAAW,SAAS,mBAAmB,KACvC,WAAW,SAAS,WAAW,KAC/B,WAAW,SAAS,eAAe,GAAG,WAAW,UAAU;AAAA,EAC7D;AACF;;;AC/BA,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAC3B,IAAM,iCAAiC;AAuBvC,eAAe,kCAAkC,YAA6C;AAC5F,QAAM,UAAW,WAAqE;AACtF,MAAI,CAAC,SAAS,eAAe,QAAQ,SAAS,cAAe,QAAO;AAEpE,QAAM,aAAa;AACnB,QAAM,MAAO,MAAM,OAAO,YAAY,MAAM,MAAM,IAAI;AACtD,MAAI,CAAC,KAAK,kBAAkB,CAAC,IAAI,yBAAyB,CAAC,IAAI,sCAAsC;AACnG,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAU,IAAI,eAAe,EAAE,OAAO,QAAQ,WAAW;AAC/D,UAAM,UAAU,IAAI,sBAAsB,EAAE,OAAO,OAAO;AAC1D,UAAM,UAAU,IAAI,qCAAqC,EAAE,OAAO,QAAQ,YAAY;AAOtF,eAAW,MAAM,QAAQ,cAAc;AACrC,YAAM,YAAY,QAAQ,eAAe,GAAG,mBAAmB;AAC/D,UAAI,cAAc,iBAAiB,cAAc,mBAAoB;AACrE,YAAM,OAAO,GAAG;AAChB,UAAI,CAAC,QAAQ,KAAK,WAAW,KAAK,KAAK,CAAC,MAAM,+BAAgC;AAC9E,YAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAC7C,YAAM,iBAAiB,eAAe,CAAC;AACvC,UAAI,mBAAmB,OAAW;AAKlC,UAAI,kBAAkB,QAAQ,eAAe,QAAQ;AACnD,gBAAQ;AAAA,UACN;AAAA,QAEF;AACA;AAAA,MACF;AACA,YAAM,YAAY,QAAQ,eAAe,cAAc;AACvD,UAAI,UAAW,QAAO;AAAA,IACxB;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,KAAK,2CAA2C,eAAe,QAAQ,IAAI,UAAU,GAAG;AAChG,WAAO;AAAA,EACT;AACF;AAkBA,eAAsB,qBACpB,SACA,mBAC+B;AAI/B,MAAI,mBAAmB;AACrB,QAAI;AACF,YAAM,UAAU,KAAK,iBAAiB;AACtC,YAAM,SAAS,KAAK,MAAM,OAAO;AAGjC,YAAM,OAAO,QAAQ,SAAS,eAAe;AAC7C,UAAI,OAAO,SAAS,YAAY,sBAAsB,KAAK,IAAI,GAAG;AAChE,eAAO,EAAE,SAAS,KAAK,YAAY,GAAG,SAAS,MAAM;AAAA,MACvD;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,yCAAyC,eAAe,QAAQ,IAAI,UAAU,GAAG;AAAA,IAChG;AAAA,EACF;AAGA,QAAM,aAAa,QAAQ,QAAQ,IAAI,eAAe;AACtD,MAAI,YAAY;AACd,QAAI;AACF,YAAM,aAAa;AACnB,YAAM,OAAQ,MAAM,OAAO,YAAY,MAAM,MAAM,IAAI;AAMvD,UAAI,MAAM,YAAY,qBAAqB,UAAU,GAAG;AACtD,cAAM,aAAa,KAAK,WAAW,YAAY,OAAO;AACtD,cAAM,SAAU,WAAmC;AACnD,cAAM,WAAW,QAAQ,MAAM,0CAA0C;AACzE,YAAI,SAAU,QAAO,EAAE,SAAS,SAAS,CAAC,EAAG,YAAY,GAAG,SAAS,MAAM;AAE3E,cAAM,WAAW,QAAQ,MAAM,4EAA4E;AAC3G,YAAI,SAAU,QAAO,EAAE,SAAS,SAAS,CAAC,GAAI,SAAS,SAAS;AAIhE,cAAM,eAAe,MAAM,kCAAkC,UAAU;AACvE,YAAI,aAAc,QAAO,EAAE,SAAS,cAAc,SAAS,SAAS;AAAA,MACtE;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,wCAAwC,eAAe,QAAQ,IAAI,UAAU,GAAG;AAAA,IAC/F;AAAA,EACF;AAEA,SAAO;AACT;AAuBO,SAAS,sBAAsB,SAAsC;AAC1E,SACE,QAAQ,QAAQ,IAAI,mBAAmB,KACvC,QAAQ,QAAQ,IAAI,WAAW,KAC/B;AAEJ;;;AZpIA,SAAS,uBAAuB,KAAyC;AACvE,QAAM,QAAQ,IAAI,QAAQ,IAAI,kBAAkB;AAChD,QAAM,OAAO,IAAI,QAAQ,IAAI,kBAAkB;AAC/C,QAAM,WAA0B,CAAC;AACjC,MAAI,SAAS,MAAM,SAAS,EAAG,UAAS,gBAAgB;AACxD,MAAI,QAAQ,KAAK,SAAS,EAAG,UAAS,UAAU;AAChD,MAAI,SAAS,iBAAiB,SAAS,QAAS,QAAO;AACvD,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAe,QAAgC;AACtE,SAAO,IAAI,SAAS,KAAK,UAAU,mBAAmB,MAAM,CAAC,GAAG;AAAA,IAC9D,QAAQ,mBAAmB,MAAM;AAAA,IACjC,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,EAChD,CAAC;AACH;AAkBO,SAAS,qBAAqB,SAAwE;AAC3G,QAAM,EAAE,kBAAkB,wBAAwB,WAAW,iBAAiB,GAAG,YAAY,IAAI;AACjG,QAAM,OAAO,qBAAqB,WAAoC;AAEtE,SAAO,OAAO,QAAuC;AACnD,UAAM,WAAW,gBAAgB,GAAG;AAKpC,UAAM,SAAS,MAAM,qBAAqB,KAAK,sBAAsB,GAAG,CAAC;AACzE,UAAM,UAAU,MAAM,KAAK,SAAS,UAAU,KAAK,MAAM;AAEzD,QAAI,QAAQ,SAAS,SAAS;AAC5B,YAAM,gBAAgB,UAAU,gBAC5B,CAAC,SACC,KAAK,cAAc,EAAE,eAAe,SAAS,eAAgB,GAAG,KAAK,CAAC,IACxE;AAMJ,YAAM,gBAAgB,QAAQ;AAC9B,YAAM,wBAAwB,UAAU,WAAW,CAAC,UAAU,gBAC1D,MAAM,gBACN;AACJ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,QAAQ;AAAA,QACd;AAAA,QACA,kBAAkB;AAAA,QAClB,GAAI,QAAQ,WAAW,EAAE,UAAU,MAAM,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,QAC/E,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,MAClD;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,SAAS,KAAK,QAAQ,MAAM;AACnD,WAAO,EAAE,SAAS,OAAO,SAAS;AAAA,EACpC;AACF;AAaO,SAAS,mBACd,SACA,SAsBiD;AACjD,QAAM,QAAQ,qBAAqB,OAAO;AAC1C,SAAO,OAAO,KAAK,QAAQ;AACzB,UAAM,SAAS,MAAM,MAAM,GAAG;AAC9B,QAAI,CAAC,OAAO,QAAS,QAAO,OAAO;AACnC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,QACE,MAAM,OAAO;AAAA,QACb,eAAe,OAAO;AAAA,QACtB,kBAAkB,OAAO;AAAA,QACzB,GAAI,OAAO,WAAW,EAAE,UAAU,MAAM,aAAa,OAAO,YAAY,IAAI,CAAC;AAAA,QAC7E,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,gCAAgC,SAAwE;AACtH,QAAM,QAAQ,qBAAqB,OAAO;AAC1C,SAAO,OAAO,QAAuC;AACnD,QAAI,CAAC,iBAAiB,GAAG,EAAG,QAAO,EAAE,SAAS,KAAK;AACnD,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;AAIO,SAAS,8BACd,SACA,SACgD;AAChD,QAAM,UAAU,mBAAyB,SAAS,OAAO;AACzD,SAAO,OAAO,KAAc,QAAiC;AAC3D,QAAI,CAAC,iBAAiB,GAAG,EAAG,QAAO,QAAQ,KAAK,CAAC,GAAG,GAAG;AACvD,WAAO,QAAQ,KAAK,GAAG;AAAA,EACzB;AACF;AAmBA,IAAM,qBAAqB,CAAC,SAC1B,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG,EAAE,QAAQ,KAAK,QAAQ,SAAS,EAAE,gBAAgB,2BAA2B,EAAE,CAAC;AAG9G,SAAS,cAAc,SAAuE;AACnG,QAAM,EAAE,UAAU,GAAG,SAAS,IAAI;AAClC,SAAO,OAAO,QAA0C;AACtD,UAAM,SAAS,MAAM,mBAAmB,KAAK,QAAQ;AACrD,QAAI,OAAO,IAAI;AAAE,aAAO,EAAE,SAAS,MAAM,KAAK,OAAO,IAAI;AAAA,IAAG;AAC5D,UAAM,OAAO,OAAO;AACpB,UAAM,WAAW,WAAW,MAAM,SAAS,KAAK,IAAI,IAAI,mBAAmB,IAAI;AAC/E,WAAO,EAAE,SAAS,OAAO,SAAS;AAAA,EACpC;AACF;AAGO,SAAS,YACd,SACA,SACiD;AACjD,QAAM,QAAQ,cAAc,OAAO;AACnC,SAAO,OAAO,KAAK,QAAQ;AACzB,UAAM,SAAS,MAAM,MAAM,GAAG;AAC9B,QAAI,CAAC,OAAO,SAAS;AAAE,aAAO,OAAO;AAAA,IAAU;AAC/C,WAAO,QAAQ,KAAK,EAAE,KAAK,OAAO,IAAI,GAAG,GAAG;AAAA,EAC9C;AACF;AAGO,SAAS,uBACd,SACA,SACiD;AACjD,QAAM,QAAQ,cAAc,OAAO;AACnC,SAAO,OAAO,KAAK,QAAQ;AACzB,QAAI,CAAC,uBAAuB,GAAG,GAAG;AAAE,aAAO,QAAQ,KAAK,CAAC,GAAG,GAAG;AAAA,IAAG;AAClE,UAAM,SAAS,MAAM,MAAM,GAAG;AAC9B,QAAI,CAAC,OAAO,SAAS;AAAE,aAAO,OAAO;AAAA,IAAU;AAC/C,WAAO,QAAQ,KAAK,EAAE,KAAK,OAAO,IAAI,GAAG,GAAG;AAAA,EAC9C;AACF;","names":["import_jose","SdkTimeoutError","options"]}
1
+ {"version":3,"sources":["../../src/identity/web.ts","../../src/_denial.ts","../../src/_response.ts","../../src/aip/verify.ts","../../src/aip/http-signature.ts","../../src/aip/types.ts","../../src/aip/request.ts","../../src/aip/gate.ts","../../src/core.ts","../../src/address.ts","../../src/cache.ts","../../src/payment/payment_header.ts","../../src/signer.ts"],"sourcesContent":["import { denialReasonStatus } from '../_denial';\nimport { denialReasonToBody } from '../_response';\nimport { buildAipErrorBody, evaluateAipRequest, type AipGateOptions } from '../aip/gate';\nimport { hasAgentIdentityHeader } from '../aip/request';\nimport { createAgentScoreCore } from '../core';\nimport { hasPaymentHeader } from '../payment/payment_header';\nimport { extractPaymentSigner, readX402PaymentHeader } from '../signer';\nimport type { VerifiedAit } from '../aip/verify';\nimport type {\n AgentIdentity,\n AgentScoreCoreOptions,\n AssessResult,\n CreateSessionOnMissing,\n DenialReason,\n FailOpenInfraReason,\n GateQuotaInfo,\n SignerVerdict,\n} from '../core';\n\ninterface AgentScoreGateOptions extends Omit<AgentScoreCoreOptions, 'createSessionOnMissing'> {\n /** Custom function to extract agent identity from a Request. */\n extractIdentity?: (req: Request) => AgentIdentity | undefined;\n /** Custom handler invoked when a request is denied. Must return a Response. */\n onDenied?: (req: Request, reason: DenialReason) => Response | Promise<Response>;\n /** Auto-create a verification session on missing identity. Hooks receive the `Request`. */\n createSessionOnMissing?: CreateSessionOnMissing<Request>;\n}\n\n/**\n * Result of a gate check. `allowed: true` means the request passed; forward it to your\n * handler. `allowed: false` means it was denied; return `response` directly to the client.\n *\n * When the request was authenticated via `operator_token`, `captureWallet` is bound to the\n * identity and can be called after payment to report the signer wallet back to AgentScore.\n * When the request was wallet-authenticated (nothing to associate), `captureWallet` is\n * undefined. Always fire-and-forget.\n */\nexport type GuardResult =\n | {\n allowed: true;\n data?: AssessResult;\n captureWallet?: (opts: {\n walletAddress: string;\n network: 'evm' | 'solana';\n idempotencyKey?: string;\n }) => Promise<void>;\n /** Synchronous read of the cached signer verdicts (`signer_match` wallet-binding\n * + `signer_sanctions` OFAC SDN wallet-address check). Both verdicts composed by\n * the gate's primary `/v1/assess` call in one round trip. Bound only on strict\n * wallet-auth requests; `undefined` otherwise (operator-token paths, discovery\n * legs, or routes the gate didn't run on). */\n getSignerVerdict?: () => SignerVerdict | undefined;\n /** Set to `true` only when the gate fail-open'd due to AgentScore-side infra failure\n * (429/5xx/network timeout). Compliance was NOT enforced this request — log/alert. */\n degraded?: boolean;\n /** Why the gate degraded — quota_exceeded / api_error / network_timeout. */\n infraReason?: FailOpenInfraReason;\n /** Per-account assess quota observability from X-Quota-* response headers. */\n quota?: GateQuotaInfo;\n }\n | { allowed: false; response: Response };\n\nfunction defaultExtractIdentity(req: Request): AgentIdentity | undefined {\n const token = req.headers.get('x-operator-token');\n const addr = req.headers.get('x-wallet-address');\n const identity: AgentIdentity = {};\n if (token && token.length > 0) identity.operatorToken = token;\n if (addr && addr.length > 0) identity.address = addr;\n if (identity.operatorToken || identity.address) return identity;\n return undefined;\n}\n\nfunction defaultOnDenied(_req: Request, reason: DenialReason): Response {\n return new Response(JSON.stringify(denialReasonToBody(reason)), {\n status: denialReasonStatus(reason),\n headers: { 'content-type': 'application/json' },\n });\n}\n\n/**\n * Create a Web Fetch-compatible gate. Works with any runtime that speaks the standard\n * Request/Response API: Cloudflare Workers, Deno Deploy, Bun, Next.js App Router, etc.\n *\n * ```ts\n * const guard = createAgentScoreGate({ apiKey: 'as_live_...', requireKyc: true });\n *\n * export default {\n * async fetch(req: Request) {\n * const result = await guard(req);\n * if (!result.allowed) return result.response;\n * return handle(req, result.data);\n * },\n * };\n * ```\n */\nexport function createAgentScoreGate(options: AgentScoreGateOptions): (req: Request) => Promise<GuardResult> {\n const { extractIdentity = defaultExtractIdentity, onDenied = defaultOnDenied, ...coreOptions } = options;\n const core = createAgentScoreCore(coreOptions as AgentScoreCoreOptions);\n\n return async (req: Request): Promise<GuardResult> => {\n const identity = extractIdentity(req);\n // Extract the payment signer pre-evaluate. When present, the API composes\n // signer_match + signer_sanctions verdicts on the primary assess response in one\n // round trip. Wallet-OFAC enforcement is unconditional — SDN wallet hits flip\n // decision -> deny inline before the handler runs, regardless of policy flags.\n const signer = await extractPaymentSigner(req, readX402PaymentHeader(req));\n const outcome = await core.evaluate(identity, req, signer);\n\n if (outcome.kind === 'allow') {\n const captureWallet = identity?.operatorToken\n ? (opts: { walletAddress: string; network: 'evm' | 'solana'; idempotencyKey?: string }) =>\n core.captureWallet({ operatorToken: identity.operatorToken!, ...opts })\n : undefined;\n // Synchronous getter — returns THIS request's signer verdicts (signer_match +\n // signer_sanctions), captured on the per-request `outcome` (NOT a shared core slot) so\n // concurrent same-wallet/different-signer requests can't read each other's verdict. Bound\n // on strict wallet-auth requests (the getter itself returns `undefined` when no signer was\n // in the request); absent for operator-token / AIT paths.\n const signerVerdict = outcome.signerVerdict;\n const getSignerVerdictBound = identity?.address && !identity?.operatorToken\n ? () => signerVerdict\n : undefined;\n return {\n allowed: true,\n data: outcome.data,\n captureWallet,\n getSignerVerdict: getSignerVerdictBound,\n ...(outcome.degraded ? { degraded: true, infraReason: outcome.infraReason } : {}),\n ...(outcome.quota ? { quota: outcome.quota } : {}),\n };\n }\n\n const response = await onDenied(req, outcome.reason);\n return { allowed: false, response };\n };\n}\n\n/**\n * Wrap a Web Fetch request handler with the gate. Denied requests are returned directly;\n * allowed requests are passed to `handler` along with the assess data.\n *\n * ```ts\n * export const POST = withAgentScoreGate(\n * { apiKey: 'as_live_...', requireKyc: true },\n * async (req, { data }) => Response.json({ ok: true }),\n * );\n * ```\n */\nexport function withAgentScoreGate<TCtx = unknown>(\n options: AgentScoreGateOptions,\n handler: (\n req: Request,\n gate: {\n data?: AssessResult;\n captureWallet?: (opts: {\n walletAddress: string;\n network: 'evm' | 'solana';\n idempotencyKey?: string;\n }) => Promise<void>;\n /** Synchronous read of the cached signer verdicts. See {@link GuardResult}'s\n * `getSignerVerdict` for the contract. */\n getSignerVerdict?: () => SignerVerdict | undefined;\n /** Set to `true` only when the gate fail-open'd due to AgentScore-side infra failure\n * (429/5xx/network timeout). Compliance was NOT enforced this request — log/alert. */\n degraded?: boolean;\n /** Why the gate degraded — quota_exceeded / api_error / network_timeout. */\n infraReason?: FailOpenInfraReason;\n /** Per-account assess quota observability from X-Quota-* response headers. */\n quota?: GateQuotaInfo;\n },\n ctx?: TCtx,\n ) => Response | Promise<Response>,\n): (req: Request, ctx?: TCtx) => Promise<Response> {\n const guard = createAgentScoreGate(options);\n return async (req, ctx) => {\n const result = await guard(req);\n if (!result.allowed) return result.response;\n return handler(\n req,\n {\n data: result.data,\n captureWallet: result.captureWallet,\n getSignerVerdict: result.getSignerVerdict,\n ...(result.degraded ? { degraded: true, infraReason: result.infraReason } : {}),\n ...(result.quota ? { quota: result.quota } : {}),\n },\n ctx,\n );\n };\n}\n\n/** Wrap `createAgentScoreGate(...)` so it only fires when a payment credential\n * is attached. Discovery legs flow through allowed (with `data: undefined`)\n * and the handler emits a 402 with all rails; settle legs run the full gate. */\nexport function createConditionalAgentScoreGate(options: AgentScoreGateOptions): (req: Request) => Promise<GuardResult> {\n const guard = createAgentScoreGate(options);\n return async (req: Request): Promise<GuardResult> => {\n if (!hasPaymentHeader(req)) return { allowed: true };\n return guard(req);\n };\n}\n\n/** Wrapper variant matching `withAgentScoreGate(opts, handler)` that only\n * invokes the gate when a payment credential is attached. */\nexport function withConditionalAgentScoreGate<TCtx = unknown>(\n options: AgentScoreGateOptions,\n handler: Parameters<typeof withAgentScoreGate<TCtx>>[1],\n): (req: Request, ctx: TCtx) => Promise<Response> {\n const wrapped = withAgentScoreGate<TCtx>(options, handler);\n return async (req: Request, ctx: TCtx): Promise<Response> => {\n if (!hasPaymentHeader(req)) return handler(req, {}, ctx);\n return wrapped(req, ctx);\n };\n}\n\n// ---------------------------------------------------------------------------\n// AIP gate (Agentic Identity Protocol) — Web Fetch\n//\n// `createAipGate` verifies a key-bound Agent Identity Token (AIT) from a trusted IdP and\n// returns a guard result; `withAipGate` wraps a handler. Fetch-native, so it reuses\n// `verifyAitRequest` directly. Identity verification only — merchants enrich via /v1/assess.\n// ---------------------------------------------------------------------------\n\nexport type AipGuardResult =\n | { allowed: true; ait: VerifiedAit }\n | { allowed: false; response: Response };\n\nexport interface AipGateWebOptions extends AipGateOptions {\n /** Custom denial responder. Defaults to a 401/403 `application/problem+json` Response. */\n onDenied?: (req: Request, body: ReturnType<typeof buildAipErrorBody>) => Response | Promise<Response>;\n}\n\nconst defaultAipResponse = (body: ReturnType<typeof buildAipErrorBody>): Response =>\n new Response(JSON.stringify(body), { status: body.status, headers: { 'content-type': 'application/problem+json' } });\n\n/** Create a Web Fetch AIP guard: returns `{ allowed, ait }` or `{ allowed: false, response }`. */\nexport function createAipGate(options: AipGateWebOptions): (req: Request) => Promise<AipGuardResult> {\n const { onDenied, ...gateOpts } = options;\n return async (req: Request): Promise<AipGuardResult> => {\n const result = await evaluateAipRequest(req, gateOpts);\n if (result.ok) { return { allowed: true, ait: result.ait }; }\n const body = result.body;\n const response = onDenied ? await onDenied(req, body) : defaultAipResponse(body);\n return { allowed: false, response };\n };\n}\n\n/** Wrap a Web Fetch handler with the AIP gate. Denied requests return the problem+json Response. */\nexport function withAipGate<TCtx = unknown>(\n options: AipGateWebOptions,\n handler: (req: Request, gate: { ait: VerifiedAit }, ctx?: TCtx) => Response | Promise<Response>,\n): (req: Request, ctx?: TCtx) => Promise<Response> {\n const guard = createAipGate(options);\n return async (req, ctx) => {\n const result = await guard(req);\n if (!result.allowed) { return result.response; }\n return handler(req, { ait: result.ait }, ctx);\n };\n}\n\n/** Conditional variant: only runs the AIP gate when an `Agent-Identity` header is present. */\nexport function withConditionalAipGate<TCtx = unknown>(\n options: AipGateWebOptions,\n handler: (req: Request, gate: { ait?: VerifiedAit }, ctx?: TCtx) => Response | Promise<Response>,\n): (req: Request, ctx?: TCtx) => Promise<Response> {\n const guard = createAipGate(options);\n return async (req, ctx) => {\n if (!hasAgentIdentityHeader(req)) { return handler(req, {}, ctx); }\n const result = await guard(req);\n if (!result.allowed) { return result.response; }\n return handler(req, { ait: result.ait }, ctx);\n };\n}\n","/**\n * Universal denial helpers shared across every adapter.\n *\n * What lives here:\n * - `FIXABLE_DENIAL_REASONS` / `isFixableDenial` — classifier for compliance reasons that can\n * be resolved by re-completing KYC (vs sanctions / age failures which are permanent).\n * - `denialReasonStatus` — picks the right HTTP status code per denial code (401 for credential\n * problems, 503 for transient API errors, 403 for everything else).\n * - `buildSignerMismatchBody` — produces the standard 403 body for a non-pass signer_match\n * verdict (read via `getSignerVerdict`).\n * - `buildContactSupportNextSteps` — standard `next_steps.action: \"contact_support\"` shape for\n * unfixable compliance denials.\n * - `verificationAgentInstructions` — the canned `agent_instructions` block for\n * identity-verification 403s. Vendors can override individual fields.\n *\n * Adapters use `denialReasonStatus` inside their default `onDenied` so vendors get the right\n * status code for free. The body builders are exported from each adapter so vendors who write\n * a custom `onDenied` can compose them without copy-paste.\n */\n\nimport type { DenialReason, VerifyWalletSignerResult } from './core';\n\n/**\n * Compliance denial reasons that can be resolved by re-completing KYC. The API emits these\n * when KYC is missing/pending/failed; the user can re-verify and retry.\n *\n * `jurisdiction_restricted` is NOT in this set — the API only emits it AFTER KYC is verified,\n * meaning the user's KYC'd country is in the merchant's blocked list (or absent from the\n * allowed list). Re-doing KYC won't change the country, so it's permanent. Same shape as\n * `sanctions_flagged` and `age_insufficient` — surface contact_support, don't waste a\n * /v1/sessions mint.\n */\nexport const FIXABLE_DENIAL_REASONS: ReadonlySet<string> = new Set([\n 'kyc_required',\n 'kyc_pending',\n 'kyc_failed',\n]);\n\n/**\n * Returns true when a `wallet_not_trusted` denial's reasons are all fixable via KYC\n * re-verification. False when any reason is permanent (sanctions, age, jurisdiction_restricted).\n *\n * Empty reasons returns false — without a known reason we can't promise a fix, so default to\n * the bare denial path (vendors can override via custom onDenied if they want different\n * behavior on empty reasons).\n */\nexport function isFixableDenial(reasons: readonly string[] | undefined): boolean {\n if (!reasons || reasons.length === 0) return false;\n return reasons.every((r) => FIXABLE_DENIAL_REASONS.has(r));\n}\n\n/**\n * The right HTTP status code for a denial. `defaultOnDenied` in every adapter uses this so\n * vendors get correct status codes without writing per-code branches.\n *\n * - 401 for credential problems the agent can recover from (`token_expired`, `invalid_credential`)\n * - 503 for transient `api_error`\n * - 403 for everything else (identity required, compliance fail, signer mismatch, etc.)\n */\nexport function denialReasonStatus(reason: DenialReason): 401 | 403 | 503 {\n if (reason.code === 'token_expired' || reason.code === 'invalid_credential') return 401;\n if (reason.code === 'api_error') return 503;\n return 403;\n}\n\n/**\n * Standard 403 body for a non-pass signer-match verdict. Returns null for `pass` so vendors\n * can call it unconditionally:\n *\n * const verdict = getSignerVerdict(c);\n * if (verdict?.signer_match) {\n * const mismatchBody = buildSignerMismatchBody({ result: verdict.signer_match });\n * if (mismatchBody) return c.json(mismatchBody, 403);\n * }\n *\n * Body shape mirrors the gate's denial bodies: top-level error.code, all signer-match fields\n * (`claimed_operator`, `actual_signer_operator`, `expected_signer`, `actual_signer`,\n * `linked_wallets`), plus a `next_steps` action describing the recovery path.\n */\nexport function buildSignerMismatchBody({\n result,\n userMessage,\n learnMoreUrl,\n}: {\n /** Projected signer_match verdict (from `getSignerVerdict(ctx).signer_match`). Only non-pass\n * kinds produce a body. */\n result: VerifyWalletSignerResult;\n /** Optional override for the human-facing `next_steps.user_message`. */\n userMessage?: string;\n /** Optional override for `next_steps.learn_more_url`. Default: AgentScore agent-identity guide. */\n learnMoreUrl?: string;\n}): Record<string, unknown> | null {\n if (result.kind === 'pass') return null;\n\n const learnMoreUrlResolved = learnMoreUrl ?? 'https://docs.agentscore.com/guides/agent-identity';\n\n if (result.kind === 'wallet_signer_mismatch') {\n const linkedWallets = result.linkedWallets ?? [];\n const userMessageResolved = userMessage ?? (linkedWallets.length > 0\n ? `Sign the payment with one of the wallets linked to this operator: ${linkedWallets.join(', ')}. Then retry.`\n : 'Sign the payment with the same wallet you claimed via X-Wallet-Address, or switch to X-Operator-Token for rail-independent identity.');\n return {\n error: {\n code: 'wallet_signer_mismatch',\n message:\n 'Payment signer does not match the wallet claimed via X-Wallet-Address. The signer and the claimed wallet must both resolve to the same AgentScore operator.',\n },\n claimed_operator: result.claimedOperator,\n actual_signer_operator: result.actualSignerOperator ?? null,\n expected_signer: result.expectedSigner,\n actual_signer: result.actualSigner,\n linked_wallets: linkedWallets,\n next_steps: {\n action: 'regenerate_payment_from_linked_wallet',\n user_message: userMessageResolved,\n learn_more_url: learnMoreUrlResolved,\n },\n };\n }\n\n // wallet_auth_requires_wallet_signing\n return {\n error: {\n code: 'wallet_auth_requires_wallet_signing',\n message:\n 'Wallet-auth requires a payment rail that carries a wallet signature (Tempo MPP, x402). Stripe SPT and card rails have no wallet signer; switch to X-Operator-Token to use those.',\n },\n next_steps: {\n action: 'switch_to_operator_token',\n user_message:\n userMessage ??\n 'Drop the X-Wallet-Address header and retry with X-Operator-Token (works on every payment rail).',\n learn_more_url: learnMoreUrlResolved,\n },\n };\n}\n\n/**\n * Standard `next_steps` block for unfixable compliance denials (sanctions, age, etc.). Vendors\n * spread this into a 403 body alongside the usual `error`/`reasons` fields.\n *\n * return c.json({\n * error: { code: 'compliance_denied', message: '...' },\n * reasons,\n * next_steps: buildContactSupportNextSteps('support@example.com'),\n * }, 403);\n */\nexport function buildContactSupportNextSteps(\n supportEmail: string,\n message?: string,\n): { action: 'contact_support'; support_email: string; user_message: string } {\n return {\n action: 'contact_support',\n support_email: supportEmail,\n user_message:\n message ??\n `If you believe this denial is in error, contact support at ${supportEmail} with the details of your request.`,\n };\n}\n\n/**\n * The canonical `agent_instructions` block for identity-verification 403s. Tells the agent how to\n * present the verify_url, poll for the operator_token, and retry the original request. Universal\n * across every AgentScore-gated merchant — overrides let vendors add merchant-specific steps\n * (e.g. \"include order_id when retrying\").\n */\nexport function verificationAgentInstructions({\n userAction,\n retryStep,\n extraSteps,\n pollIntervalSeconds = 5,\n timeoutSeconds = 3600,\n orderTtl,\n extra,\n}: {\n /** Override the user-facing message. */\n userAction?: string;\n /** Replace the generic \"Retry the original merchant request...\" step with a merchant-specific\n * one (e.g. \"Retry POST /purchase with X-Operator-Token AND include order_id...\"). When set,\n * this REPLACES baseSteps[4] rather than appending — use it instead of `extraSteps[0]` when\n * your retry instruction is a refinement of the canonical retry, not an additional step. */\n retryStep?: string;\n /** Append additional steps after the retry step. Use this for genuinely additional steps\n * (e.g. \"After payment the same call returns 200 with the order\"), not for re-stating the\n * retry — use `retryStep` for that. */\n extraSteps?: string[];\n /** Override the poll cadence. Default 5 seconds. */\n pollIntervalSeconds?: number;\n /** Override how long the agent should keep polling. Default 3600 seconds (1 hour). */\n timeoutSeconds?: number;\n /** Optional `order_ttl` note describing how long pending orders survive. */\n orderTtl?: string;\n /** Arbitrary additional fields merged into the instructions object. */\n extra?: Record<string, unknown>;\n} = {}): {\n action: 'poll_for_credential';\n user_action: string;\n steps: string[];\n poll_interval_seconds: number;\n poll_secret_header: 'X-Poll-Secret';\n retry_token_header: 'X-Operator-Token';\n timeout_seconds: number;\n order_ttl?: string;\n [key: string]: unknown;\n} {\n const baseSteps = [\n 'Present the verify_url directly to the user — it is a complete, ready-to-open URL with the session token already embedded (e.g. https://www.agentscore.com/verify?session=sess_...). Do NOT modify or construct the URL yourself.',\n `Immediately begin polling poll_url every ${pollIntervalSeconds} seconds with header X-Poll-Secret set to poll_secret. The user will complete verification in their browser while you poll in the background.`,\n 'The user visits the URL, signs in, completes identity verification (photo ID + selfie via Stripe Identity), and closes the tab. They do NOT need to copy or paste anything back to you.',\n 'When your poll returns status \"verified\", extract operator_token from the response. This is a one-time value — save it immediately. Subsequent polls return status \"consumed\" without the token.',\n retryStep ?? 'Retry the original merchant request with header X-Operator-Token set to the operator_token value.',\n ];\n\n return {\n action: 'poll_for_credential',\n user_action:\n userAction ??\n 'The user must visit verify_url to complete identity verification before this request can proceed',\n steps: extraSteps ? [...baseSteps, ...extraSteps] : baseSteps,\n poll_interval_seconds: pollIntervalSeconds,\n poll_secret_header: 'X-Poll-Secret',\n retry_token_header: 'X-Operator-Token',\n timeout_seconds: timeoutSeconds,\n ...(orderTtl ? { order_ttl: orderTtl } : {}),\n ...(extra ?? {}),\n };\n}\n","/**\n * Shared DenialReason → response body serialization for all adapters.\n *\n * Keeps Hono / Express / Fastify / Web / Next.js defaults aligned — a field added\n * here shows up in every adapter's 403 body automatically, and there's one place\n * to test the marshaling.\n *\n * Body shape: `{ error: { code, message }, ... }` — matches the canonical AgentScore\n * error envelope so downstream agents see one consistent `error.code` +\n * `error.message` pair regardless of which layer produced the denial.\n */\n\nimport type { DenialCode, DenialReason } from './core.js';\n\n/**\n * JSON-encoded canonical agent_instructions per denial code. Auto-injected by\n * `denialReasonToBody` when the gate produces a DenialReason without explicit\n * `agent_instructions` so every denial carries a machine-readable next step.\n *\n * Codes covered:\n * - `wallet_not_trusted` — gate never stamps instructions, fallback ensures coverage\n * - `payment_required` — gate never stamps; merchant tier misconfig, contact-merchant action\n * - `identity_verification_required` — fallback when API didn't return next_steps\n * - `token_expired` — fallback when API didn't return next_steps\n * - `api_error` — `retry_with_backoff` envelope; sole retry channel (no separate\n * next_steps block emitted)\n *\n * Codes already stamped explicitly upstream in core.ts (`missing_identity`,\n * `invalid_credential`) and codes that don't go through DenialReason\n * (`wallet_signer_mismatch`, `wallet_auth_requires_wallet_signing` — handled by\n * `getSignerVerdict` + `buildSignerMismatchBody`) are not in this map.\n */\nconst WALLET_NOT_TRUSTED_INSTRUCTIONS = JSON.stringify({\n action: 'contact_support',\n steps: [\n 'The wallet\\'s operator failed an UNFIXABLE compliance check (sanctions, age, or jurisdiction). `reasons` lists which: `sanctions_flagged` / `age_insufficient` / `jurisdiction_restricted`. KYC re-verification won\\'t change the outcome — the policy denial is structural.',\n 'Surface the denial to the user with the merchant\\'s support contact. Do not retry the same merchant request; do not hand the user a verify_url (verification won\\'t fix this code path).',\n 'Fixable compliance reasons (`kyc_required`, `kyc_pending`, `kyc_failed`) do NOT land on this code — the gate auto-mints a verification session for those and returns `identity_verification_required` with poll endpoints, same shape as `missing_identity`. `jurisdiction_restricted` IS in the unfixable bucket because the API only emits it after KYC is verified (the user\\'s KYC\\'d country is in the blocked list — re-doing KYC won\\'t change the country).',\n ],\n user_message:\n 'This purchase is denied by the merchant\\'s compliance policy and cannot be resolved by re-verifying. Contact the merchant\\'s support if you believe this is in error.',\n});\n\nconst PAYMENT_REQUIRED_INSTRUCTIONS = JSON.stringify({\n action: 'contact_merchant',\n steps: [\n 'The merchant\\'s AgentScore account does not have the assess endpoint enabled, so agent identity cannot be evaluated. This is a merchant-side configuration gap — there is no agent-side recovery.',\n 'Contact the merchant (their support channel — typically listed in /llms.txt or the OpenAPI servers metadata) so they can resolve the configuration on their side.',\n ],\n user_message:\n 'This merchant\\'s identity gate is misconfigured. Contact the merchant — there\\'s nothing to fix on the agent side.',\n});\n\nconst IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({\n action: 'deliver_verify_url_and_poll',\n steps: [\n 'Share verify_url with the user — they complete identity verification on AgentScore.',\n 'If session_id + poll_secret are present in the body, poll poll_url every 5 seconds with header `X-Poll-Secret: <poll_secret>` until status=verified. The poll returns a one-time operator_token.',\n 'Retry the original request with header `X-Operator-Token: <opc_...>`.',\n ],\n user_message:\n 'Identity verification is required. Visit verify_url, then poll poll_url for the operator token and retry.',\n});\n\nconst API_ERROR_INSTRUCTIONS = JSON.stringify({\n action: 'retry_with_backoff',\n steps: [\n 'Verification is temporarily unavailable. Retry the request after 5-30 seconds with exponential backoff.',\n 'This is NOT a compliance denial — the user does not need to re-verify their identity. Send the same identity headers (X-Wallet-Address or X-Operator-Token) on retry.',\n 'If the request continues to fail after 3+ retries (~60 seconds total), surface the error to the user with the merchant\\'s support contact.',\n ],\n user_message:\n 'Verification is temporarily unavailable. Please try again in a moment — this is a transient issue, not a problem with your account.',\n});\n\nexport const QUOTA_EXCEEDED_INSTRUCTIONS = JSON.stringify({\n action: 'contact_merchant',\n steps: [\n 'AgentScore identity verification is unavailable for this merchant. This is a merchant-side issue and is NOT recoverable via retry.',\n 'Do not retry: the same 503 will be returned until the merchant resolves the issue on their side.',\n 'Surface to the user with the merchant\\'s support contact. The merchant (not the agent) needs to act.',\n ],\n user_message:\n 'This merchant\\'s identity verification is temporarily unavailable. Try again later, or contact the merchant directly.',\n});\n\nconst TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS = JSON.stringify({\n action: 'deliver_verify_url_and_poll',\n steps: [\n 'The operator token is expired or revoked. AgentScore auto-mints a fresh verification session — complete it to receive a new opc_...',\n 'Share verify_url with the user, then poll poll_url every 5 seconds with header `X-Poll-Secret: <poll_secret>` until status=verified. The poll returns a fresh one-time operator_token.',\n 'Retry the original request with header `X-Operator-Token: <new_opc_...>`.',\n ],\n user_message:\n 'Operator token is expired or revoked. A new verification session has been minted — visit verify_url to refresh.',\n});\n\nconst DEFAULT_AGENT_INSTRUCTIONS: Partial<Record<DenialCode, string>> = {\n api_error: API_ERROR_INSTRUCTIONS,\n wallet_not_trusted: WALLET_NOT_TRUSTED_INSTRUCTIONS,\n payment_required: PAYMENT_REQUIRED_INSTRUCTIONS,\n identity_verification_required: IDENTITY_VERIFICATION_REQUIRED_FALLBACK_INSTRUCTIONS,\n token_expired: TOKEN_EXPIRED_FALLBACK_INSTRUCTIONS,\n};\n\nconst DEFAULT_MESSAGES: Record<DenialCode, string> = {\n missing_identity:\n 'No identity provided. Send X-Wallet-Address (wallet) or X-Operator-Token (credential).',\n identity_verification_required:\n 'Identity verification is required to access this resource. Visit verify_url to complete KYC.',\n wallet_not_trusted:\n 'The wallet does not meet the merchant compliance policy.',\n api_error:\n 'AgentScore is unreachable. This is transient — retry in a few seconds.',\n payment_required:\n 'Assess endpoint not enabled for this merchant. Contact support.',\n wallet_signer_mismatch:\n 'Payment signer does not match the wallet claimed via X-Wallet-Address. The signer and the claimed wallet must both resolve to the same AgentScore operator.',\n wallet_auth_requires_wallet_signing:\n 'X-Wallet-Address was sent with a rail that has no wallet signature (Stripe SPT / card). Switch to X-Operator-Token, or use a wallet-signing rail (Tempo MPP, x402).',\n token_expired:\n 'The operator token is expired or revoked. A fresh verification session has been minted — visit verify_url to mint a new token.',\n invalid_credential:\n 'The operator token is not recognized. Switch to a different stored token, or drop the header to bootstrap a fresh session.',\n};\n\n// Field names the gate claims authority over. Merchant-provided `extra` (from the\n// onBeforeSession hook) MUST NOT override these — a buggy or malicious hook could\n// otherwise replace `verify_url` with a phishing URL or drop agent_instructions.\nconst RESERVED_FIELDS = new Set([\n 'error',\n 'decision',\n 'reasons',\n 'verify_url',\n 'session_id',\n 'poll_secret',\n 'poll_url',\n 'agent_instructions',\n 'agent_memory',\n 'claimed_operator',\n 'actual_signer_operator',\n 'expected_signer',\n 'actual_signer',\n 'linked_wallets',\n]);\n\n/**\n * Build the canonical 4xx body shape for `identity_verification_required`.\n *\n * Every merchant maps the gate's auto-minted session fields (verify_url,\n * session_id, poll_secret, poll_url, agent_instructions) into their own\n * envelope with a merchant-specific message + error code. This collapses that\n * mapping into one call:\n *\n * ```ts\n * if (reason.code === 'identity_verification_required') {\n * return {\n * status: 403,\n * body: buildVerificationRequiredBody(reason, {\n * message: 'Identity verification is required to call this endpoint.',\n * agentInstructions: JSON.stringify(VERIFICATION_AGENT_INSTRUCTIONS),\n * }),\n * };\n * }\n * ```\n *\n * Goods merchants that surface an `order_id` (or similar) from\n * `createSessionOnMissing.onBeforeSession` get it for free via\n * `denialReasonToBody(reason)`'s `reason.extra` passthrough — but can also\n * pass `opts.extra` for fallbacks (e.g. when invoked outside the auto-mint\n * path and order_id needs to come from the validated context).\n */\nexport function buildVerificationRequiredBody(\n reason: DenialReason,\n opts: {\n /** Override the `error.message`. Defaults to the canonical copy. */\n message?: string;\n /** Replace `agent_instructions` with merchant-specific copy. When omitted,\n * the gate-supplied or default instructions ride through. */\n agentInstructions?: string;\n /** Additional fields spread into the body (e.g. fallback `order_id`). */\n extra?: Record<string, unknown>;\n } = {},\n): Record<string, unknown> {\n const body = denialReasonToBody(reason);\n body.error = {\n code: 'operator_verification_required',\n message: opts.message ?? 'Identity verification is required.',\n };\n if (opts.agentInstructions !== undefined) {\n body.agent_instructions = opts.agentInstructions;\n }\n if (opts.extra) {\n for (const [k, v] of Object.entries(opts.extra)) body[k] = v;\n }\n return body;\n}\n\nexport function denialReasonToBody(reason: DenialReason): Record<string, unknown> {\n const message = reason.message ?? DEFAULT_MESSAGES[reason.code];\n const body: Record<string, unknown> = { error: { code: reason.code, message } };\n if (reason.decision) body.decision = reason.decision;\n if (reason.reasons) body.reasons = reason.reasons;\n if (reason.verify_url) body.verify_url = reason.verify_url;\n if (reason.session_id) body.session_id = reason.session_id;\n if (reason.poll_secret) body.poll_secret = reason.poll_secret;\n if (reason.poll_url) body.poll_url = reason.poll_url;\n const instructions = reason.agent_instructions ?? DEFAULT_AGENT_INSTRUCTIONS[reason.code];\n if (instructions) body.agent_instructions = instructions;\n if (reason.agent_memory) body.agent_memory = reason.agent_memory;\n if (reason.claimed_operator) body.claimed_operator = reason.claimed_operator;\n if (reason.code === 'wallet_signer_mismatch') body.actual_signer_operator = reason.actual_signer_operator ?? null;\n if (reason.expected_signer) body.expected_signer = reason.expected_signer;\n if (reason.actual_signer) body.actual_signer = reason.actual_signer;\n if (reason.linked_wallets && reason.linked_wallets.length > 0) body.linked_wallets = reason.linked_wallets;\n if (reason.extra) {\n for (const [key, value] of Object.entries(reason.extra)) {\n if (RESERVED_FIELDS.has(key)) {\n console.warn(`[gate] onBeforeSession returned reserved field \"${key}\" — ignoring to preserve gate authority`);\n continue;\n }\n body[key] = value;\n }\n }\n return body;\n}\n","/**\n * AIP Agent Identity Token (AIT) verification pipeline — the verifier orchestrator.\n *\n * This is the function a merchant gate calls. It executes the spec's verification steps over\n * a presented request, composing the three foundation modules:\n * - {@link ./jwks} — trusted-issuer enforcement + key discovery\n * - {@link ./http-signature} — RFC 9421 proof-of-possession over the request\n * - {@link ./types} — AIT structural contract\n *\n * Steps (per spec):\n * 1. read the `Agent-Identity` header (one or more)\n * 2. decode the JWT header (`kid`) + payload; confirm AIT shape (`cnf` + `agent`)\n * 3. resolve the IdP's signing key from its JWKS (trusted-issuer + HTTPS enforced)\n * 4. verify the IdP signature on the JWT (reject `alg:none`; key is Ed25519)\n * 5. check `exp` / `iat` with skew\n * 6. extract `cnf.jwk`\n * 7. verify the RFC 9421 HTTP Message Signature with `cnf.jwk`\n * 8. confirm the signature `keyid` == JWK thumbprint of `cnf.jwk` (done inside step 7)\n *\n * On success it returns the validated, signature-checked claims. On failure it returns a\n * typed reason that maps onto AIP's wire error codes (the gate turns these into 401/403).\n */\n\nimport { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from 'jose';\nimport { verifyMessageSignature } from './http-signature';\nimport { isAitShape, validateAitPayload, type AitPayload } from './types';\nimport type { JwksCache } from './jwks';\n\n/** Header that carries the AIT JWT. */\nexport const AGENT_IDENTITY_HEADER = 'agent-identity';\n\n/** Request fields the verifier needs. Framework-agnostic; adapters map their req onto this. */\nexport interface VerifyRequestContext {\n method: string;\n authority: string;\n path: string;\n /** All `Agent-Identity` header values present on the request (one per IdP). */\n agentIdentityHeaders: string[];\n signatureInput: string | null;\n signature: string | null;\n}\n\nexport interface VerifyAitOptions {\n jwks: JwksCache;\n now?: number;\n maxSkewSeconds?: number;\n /** Max accepted AIT lifetime (`exp - iat`) in seconds. Defense-in-depth vs an external issuer\n * minting a long-lived bearer credential. The spec recommends a 60–300s window; default 300 so a\n * stolen AIT's usable window stays short even at the edge (standalone `aipGate`, no `/v1/assess`).\n * Our own mint is 300s, so first-party tokens sit exactly at the ceiling. Matches the\n * authoritative API verifier's default (the AgentScore API verifier), lowered from 3600. */\n maxLifetimeSeconds?: number;\n}\n\n/**\n * Failure reasons, aligned with AIP wire error codes. The gate maps:\n * no_token / malformed_token / invalid_signature / expired_token → 401\n * untrusted_issuer / weak_auth / invalid_claims → 403\n */\nexport type VerifyAitFailure =\n | 'no_token'\n | 'malformed_token'\n | 'untrusted_issuer'\n | 'key_unavailable'\n | 'idp_signature_invalid'\n | 'expired_token'\n | 'invalid_claims'\n | 'pop_signature_missing'\n | 'pop_signature_invalid';\n\nexport interface VerifiedAit {\n payload: AitPayload;\n /** The issuer (canonical, as presented). */\n iss: string;\n /** The agent's bound public key (`cnf.jwk`). */\n cnfJwk: AitPayload['cnf']['jwk'];\n /** The raw JWT string that verified (the winning `Agent-Identity` header value, Bearer\n * prefix stripped). Lets a gate forward the exact token to `/v1/assess` as `aip_token`. */\n token: string;\n /** The RFC 9421 signature material for this request — forwarded to `/v1/assess` as\n * `aip_signature` so the API re-verifies proof-of-possession authoritatively (the edge\n * check here is only a fail-fast filter; the API is the source of truth). */\n signatureMaterial: {\n method: string;\n authority: string;\n path: string;\n signature_input: string;\n signature: string;\n };\n}\n\nexport type VerifyAitResult =\n | { ok: true; ait: VerifiedAit }\n | { ok: false; reason: VerifyAitFailure };\n\n/**\n * Verify the AIP credential on a request. When multiple `Agent-Identity` headers are present,\n * each is tried; the first that fully verifies AND whose `cnf.jwk` matches the request's\n * RFC 9421 signature wins (all AITs on one request must share the same `cnf` key, so the PoP\n * signature is checked once against the winning key).\n */\nexport const verifyAit = async (\n ctx: VerifyRequestContext,\n opts: VerifyAitOptions,\n): Promise<VerifyAitResult> => {\n if (ctx.agentIdentityHeaders.length === 0) {\n return { ok: false, reason: 'no_token' };\n }\n if (!ctx.signatureInput || !ctx.signature) {\n return { ok: false, reason: 'pop_signature_missing' };\n }\n // Captured post-guard (string, not string|null) — reused for the local fail-fast PoP check and\n // forwarded to /v1/assess so the API can re-verify the same proof-of-possession authoritatively.\n const signatureInput = ctx.signatureInput;\n const signature = ctx.signature;\n\n let lastFailure: VerifyAitFailure = 'malformed_token';\n\n for (const raw of ctx.agentIdentityHeaders) {\n const token = stripBearer(raw);\n\n // Step 2: decode header + payload, confirm AIT shape.\n let header: { alg?: string; kid?: string };\n let payload: unknown;\n try {\n header = decodeProtectedHeader(token);\n payload = decodeJwt(token);\n } catch {\n lastFailure = 'malformed_token';\n continue;\n }\n if (header.alg === undefined || header.alg.toLowerCase() === 'none') {\n lastFailure = 'malformed_token';\n continue;\n }\n if (!isAitShape(payload)) {\n lastFailure = 'malformed_token';\n continue;\n }\n\n // Structural contract (incl. human_confirmed→amr).\n const validated = validateAitPayload(payload);\n if (!validated.ok) {\n lastFailure = 'invalid_claims';\n continue;\n }\n const claims = validated.payload;\n\n // Step 3: resolve IdP key (trusted-issuer + HTTPS enforced inside).\n const keyLookup = await opts.jwks.getKey(claims.iss, header.kid);\n if (!keyLookup.ok) {\n // `untrusted_issuer` (not on the allowlist) and `insecure_issuer` (http:// issuer) are both\n // PERMANENT trust failures → 403, not the retryable 503 of `key_unavailable` (a transient\n // JWKS-fetch problem). Don't tell an agent to retry a config error it can't fix.\n lastFailure =\n keyLookup.reason === 'untrusted_issuer' || keyLookup.reason === 'insecure_issuer'\n ? 'untrusted_issuer'\n : 'key_unavailable';\n continue;\n }\n\n // Step 4 + 5: verify IdP signature; enforce alg match + expiry/skew. The JWT iat/exp tolerance\n // and the RFC 9421 PoP `created`/`expires` window are both 60s (the AIP spec's recommended\n // window). An explicit `maxSkewSeconds` override, when set, applies to both.\n const jwtClockTolerance = opts.maxSkewSeconds ?? 60;\n try {\n const idpKey = await importJWK(keyLookup.key, normalizeAlg(header.alg));\n await jwtVerify(token, idpKey, {\n // Pin the signature algorithm allowlist (RFC 8725 §3.1) — also rejects `alg:none`. Without\n // this, jose accepts whatever alg the resolved JWK supports, so a trusted IdP publishing a\n // non-Ed25519 (e.g. RSA/EC) `use:sig` key would let an attacker present an RS256/ES256\n // token that verifies. Matches the server-side allowlist in the AgentScore API verifier.\n algorithms: AIT_SIGNING_ALGS,\n clockTolerance: jwtClockTolerance,\n currentDate: opts.now !== undefined ? new Date(opts.now * 1000) : undefined,\n });\n } catch (err) {\n lastFailure = isExpiry(err) ? 'expired_token' : 'idp_signature_invalid';\n continue;\n }\n\n // Spec step 5 also requires `iat` not be in the future. jose's `jwtVerify` validates `exp`/`nbf`\n // but does not reject a future `iat` by default, so check it explicitly (same skew tolerance).\n const nowSec = opts.now ?? Math.floor(Date.now() / 1000);\n if (claims.iat > nowSec + jwtClockTolerance) {\n lastFailure = 'expired_token';\n continue;\n }\n\n // Defense-in-depth: reject a long-lived AIT (spec recommends 60–300s). Own mint is exactly 300s,\n // so first-party tokens pass at the ceiling; this bites a trusted EXTERNAL issuer minting a\n // longer-lived bearer credential. Lowered 3600 → 300 (matching the authoritative API verifier)\n // to keep a stolen token's usable window short, complementing the now-mandatory PoP time bound.\n if (claims.exp - claims.iat > (opts.maxLifetimeSeconds ?? 300)) {\n lastFailure = 'expired_token';\n continue;\n }\n\n // Step 6 + 7 + 8: PoP — verify the RFC 9421 signature against cnf.jwk.\n const popResult = await verifyMessageSignature({\n method: ctx.method,\n authority: ctx.authority,\n path: ctx.path,\n // The agent-identity covered component is the BARE AIT (a Bearer prefix, if present, is\n // transport that `stripBearer` removed above). Verify over `token`, not `raw`, so the edge and\n // the API — which verifies over the forwarded bare aip_token — reconstruct the identical base.\n agentIdentity: token,\n signatureInput,\n signature,\n cnfJwk: claims.cnf.jwk,\n now: opts.now,\n maxSkewSeconds: opts.maxSkewSeconds,\n });\n if (!popResult.ok) {\n lastFailure = 'pop_signature_invalid';\n continue;\n }\n\n return {\n ok: true,\n ait: {\n payload: claims,\n iss: claims.iss,\n cnfJwk: claims.cnf.jwk,\n token,\n signatureMaterial: {\n method: ctx.method,\n authority: ctx.authority,\n path: ctx.path,\n signature_input: signatureInput,\n signature,\n },\n },\n };\n }\n\n return { ok: false, reason: lastFailure };\n};\n\n/** Strip an optional `Bearer ` prefix from a header value. */\nconst stripBearer = (value: string): string => {\n const trimmed = value.trim();\n return /^bearer\\s+/i.test(trimmed) ? trimmed.replace(/^bearer\\s+/i, '') : trimmed;\n};\n\n/** Map a JWT header `alg` to the JOSE alg name jose expects for key import. */\n/** Allowed AIT JWT signature algorithms (RFC 8725 §3.1 allowlist). EdDSA is AIP's default; ES256\n * is permitted for parity with the server-side verifier. Anything else (RS*, HS*, none) is\n * rejected at `jwtVerify`, regardless of what alg the token header claims or the resolved JWK\n * supports. */\nconst AIT_SIGNING_ALGS = ['EdDSA', 'ES256'];\n\nconst normalizeAlg = (alg: string): string => (alg.toLowerCase() === 'eddsa' ? 'EdDSA' : alg);\n\n/** jose throws JWTExpired with code 'ERR_JWT_EXPIRED' on expiry. */\nconst isExpiry = (err: unknown): boolean =>\n typeof err === 'object' && err !== null && (err as { code?: string }).code === 'ERR_JWT_EXPIRED';\n","/**\n * RFC 9421 HTTP Message Signatures — the AIP-constrained subset.\n *\n * AIP (Agentic Identity Protocol) binds an Agent Identity Token (AIT) to the\n * agent that presents it: the agent signs each HTTP request with the private key whose\n * public half is carried in the AIT's `cnf.jwk` (RFC 7800). A verifier reconstructs the\n * RFC 9421 signature base, verifies it against `cnf.jwk`, and confirms the signature's\n * `keyid` equals the JWK thumbprint (RFC 7638) of that key. A stolen AIT is then useless\n * without the bound private key.\n *\n * This module implements ONLY the shape AIP uses, not the full RFC 9421 grammar:\n *\n * - Covered components: the derived components `@method`, `@authority`, `@path`, plus the\n * `agent-identity` header field. (The AIP \"minimum required\" set.) Extra components in a\n * presented signature are accepted and covered if the caller supplies their values.\n * - One labeled signature per request, tagged `tag=\"agent-identity\"`. Web Bot Auth\n * signatures (`tag=\"web-bot-auth\"`) may coexist on the same request under a different\n * label; we select ours by tag, ignoring the rest.\n * - Algorithm: Ed25519 (EdDSA over OKP/Ed25519). AIP's default and only signing curve.\n *\n * The structured-field parsing here is deliberately narrow: it parses the AIP member of the\n * `Signature-Input` / `Signature` dictionaries (a parenthesized inner list + integer/string\n * params, and a single byte-sequence value). It is not a general RFC 8941 parser.\n */\n\nimport { calculateJwkThumbprint, importJWK, type JWK } from 'jose';\n\nconst { subtle } = globalThis.crypto;\n\n/** Runtime-agnostic base64 (standard, not base64url) codecs. The verify path runs on every AIT\n * check, including the Fetch-native web / nextjs adapters that target Cloudflare Workers / Vercel\n * Edge where the Node `Buffer` global is undefined — so decode/encode via `atob`/`btoa`, which are\n * available on every standards runtime (and Node ≥16). */\nconst b64ToBytes = (b64: string): Uint8Array => {\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) { out[i] = bin.charCodeAt(i); }\n return out;\n};\n\nconst bytesToB64 = (bytes: Uint8Array): string => {\n let bin = '';\n for (let i = 0; i < bytes.length; i++) { bin += String.fromCharCode(bytes[i]!); }\n return btoa(bin);\n};\n\n/** The AIP \"minimum required\" covered components, in canonical order. */\nexport const AIP_COVERED_COMPONENTS = ['@method', '@authority', '@path', 'agent-identity'] as const;\n\n/** Tag that identifies the AIP signature among coexisting RFC 9421 signatures. */\nexport const AIP_SIGNATURE_TAG = 'agent-identity';\n\n/** Default clock-skew tolerance (seconds) for `created` / `expires`. Aligned to the AIP spec's\n * recommended 60s window (and to the JWT iat/exp tolerance) so the whole AIP check uses one value. */\nconst DEFAULT_MAX_SKEW_SECONDS = 60;\n\n/** Hard ceiling on the PoP signature's own declared lifetime (`expires - created`), in seconds.\n * Requiring `created`+`expires` bounds replay to the declared window — but with no ceiling a\n * malicious trusted-issuer agent could set `expires = created + (AIT lifetime)` and replay for the\n * full window. Cap it tightly so every accepted PoP is short-lived. First-party `pay` signs a 60s\n * window, so it passes; this only bites a signer that declares an over-long PoP. Matches the\n * authoritative API verifier's `MAX_POP_WINDOW_SECONDS` (the AgentScore API verifier) so the\n * edge (standalone `aipGate`) and the API can't drift. (Distinct from the AIT JWT's `exp - iat`\n * ceiling in verify.ts — this is the HTTP-signature layer.) */\nexport const MAX_POP_WINDOW_SECONDS = 120;\n\n/** Parameters parsed from (or used to build) a `Signature-Input` member. */\nexport interface SignatureParams {\n components: string[];\n created?: number;\n expires?: number;\n keyid?: string;\n tag?: string;\n alg?: string;\n}\n\nexport interface VerifyMessageSignatureInput {\n /** HTTP method, e.g. `POST`. Case-insensitive; normalized to upper. */\n method: string;\n /** Authority (host[:port]), e.g. `wine-merchant.com`. Lowercased; default ports dropped. */\n authority: string;\n /** Request path (no query), e.g. `/checkout`. */\n path: string;\n /** Raw value of the `Agent-Identity` header the signature covers. */\n agentIdentity: string;\n /** Raw `Signature-Input` header value. */\n signatureInput: string;\n /** Raw `Signature` header value. */\n signature: string;\n /** The agent's public key from the AIT's `cnf.jwk`. */\n cnfJwk: JWK;\n /** Wall-clock seconds; defaults to now. Injectable for tests. */\n now?: number;\n /** Skew tolerance for created/expires. Defaults to {@link DEFAULT_MAX_SKEW_SECONDS}. */\n maxSkewSeconds?: number;\n /** Extra covered-component values, keyed by component name (for components beyond the AIP minimum). */\n extraComponents?: Record<string, string>;\n}\n\nexport type VerifyFailureReason =\n | 'no_aip_signature'\n | 'malformed_signature_input'\n | 'malformed_signature'\n | 'unsupported_alg'\n | 'missing_keyid'\n | 'keyid_mismatch'\n | 'missing_covered_component'\n | 'created_missing'\n | 'expires_missing'\n | 'pop_window_too_long'\n | 'created_in_future'\n | 'expired'\n | 'unsupported_cnf_key'\n | 'signature_invalid';\n\nexport type VerifyMessageSignatureResult =\n | { ok: true; params: SignatureParams }\n | { ok: false; reason: VerifyFailureReason };\n\n/**\n * Normalize an authority for `@authority` per RFC 9421 §2.2.3: lowercase, drop the default\n * port for the scheme. We don't know the scheme here, so we drop the common defaults (80/443).\n */\nexport const normalizeAuthority = (authority: string): string => {\n const lower = authority.trim().toLowerCase();\n const colon = lower.lastIndexOf(':');\n if (colon === -1) { return lower; }\n // Guard against IPv6 literals like `[::1]` with no port.\n if (lower.includes(']') && colon < lower.indexOf(']')) { return lower; }\n const host = lower.slice(0, colon);\n const port = lower.slice(colon + 1);\n if (port === '80' || port === '443') { return host; }\n return lower;\n};\n\n/** Serialize one derived/header component value into its signature-base line value. */\nconst componentValue = (\n name: string,\n input: { method: string; authority: string; path: string; agentIdentity: string; extra?: Record<string, string> },\n): string | null => {\n switch (name) {\n case '@method':\n return input.method.toUpperCase();\n case '@authority':\n return normalizeAuthority(input.authority);\n case '@path':\n return input.path;\n case 'agent-identity':\n return input.agentIdentity.trim();\n default:\n return input.extra?.[name] ?? null;\n }\n};\n\n/** Serialize the inner-list of covered components: `(\"@method\" \"@authority\" ...)`. */\nconst serializeComponentList = (components: string[]): string =>\n `(${components.map((c) => `\"${c}\"`).join(' ')})`;\n\n/** Serialize the `;k=v` params suffix in canonical order. */\nconst serializeParams = (p: SignatureParams): string => {\n const parts: string[] = [];\n if (p.created !== undefined) { parts.push(`created=${p.created}`); }\n if (p.expires !== undefined) { parts.push(`expires=${p.expires}`); }\n if (p.keyid !== undefined) { parts.push(`keyid=\"${p.keyid}\"`); }\n if (p.alg !== undefined) { parts.push(`alg=\"${p.alg}\"`); }\n if (p.tag !== undefined) { parts.push(`tag=\"${p.tag}\"`); }\n return parts.map((s) => `;${s}`).join('');\n};\n\n/**\n * Build the RFC 9421 signature base: one line per covered component, then the\n * `@signature-params` line. Components are joined by `\\n` with no trailing newline.\n * Throws if a covered component has no available value.\n *\n * On the VERIFY path, pass `rawSignatureParams` — the member value exactly as received from\n * `Signature-Input` — so the base reproduces the signer's serialization byte-for-byte regardless\n * of the order they emitted the params in (RFC 9421 §2.3 puts no order on them). Without it the\n * line is re-serialized in our canonical order (the SIGN path), which would wrongly reject a\n * spec-legal signer that ordered params differently.\n */\nexport const buildSignatureBase = (\n params: SignatureParams,\n input: { method: string; authority: string; path: string; agentIdentity: string; extra?: Record<string, string> },\n rawSignatureParams?: string,\n): string => {\n const lines: string[] = [];\n for (const name of params.components) {\n const value = componentValue(name, input);\n if (value === null) {\n throw new MissingComponentError(name);\n }\n lines.push(`\"${name}\": ${value}`);\n }\n const paramsValue = rawSignatureParams ?? serializeComponentList(params.components) + serializeParams(params);\n lines.push(`\"@signature-params\": ${paramsValue}`);\n return lines.join('\\n');\n};\n\nclass MissingComponentError extends Error {\n constructor(public component: string) {\n super(`signature base missing covered component: ${component}`);\n this.name = 'MissingComponentError';\n }\n}\n\n/**\n * Parse a `Signature-Input` dictionary and return the member tagged `tag`. The tag is REQUIRED\n * (the AIP spec mandates `tag=\"agent-identity\"`): an untagged member is skipped like any\n * wrong-tagged member. `rawParams` is the member's value exactly as received (the inner list +\n * its parameters, byte-for-byte, trimmed of surrounding OWS only) — the verifier echoes it into\n * the `\"@signature-params\"` base line so the signer's param order is preserved.\n * Returns null if no AIP member is found or the member is malformed.\n */\nexport const parseSignatureInput = (header: string, tag = AIP_SIGNATURE_TAG): { label: string; params: SignatureParams; rawParams: string } | null => {\n const members = splitDictionary(header);\n if (members.length === 0) { return null; }\n\n const parsed = members\n .map((m) => {\n const params = parseInnerListMember(m.value);\n return params ? { label: m.label, params, rawParams: m.value } : null;\n })\n .filter((x): x is { label: string; params: SignatureParams; rawParams: string } => x !== null);\n\n if (parsed.length === 0) { return null; }\n\n return parsed.find((p) => p.params.tag === tag) ?? null;\n};\n\n/**\n * Parse a `Signature` dictionary and return the byte-sequence value for `label`.\n * RFC 8941 byte sequences are `:<base64>:`.\n */\nexport const parseSignatureValue = (header: string, label: string): Uint8Array | null => {\n const members = splitDictionary(header);\n const member = members.find((m) => m.label === label);\n if (!member) { return null; }\n const v = member.value.trim();\n if (!v.startsWith(':') || !v.endsWith(':') || v.length < 2) { return null; }\n const b64 = v.slice(1, -1);\n try {\n return b64ToBytes(b64);\n } catch {\n return null;\n }\n};\n\n/** A single `label=value` member of a structured-field dictionary. */\ninterface DictMember { label: string; value: string; }\n\n/**\n * Split a dictionary header into `label=value` members at top-level commas, respecting\n * parentheses (inner lists) and colon-delimited byte sequences so commas inside them\n * don't split. Narrow but correct for the AIP shapes we emit/consume.\n */\nconst splitDictionary = (header: string): DictMember[] => {\n const out: DictMember[] = [];\n let depth = 0;\n let inBytes = false;\n let inString = false;\n let current = '';\n for (let i = 0; i < header.length; i++) {\n const ch = header[i];\n if (inString) {\n current += ch;\n if (ch === '\"' && header[i - 1] !== '\\\\') { inString = false; }\n continue;\n }\n if (ch === '\"') { inString = true; current += ch; continue; }\n if (ch === ':') { inBytes = !inBytes; current += ch; continue; }\n if (!inBytes && ch === '(') { depth++; current += ch; continue; }\n if (!inBytes && ch === ')') { depth = Math.max(0, depth - 1); current += ch; continue; }\n if (!inBytes && depth === 0 && ch === ',') {\n pushMember(out, current);\n current = '';\n continue;\n }\n current += ch;\n }\n pushMember(out, current);\n return out;\n};\n\nconst pushMember = (out: DictMember[], raw: string): void => {\n const trimmed = raw.trim();\n if (!trimmed) { return; }\n const eq = trimmed.indexOf('=');\n if (eq === -1) { return; }\n const label = trimmed.slice(0, eq).trim();\n const value = trimmed.slice(eq + 1).trim();\n if (label) { out.push({ label, value }); }\n};\n\n/** Parse an inner-list member value: `(\"@method\" ...);created=...;keyid=\"...\";tag=\"...\"`. */\nconst parseInnerListMember = (value: string): SignatureParams | null => {\n const open = value.indexOf('(');\n const close = value.indexOf(')', open + 1);\n if (open === -1 || close === -1) { return null; }\n const listBody = value.slice(open + 1, close).trim();\n const components = listBody.length === 0\n ? []\n : (listBody.match(/\"[^\"]*\"/g) ?? []).map((s) => s.slice(1, -1));\n\n const params: SignatureParams = { components };\n const paramStr = value.slice(close + 1);\n // Match ;key=value where value is an integer or a quoted string.\n const re = /;\\s*([a-zA-Z][a-zA-Z0-9_-]*)\\s*=\\s*(\"(?:[^\"\\\\]|\\\\.)*\"|-?\\d+)/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(paramStr)) !== null) {\n const key = match[1];\n const raw = match[2];\n const val = raw.startsWith('\"') ? raw.slice(1, -1) : Number(raw);\n if (key === 'created') { params.created = val as number; }\n else if (key === 'expires') { params.expires = val as number; }\n else if (key === 'keyid') { params.keyid = val as string; }\n else if (key === 'tag') { params.tag = val as string; }\n else if (key === 'alg') { params.alg = val as string; }\n }\n return params;\n};\n\n/**\n * Verify an AIP HTTP Message Signature. Performs the full check:\n * 1. select the AIP-tagged member of `Signature-Input`\n * 2. confirm the AIP minimum covered components are present\n * 3. REQUIRE both `created` and `expires`, reject an over-long declared window\n * (`expires - created` > MAX_POP_WINDOW_SECONDS → `pop_window_too_long`), then enforce them\n * against `now` with skew tolerance. Both are mandatory: an optional time bound is no time\n * bound — without `expires` a captured `(token, Signature-Input, Signature)` triple is\n * replayable for the whole AIT lifetime. A signature omitting either is rejected\n * (`created_missing` / `expires_missing`). This matches the authoritative API verifier\n * (the AgentScore API verifier) so a merchant running `aipGate` STANDALONE (the\n * crypto-identity-only deployment with no `/v1/assess`) gets the same replay defense.\n * 4. confirm `keyid` equals the RFC 7638 thumbprint of `cnf.jwk`\n * 5. reconstruct the signature base and verify Ed25519 over it\n *\n * NOTE: this is a STATELESS verifier — it bounds the replay WINDOW but does not dedupe within it.\n * A captured triple can still be replayed until `expires` (≤ MAX_POP_WINDOW_SECONDS + skew from\n * `created`). A stateful seen-signature cache (as in the authoritative API) is out of scope for the\n * SDK edge; the tight window bound is the meaningful mitigation here.\n */\nexport const verifyMessageSignature = async (\n input: VerifyMessageSignatureInput,\n): Promise<VerifyMessageSignatureResult> => {\n const selected = parseSignatureInput(input.signatureInput);\n if (!selected) { return { ok: false, reason: 'no_aip_signature' }; }\n const { label, params, rawParams } = selected;\n\n // The `alg` param is optional in RFC 9421 (the verifier derives the algorithm from the key);\n // when a signer does include it, the registered HTTP-sig label is `ed25519`. Accept that plus the\n // JWS spelling `EdDSA`, case-insensitively, so a spec-loose external signer isn't wrongly rejected\n // — the actual key type is still pinned to OKP/Ed25519 below, so this only affects the label.\n if (params.alg !== undefined && !['ed25519', 'eddsa'].includes(params.alg.toLowerCase())) {\n return { ok: false, reason: 'unsupported_alg' };\n }\n\n // All AIP-minimum components must be covered.\n for (const required of AIP_COVERED_COMPONENTS) {\n if (!params.components.includes(required)) {\n return { ok: false, reason: 'missing_covered_component' };\n }\n }\n\n // REQUIRE both `created` and `expires`. Treating them as optional leaves an unbounded replay\n // window — a captured signature with no `expires` is valid for the AIT's full lifetime. Reject\n // when either is absent so every accepted PoP carries an explicit, enforceable time bound. (Our\n // pay signer always emits both with a 60s window; this only rejects spec-loose external signers.)\n if (params.created === undefined) { return { ok: false, reason: 'created_missing' }; }\n if (params.expires === undefined) { return { ok: false, reason: 'expires_missing' }; }\n\n // Bound the PoP's own declared lifetime. created+expires alone only bound replay to whatever\n // window the SIGNER chose — a malicious trusted-issuer agent could declare a window as wide as the\n // AIT lifetime and replay for all of it. Reject an over-long window so every accepted PoP is\n // short-lived. (pay signs 60s; this only bites a signer declaring > MAX_POP_WINDOW_SECONDS.)\n // A NEGATIVE window (expires before created) is equally malformed — without the explicit check\n // it would slip under the cap (negative < 120).\n if (params.expires < params.created || params.expires - params.created > MAX_POP_WINDOW_SECONDS) {\n return { ok: false, reason: 'pop_window_too_long' };\n }\n\n const now = input.now ?? Math.floor(Date.now() / 1000);\n const skew = input.maxSkewSeconds ?? DEFAULT_MAX_SKEW_SECONDS;\n if (params.created > now + skew) {\n return { ok: false, reason: 'created_in_future' };\n }\n if (params.expires < now - skew) {\n return { ok: false, reason: 'expired' };\n }\n\n if (!params.keyid) { return { ok: false, reason: 'missing_keyid' }; }\n\n // The RFC 9421 proof-of-possession is verified with the agent's `cnf` key, which AIP binds as\n // Ed25519 (OKP). Validate the key shape BEFORE thumbprinting / importing: a malformed JWK\n // (missing or non-string `x`) makes `calculateJwkThumbprint` throw, and a non-OKP key (e.g. a\n // P-256 EC cnf) makes `importJWK(... 'EdDSA')` throw JOSENotSupported. Neither call site below\n // catches, so an unguarded throw would crash the gate — reject with a typed failure instead.\n // (Note: the JWT alg allowlist permits ES256 for the IDP *issuer* signing key, a different key.)\n const cnf = input.cnfJwk as { kty?: unknown; crv?: unknown; x?: unknown };\n if (cnf.kty !== 'OKP' || cnf.crv !== 'Ed25519' || typeof cnf.x !== 'string' || cnf.x.length === 0) {\n return { ok: false, reason: 'unsupported_cnf_key' };\n }\n\n let thumbprint: string;\n try {\n thumbprint = await calculateJwkThumbprint(input.cnfJwk, 'sha256');\n } catch {\n return { ok: false, reason: 'unsupported_cnf_key' };\n }\n if (params.keyid !== thumbprint) { return { ok: false, reason: 'keyid_mismatch' }; }\n\n const sig = parseSignatureValue(input.signature, label);\n if (!sig) { return { ok: false, reason: 'malformed_signature' }; }\n\n let base: string;\n try {\n base = buildSignatureBase(params, {\n method: input.method,\n authority: input.authority,\n path: input.path,\n agentIdentity: input.agentIdentity,\n extra: input.extraComponents,\n }, rawParams);\n } catch (err) {\n if (err instanceof MissingComponentError) { return { ok: false, reason: 'missing_covered_component' }; }\n throw err;\n }\n\n // cnf key shape (OKP/Ed25519 with a string `x`) was validated above, before thumbprinting.\n let valid: boolean;\n try {\n const key = await importJWK(input.cnfJwk, 'EdDSA');\n if (!(key instanceof CryptoKey)) {\n // jose returns a Uint8Array for symmetric keys; Ed25519 public is always a CryptoKey.\n return { ok: false, reason: 'signature_invalid' };\n }\n valid = await subtle.verify(\n { name: 'Ed25519' },\n key,\n sig as unknown as ArrayBuffer,\n new TextEncoder().encode(base) as unknown as ArrayBuffer,\n );\n } catch {\n // Any crypto/import failure is a verification failure, never an uncaught throw.\n return { ok: false, reason: 'signature_invalid' };\n }\n return valid ? { ok: true, params } : { ok: false, reason: 'signature_invalid' };\n};\n\nexport interface SignMessageInput {\n method: string;\n authority: string;\n path: string;\n agentIdentity: string;\n /** Agent private key (Ed25519 JWK with `d`). */\n privateJwk: JWK;\n /** Agent public key; used to derive `keyid` (thumbprint). */\n publicJwk: JWK;\n created?: number;\n expires?: number;\n /** Signature dictionary label. Defaults to `ait`. */\n label?: string;\n components?: string[];\n extraComponents?: Record<string, string>;\n}\n\n/** Build the `Signature-Input` and `Signature` header values for an AIP request. */\nexport const signMessage = async (\n input: SignMessageInput,\n): Promise<{ signatureInput: string; signature: string }> => {\n const label = input.label ?? 'ait';\n const components = input.components ?? [...AIP_COVERED_COMPONENTS];\n const created = input.created ?? Math.floor(Date.now() / 1000);\n const keyid = await calculateJwkThumbprint(input.publicJwk, 'sha256');\n\n const params: SignatureParams = {\n components,\n created,\n expires: input.expires,\n keyid,\n tag: AIP_SIGNATURE_TAG,\n };\n\n const base = buildSignatureBase(params, {\n method: input.method,\n authority: input.authority,\n path: input.path,\n agentIdentity: input.agentIdentity,\n extra: input.extraComponents,\n });\n\n const key = await importJWK(input.privateJwk, 'EdDSA');\n if (!(key instanceof CryptoKey)) {\n throw new Error('signMessage: expected an Ed25519 private CryptoKey');\n }\n const sigBytes = await subtle.sign(\n 'Ed25519',\n key,\n new TextEncoder().encode(base) as unknown as ArrayBuffer,\n );\n const b64 = bytesToB64(new Uint8Array(sigBytes));\n\n const signatureInput = `${label}=${serializeComponentList(components)}${serializeParams(params)}`;\n const signature = `${label}=:${b64}:`;\n return { signatureInput, signature };\n};\n","/**\n * AIP (Agentic Identity Protocol) token types and the claim contract.\n *\n * An Agent Identity Token (AIT) is a JWT signed by an Identity Provider (IdP). It binds a\n * verified human's identity to the specific agent presenting it (via `cnf`, RFC 7800) and\n * carries the trust level, authentication method, optional intent, and optional identity\n * claims the IdP attests to.\n *\n * This module is the single source of truth for the claim shape on the verifier side. It\n * encodes the spec's required / recommended / optional claims plus the AgentScore extension\n * claims (sanctions, jurisdiction, structured id-verification, cross-merchant graph, payment\n * signer) we carry when we act as a compliance IdP.\n *\n * Extensibility contract (per spec): the `identity` object is open. If a claim is present,\n * the IdP attests to it; verifiers ignore claims they don't recognize. Absence is the\n * \"unknown\" signal — IdPs do not ship `null` for \"not checked\".\n */\n\nimport type { JWK } from 'jose';\n\n/** Degree of human involvement in issuing this specific AIT. */\nexport type TrustLevel = 'autonomous' | 'human_present' | 'human_confirmed';\n\n/**\n * Authentication Method Reference values (RFC 8176 / IANA AMR registry). Open set — these\n * are the values relevant to agent identity; others are valid and pass through.\n */\nexport type AmrValue = 'face' | 'fpt' | 'hwk' | 'otp' | 'pin' | 'pwd' | 'sms' | 'swk' | 'user' | 'mfa';\n\n/** RFC 7800 confirmation claim: binds the AIT to the agent's signing key. */\ninterface CnfClaim {\n jwk: JWK;\n}\n\n/** Agent metadata. `provider` is required; `instance` is recommended. */\ninterface AgentClaim {\n provider: string;\n instance?: string;\n}\n\n/** How the user authorized THIS AIT (not prior authentication history). */\ninterface AuthClaim {\n amr?: AmrValue[] | string[];\n /** When the user authenticated for this token (Unix seconds). Mirrors OIDC `auth_time`. */\n time?: number;\n}\n\n/** What the agent intends to do. Optional; verifiers may require it for non-read actions. */\nexport interface IntentClaim {\n actions?: string[];\n description?: string;\n}\n\n/** AgentScore wallet-binding extension (orthogonal to `cnf`, which binds the agent key). */\ninterface PaymentSignerClaim {\n address: string;\n network: 'evm' | 'solana';\n /** Relationship the IdP attests between signer and the operator graph. */\n match?: 'linked_operator' | 'claimed_operator';\n}\n\ninterface PaymentClaim {\n signer?: PaymentSignerClaim;\n}\n\n/**\n * Identity claims (presence == IdP attestation). Spec-defined fields plus AgentScore\n * compliance extension claims. Open by contract — unknown fields are allowed and ignored.\n */\nexport interface IdentityClaim {\n email?: string;\n email_verified?: boolean;\n name?: string;\n phone?: string;\n phone_verified?: boolean;\n age_over_18?: boolean;\n age_over_21?: boolean;\n id_verified?: boolean;\n\n // --- AgentScore compliance extensions ---\n id_verification?: {\n provider?: string;\n method?: string;\n document_type?: string;\n verified_at?: number;\n };\n /** ISO 3166-1 alpha-2, optionally with ISO 3166-2 subdivision (e.g. \"US-CA\"). */\n jurisdiction?: string;\n sanctions_clear?: boolean;\n sanctions_checked_at?: number;\n sanctions_providers?: string[];\n linked_wallets?: Array<{ address: string; network: 'evm' | 'solana' }>;\n merchants_paid?: number;\n first_seen?: number;\n\n // Open extension space.\n [claim: string]: unknown;\n}\n\n/** The decoded AIT JWT payload. */\nexport interface AitPayload {\n aip_version: string;\n iss: string;\n sub: string;\n iat: number;\n exp: number;\n cnf: CnfClaim;\n agent: AgentClaim;\n trust_level?: TrustLevel;\n auth?: AuthClaim;\n intent?: IntentClaim;\n identity?: IdentityClaim;\n payment?: PaymentClaim;\n [claim: string]: unknown;\n}\n\n/** The decoded AIT JWT header. */\nexport interface AitHeader {\n alg: string;\n typ?: string;\n kid?: string;\n [param: string]: unknown;\n}\n\n/**\n * Structural validation of a decoded AIT payload. Confirms the required claims are present\n * and well-typed, and enforces the one normative conditional in the spec: a\n * `human_confirmed` token MUST carry at least one `auth.amr` value.\n *\n * This is shape/contract validation only — it does NOT verify signatures (that's the\n * verifier pipeline) and does NOT apply trust policy (that's the gate / `/v1/assess`).\n */\nexport type AitValidationResult =\n | { ok: true; payload: AitPayload }\n | { ok: false; reason: AitValidationFailure };\n\ntype AitValidationFailure =\n | 'not_an_object'\n | 'missing_aip_version'\n | 'missing_iss'\n | 'missing_sub'\n | 'missing_iat'\n | 'missing_exp'\n | 'missing_cnf'\n | 'missing_agent_provider'\n | 'human_confirmed_without_amr';\n\nconst isObject = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.length > 0;\n\n/**\n * Detect whether a decoded JWT payload is an AIT: per spec, an AIT is discriminated by the\n * presence of `cnf` + `agent` claims (not the `typ` header).\n */\nexport const isAitShape = (payload: unknown): boolean =>\n isObject(payload) && isObject(payload.cnf) && isObject(payload.agent);\n\n/** Validate the structural contract of a decoded AIT payload. */\nexport const validateAitPayload = (payload: unknown): AitValidationResult => {\n if (!isObject(payload)) { return { ok: false, reason: 'not_an_object' }; }\n if (!isNonEmptyString(payload.aip_version)) { return { ok: false, reason: 'missing_aip_version' }; }\n if (!isNonEmptyString(payload.iss)) { return { ok: false, reason: 'missing_iss' }; }\n if (!isNonEmptyString(payload.sub)) { return { ok: false, reason: 'missing_sub' }; }\n if (typeof payload.iat !== 'number') { return { ok: false, reason: 'missing_iat' }; }\n if (typeof payload.exp !== 'number') { return { ok: false, reason: 'missing_exp' }; }\n if (!isObject(payload.cnf) || !isObject((payload.cnf as Record<string, unknown>).jwk)) {\n return { ok: false, reason: 'missing_cnf' };\n }\n if (!isObject(payload.agent) || !isNonEmptyString((payload.agent as Record<string, unknown>).provider)) {\n return { ok: false, reason: 'missing_agent_provider' };\n }\n\n // Normative conditional: human_confirmed requires auth.amr with at least one value.\n if (payload.trust_level === 'human_confirmed') {\n const auth = payload.auth;\n const amr = isObject(auth) ? auth.amr : undefined;\n if (!Array.isArray(amr) || amr.length === 0) {\n return { ok: false, reason: 'human_confirmed_without_amr' };\n }\n }\n\n return { ok: true, payload: payload as AitPayload };\n};\n","/**\n * Build an AIP {@link VerifyRequestContext} from a standard WHATWG `Request`.\n *\n * Every framework adapter ultimately has (or can produce) a `Request`: Hono exposes\n * `c.req.raw`, Next.js / Web Fetch hand you one directly, and Express/Fastify can be shimmed.\n * This helper centralizes the header + URL extraction so adapters stay thin and the parsing\n * rules (authority derivation, multiple `Agent-Identity` headers) live in one place.\n */\n\nimport { AGENT_IDENTITY_HEADER, type VerifyRequestContext } from './verify';\n\n/**\n * Read all values of a possibly-repeated header. The Fetch `Headers` object folds repeated\n * headers into a single comma-joined value; for `Agent-Identity` we must split them back out\n * because each AIT is an independent JWT. JWTs are base64url dot-separated and never contain a\n * bare comma, so splitting on `,` is safe.\n */\nconst readAgentIdentityHeaders = (headers: Headers): string[] => {\n const raw = headers.get(AGENT_IDENTITY_HEADER);\n if (!raw) { return []; }\n return raw\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n};\n\n/**\n * Derive `@authority` for RFC 9421. Prefer the `Host` header (what the client addressed);\n * fall back to the URL host. Returned as-is; {@link normalizeAuthority} canonicalizes during\n * signature-base construction.\n */\nconst deriveAuthority = (req: Request, url: URL): string => req.headers.get('host') ?? url.host;\n\n/** Build the framework-agnostic verify context from a standard `Request`. A configured\n * `authority` pin (e.g. `AipGateOptions.authority`) wins over the inbound `Host` header. */\nexport const buildVerifyContextFromRequest = (req: Request, authority?: string): VerifyRequestContext => {\n const url = new URL(req.url);\n return {\n method: req.method,\n authority: authority ?? deriveAuthority(req, url),\n path: url.pathname,\n agentIdentityHeaders: readAgentIdentityHeaders(req.headers),\n signatureInput: req.headers.get('signature-input'),\n signature: req.headers.get('signature'),\n };\n};\n\n/** True when the request carries an AIP credential (at least one `Agent-Identity` header). */\nexport const hasAgentIdentityHeader = (req: Request): boolean =>\n readAgentIdentityHeaders(req.headers).length > 0;\n\n/** Read a header from a Node-style header map (value may be string | string[] | undefined). */\nconst readNodeHeader = (\n headers: Record<string, string | string[] | undefined>,\n name: string,\n): string | undefined => {\n const v = headers[name] ?? headers[name.toLowerCase()];\n if (v === undefined) { return undefined; }\n return Array.isArray(v) ? v.join(', ') : v;\n};\n\n/** True when a Node-style header map carries an `Agent-Identity` header. */\nexport const hasAgentIdentityHeaderNode = (\n headers: Record<string, string | string[] | undefined>,\n): boolean => {\n const raw = readNodeHeader(headers, 'agent-identity');\n return raw !== undefined && raw.split(',').some((s) => s.trim().length > 0);\n};\n\n/**\n * Build the verify context from Express/Fastify-style parts (Node header map + method + URL).\n * These frameworks don't expose a Fetch `Request`, so adapters pass raw pieces here.\n */\nexport const buildVerifyContextFromParts = (parts: {\n method: string;\n /** Full request URL, or just the path. Used to derive `@path`. */\n url: string;\n /** Node header map. */\n headers: Record<string, string | string[] | undefined>;\n /** Authority override; falls back to the `host` header. */\n authority?: string;\n}): VerifyRequestContext => {\n const agentIdentityRaw = readNodeHeader(parts.headers, 'agent-identity');\n const agentIdentityHeaders = agentIdentityRaw\n ? agentIdentityRaw.split(',').map((s) => s.trim()).filter((s) => s.length > 0)\n : [];\n const host = parts.authority ?? readNodeHeader(parts.headers, 'host') ?? '';\n // url may be an absolute URL or an origin-form target (\"/checkout?...\", possibly \"//x\"). Build\n // the URL by APPENDING the target to the origin (not resolving it as a reference) so a leading\n // \"//\" is treated as PATH — `new URL('//x', base)` would mis-read \"//x\" as a protocol-relative\n // authority and drop it, diverging from the signer's `URL.pathname` and failing PoP.\n // Always assigned in both branches below, so no initializer (avoids a dead assignment).\n let path: string;\n try {\n if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(parts.url)) {\n path = new URL(parts.url).pathname;\n } else {\n const target = parts.url.startsWith('/') ? parts.url : `/${parts.url}`;\n path = new URL(`http://${host || 'localhost'}${target}`).pathname;\n }\n } catch {\n const q = parts.url.indexOf('?');\n path = q === -1 ? parts.url : parts.url.slice(0, q);\n }\n return {\n method: parts.method,\n authority: host,\n path,\n agentIdentityHeaders,\n signatureInput: readNodeHeader(parts.headers, 'signature-input') ?? null,\n signature: readNodeHeader(parts.headers, 'signature') ?? null,\n };\n};\n","/**\n * Framework-agnostic AIP gate orchestration.\n *\n * `verifyAitRequest` is the one call a framework adapter makes: hand it a standard `Request`\n * plus a {@link JwksCache}, and it returns the verified AIT claims or a typed failure. The\n * helpers here also map that failure onto the AIP wire contract — HTTP status + error code +\n * an RFC 9457 problem-details body — so every adapter renders denials identically.\n *\n * This layer does identity *verification* only (is this a real, key-bound AIT from a trusted\n * IdP?). Policy enrichment — sanctions, jurisdiction, cross-merchant graph — happens when the\n * merchant additionally feeds the verified claims to `/v1/assess`; that's the gate's choice,\n * not something this module forces.\n */\n\nimport { buildVerifyContextFromParts, buildVerifyContextFromRequest } from './request';\nimport { verifyAit, type VerifiedAit, type VerifyAitFailure, type VerifyRequestContext } from './verify';\nimport type { JwksCache } from './jwks';\nimport type { TrustLevel } from './types';\n\nexport interface AipGateOptions {\n jwks: JwksCache;\n now?: number;\n maxSkewSeconds?: number;\n /** Expected `@authority` (public hostname) the RFC 9421 signature must cover. When set, the\n * verifier binds the signature to this value instead of trusting the inbound `Host` header —\n * pin it to your real public host (e.g. `'wine.example.com'`) when behind a proxy or\n * multi-vhost listener that does not normalize `Host`, to prevent a captured AIT+signature\n * from being replayed to a different virtual host on the same origin. Same semantics as\n * Checkout's `AipGateConfig.authority`. */\n authority?: string;\n /** Minimum `trust_level` (autonomous < human_present < human_confirmed) the AIT must assert —\n * the spec's human-presence gate. Insufficient → 403 weak_auth with `required_trust_level`.\n * Enforced by {@link evaluateAipRequest} / {@link evaluateAipParts}. Unset = any trust level. */\n requireTrustLevel?: TrustLevel;\n /** Acceptable `auth.amr` methods (RFC 8176); the AIT must carry ≥1. Insufficient → 403 weak_auth\n * with `required_amr`. Unset = not enforced. */\n requireAmr?: string[];\n /** Identity claims the endpoint needs — surfaced as `required_claims` on insufficient_claims\n * denials so the agent can self-correct. Advisory only (enforce by feeding the verified claims\n * to your own policy / `/v1/assess`; this gate does identity + trust_level/amr). */\n requiredClaims?: string[];\n /** Trusted issuer URLs surfaced as `trusted_issuers` on untrusted_issuer denials. */\n trustedIssuers?: string[];\n}\n\nexport type AipGateResult =\n | { ok: true; ait: VerifiedAit }\n | { ok: false; failure: VerifyAitFailure };\n\n/** Verify the AIP credential from a pre-built context. Shared by all adapter entry points. */\nconst verifyFromContext = async (ctx: VerifyRequestContext, opts: AipGateOptions): Promise<AipGateResult> => {\n const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });\n return result.ok ? { ok: true, ait: result.ait } : { ok: false, failure: result.reason };\n};\n\n/** Apply the gate's configured `authority` pin to a parts object: an explicit per-call\n * `parts.authority` (e.g. Checkout's) wins, then the gate option, then the inbound `Host`. */\nconst partsWithAuthority = (\n parts: { method: string; url: string; headers: Record<string, string | string[] | undefined>; authority?: string },\n opts: AipGateOptions,\n): typeof parts => {\n const authority = parts.authority ?? opts.authority;\n return authority !== undefined ? { ...parts, authority } : parts;\n};\n\n/** Verify the AIP credential on a standard Fetch `Request` (Hono / Web / Next.js). */\nexport const verifyAitRequest = (req: Request, opts: AipGateOptions): Promise<AipGateResult> =>\n verifyFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);\n\n/** Verify the AIP credential from Express/Fastify-style parts (Node header map + method + url). */\nexport const verifyAitParts = (\n parts: { method: string; url: string; headers: Record<string, string | string[] | undefined>; authority?: string },\n opts: AipGateOptions,\n): Promise<AipGateResult> => verifyFromContext(buildVerifyContextFromParts(partsWithAuthority(parts, opts)), opts);\n\n/** Map an internal verify failure to the AIP wire error code (per spec error taxonomy). */\nexport const aipErrorCode = (failure: VerifyAitFailure): string => {\n switch (failure) {\n case 'no_token':\n case 'pop_signature_missing':\n return 'agent_identity_required';\n case 'untrusted_issuer':\n return 'untrusted_issuer';\n case 'expired_token':\n return 'expired_token';\n case 'invalid_claims':\n return 'insufficient_claims';\n case 'key_unavailable':\n // The IdP's JWKS could not be fetched/resolved — our infra couldn't reach a trusted\n // issuer, not a client-side auth failure. Distinct code so agents back off + retry\n // rather than uselessly re-signing.\n return 'idp_unavailable';\n case 'malformed_token':\n case 'idp_signature_invalid':\n case 'pop_signature_invalid':\n return 'invalid_signature';\n default:\n return 'invalid_signature';\n }\n};\n\n/** HTTP status for an AIP verify failure: 503 when our infra couldn't reach the IdP (retryable),\n * 403 for trust/claims, 401 for auth-presence/signature. */\nexport const aipErrorStatus = (failure: VerifyAitFailure): 401 | 403 | 503 => {\n switch (failure) {\n case 'key_unavailable':\n return 503;\n case 'untrusted_issuer':\n case 'invalid_claims':\n return 403;\n default:\n return 401;\n }\n};\n\n/** Human-readable detail for the failure, for the problem-details body. */\nconst aipErrorDetail = (failure: VerifyAitFailure): string => {\n switch (failure) {\n case 'no_token':\n return 'No Agent-Identity token was presented.';\n case 'pop_signature_missing':\n return 'The request is missing the RFC 9421 HTTP Message Signature that proves possession of the token-bound key.';\n case 'untrusted_issuer':\n return \"The token's issuer is not in this service's trusted-issuer list.\";\n case 'expired_token':\n return 'The Agent Identity Token has expired.';\n case 'invalid_claims':\n return 'The token is missing required claims for this endpoint.';\n case 'malformed_token':\n return 'The Agent-Identity header could not be parsed as an Agent Identity Token.';\n case 'idp_signature_invalid':\n return \"The identity provider's signature on the token failed verification.\";\n case 'pop_signature_invalid':\n return 'The request signature did not match the key bound to the token.';\n case 'key_unavailable':\n return \"The identity provider's signing key could not be resolved.\";\n default:\n return 'Token verification failed.';\n }\n};\n\n/** RFC 9457 problem-details body for an AIP denial. Known fields are typed; `required_*` /\n * `trusted_issuers` escalation extensions ride in the index signature. */\nexport type AipErrorBody = { type: string; title: string; status: number; detail: string; [k: string]: unknown };\n\n/** Merchant requirements attached to an AIP escalation body so the agent can self-correct. */\nexport interface AipErrorRequirements {\n trustedIssuers?: string[];\n requiredClaims?: string[];\n requiredTrustLevel?: TrustLevel;\n requiredAmr?: string[];\n}\n\n/**\n * Build an RFC 9457 problem-details body for an AIP verify failure. Adapters serialize this as\n * `application/problem+json` with {@link aipErrorStatus}. Optionally carries the merchant's\n * requirements — `trusted_issuers` on untrusted_issuer; `required_claims` / `required_trust_level` /\n * `required_amr` on insufficient_claims — so the agent learns what would satisfy the gate.\n */\nexport const buildAipErrorBody = (failure: VerifyAitFailure, requirements?: AipErrorRequirements): AipErrorBody => {\n const code = aipErrorCode(failure);\n const body: AipErrorBody = {\n type: `urn:aip:error:${code}`,\n title: code.replace(/_/g, ' '),\n status: aipErrorStatus(failure),\n detail: aipErrorDetail(failure),\n };\n if (requirements) {\n if (code === 'untrusted_issuer' && requirements.trustedIssuers?.length) {\n body.trusted_issuers = requirements.trustedIssuers;\n }\n if (code === 'insufficient_claims') {\n if (requirements.requiredClaims?.length) body.required_claims = requirements.requiredClaims;\n if (requirements.requiredTrustLevel !== undefined) body.required_trust_level = requirements.requiredTrustLevel;\n if (requirements.requiredAmr?.length) body.required_amr = requirements.requiredAmr;\n }\n }\n return body;\n};\n\n/**\n * Map an AgentScore *policy-deny* code (a `/v1/assess` decision, NOT a verify failure) to its\n * spec AIP error code + HTTP status. This is the policy-side counterpart to {@link aipErrorCode}\n * (which maps the verify-FAILURE taxonomy). On the AIT-input path a denied `/v1/assess` decision\n * surfaces as one of these AgentScore codes; the spec's fixed error set expresses each as:\n * - `token_expired` → `expired_token` (401)\n * - `invalid_credential` → `invalid_signature` (401)\n * - `api_error` → `idp_unavailable` (503, transient — the claims couldn't be evaluated)\n * - everything else (compliance: `wallet_not_trusted` + `sanctions_flagged` / `age_insufficient`\n * / `jurisdiction_restricted` / `kyc_*`) → `insufficient_claims` (403): the AIT did not attest\n * (or attested a failing value for) the required compliance claim.\n */\nconst aipPolicyDenyCode = (code: string): { code: string; status: 401 | 403 | 503 } => {\n switch (code) {\n case 'token_expired':\n return { code: 'expired_token', status: 401 };\n case 'invalid_credential':\n return { code: 'invalid_signature', status: 401 };\n case 'api_error':\n return { code: 'idp_unavailable', status: 503 };\n default:\n return { code: 'insufficient_claims', status: 403 };\n }\n};\n\n/**\n * Wrap an AgentScore AIT-path denial body in the RFC 9457 + AIP-spec superset.\n *\n * Reuses {@link buildAipErrorBody}'s SHAPE convention (`type`/`title`/`status`/`detail` +\n * escalation extensions) but for the *policy-deny* case — a verified AIT that `/v1/assess` then\n * denied — which carries an AgentScore compliance/credential code, not a verify-failure reason.\n *\n * The result is a SUPERSET: the canonical `{ error, agent_instructions, ... }` body is spread in\n * verbatim (so existing consumers keep parsing `error.code`), with the RFC 9457 envelope layered\n * on top. `detail` names the precise AgentScore reason(s); `error.code` stays the AgentScore code.\n * Escalation fields (`required_claims` / `required_trust_level` / `required_amr` on\n * insufficient_claims, `trusted_issuers` on untrusted_issuer) ride along when known.\n */\nexport const buildAipPolicyDenyBody = (\n code: string,\n reasons: string[] | undefined,\n body: Record<string, unknown>,\n requirements?: AipErrorRequirements,\n): Record<string, unknown> => {\n const spec = aipPolicyDenyCode(code);\n const reasonList = reasons ?? [];\n const detail =\n spec.code === 'insufficient_claims'\n ? reasonList.length > 0\n ? `The Agent Identity Token did not attest a passing value for the required compliance claim(s). AgentScore decision: ${code} (${reasonList.join(', ')}).`\n : `The Agent Identity Token did not satisfy the merchant's compliance policy. AgentScore decision: ${code}.`\n : `AgentScore decision: ${code}.`;\n const superset: Record<string, unknown> = {\n type: `urn:aip:error:${spec.code}`,\n title: spec.code.replace(/_/g, ' '),\n status: spec.status,\n detail,\n };\n // Escalation extensions, scoped exactly as the spec mandates: `required_claims` /\n // `required_trust_level` / `required_amr` on insufficient_claims. `trusted_issuers` belongs to\n // untrusted_issuer — a VERIFY failure that never reaches the policy-deny path — so it is not\n // emitted here (the edge-deny `buildAipErrorBody` owns that one).\n if (requirements && spec.code === 'insufficient_claims') {\n if (requirements.requiredClaims?.length) superset.required_claims = requirements.requiredClaims;\n if (requirements.requiredTrustLevel !== undefined) superset.required_trust_level = requirements.requiredTrustLevel;\n if (requirements.requiredAmr?.length) superset.required_amr = requirements.requiredAmr;\n }\n // Spread the canonical body LAST so `error` / `agent_instructions` / `reasons` win verbatim —\n // the RFC 9457 fields are additive and never clobber the rich AgentScore scheme. The envelope\n // fields themselves (`type` / `title` / `status` / `detail`) are RESERVED the other way: the\n // canonical body never carries them legitimately, but a merchant `onBeforeSession` hook's\n // `extra` rides through `denialReasonToBody` unfiltered — strip them so a smuggled `status`\n // can't rewrite the problem+json envelope (or the HTTP status Checkout derives from it).\n const { type: _type, title: _title, status: _status, detail: _detail, ...rest } = body;\n return { ...superset, ...rest };\n};\n\n/** Trust-level ordering: a token satisfies a requirement when its level ≥ the required level. */\nconst TRUST_RANK: Record<string, number> = { autonomous: 0, human_present: 1, human_confirmed: 2 };\n\n/**\n * Check a verified AIT against the gate's `trust_level` / `auth.amr` requirements (the spec's\n * human-presence gate). Returns a detail string when insufficient (→ weak_auth), else null.\n */\nexport const checkTrustRequirements = (\n payload: { trust_level?: string | undefined; auth?: { amr?: string[] | undefined } | undefined },\n requiredTrustLevel?: TrustLevel,\n requiredAmr?: string[],\n): string | null => {\n if (requiredTrustLevel !== undefined) {\n const have = TRUST_RANK[payload.trust_level ?? 'autonomous'] ?? 0;\n const need = TRUST_RANK[requiredTrustLevel] ?? 0;\n if (have < need) {\n 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).`;\n }\n }\n if (requiredAmr !== undefined && requiredAmr.length > 0) {\n const amr = Array.isArray(payload.auth?.amr) ? payload.auth!.amr! : [];\n if (!amr.some((m) => requiredAmr.includes(m))) {\n return `This endpoint requires an authentication method in [${requiredAmr.join(', ')}]; the token carries [${amr.join(', ') || 'none'}].`;\n }\n }\n return null;\n};\n\n/** Build an RFC 9457 `weak_auth` body for a token that failed the trust_level / auth.amr gate. */\nexport const buildAipWeakAuthBody = (opts: {\n detail: string;\n requiredTrustLevel?: TrustLevel;\n requiredAmr?: string[];\n trustedIssuers?: string[];\n}): AipErrorBody => ({\n type: 'urn:aip:error:weak_auth',\n title: 'weak auth',\n status: 403,\n detail: opts.detail,\n ...(opts.requiredTrustLevel !== undefined && { required_trust_level: opts.requiredTrustLevel }),\n ...(opts.requiredAmr !== undefined && opts.requiredAmr.length > 0 && { required_amr: opts.requiredAmr }),\n ...(opts.trustedIssuers !== undefined && opts.trustedIssuers.length > 0 && { trusted_issuers: opts.trustedIssuers }),\n});\n\n/** A verified AIT, or a ready-to-render RFC 9457 denial body (HTTP status on `body.status`). */\nexport type AipGateEvaluation =\n | { ok: true; ait: VerifiedAit }\n | { ok: false; body: AipErrorBody };\n\n/** Collect the merchant's requirements from gate options, for attaching to denial bodies. */\nconst requirementsFromOptions = (opts: AipGateOptions): AipErrorRequirements => ({\n ...(opts.trustedIssuers !== undefined && { trustedIssuers: opts.trustedIssuers }),\n ...(opts.requiredClaims !== undefined && { requiredClaims: opts.requiredClaims }),\n ...(opts.requireTrustLevel !== undefined && { requiredTrustLevel: opts.requireTrustLevel }),\n ...(opts.requireAmr !== undefined && { requiredAmr: opts.requireAmr }),\n});\n\n/**\n * Verify the AIP credential AND enforce the gate's trust_level / auth.amr requirement in one call —\n * the standalone-adapter counterpart to {@link verifyAitRequest}. Returns the verified AIT, or an\n * RFC 9457 denial body (a verify failure → its wire code; trust insufficient → weak_auth) carrying\n * the merchant's `required_*` / `trusted_issuers` so the agent can self-correct.\n */\nconst evaluateFromContext = async (ctx: VerifyRequestContext, opts: AipGateOptions): Promise<AipGateEvaluation> => {\n const result = await verifyAit(ctx, { jwks: opts.jwks, now: opts.now, maxSkewSeconds: opts.maxSkewSeconds });\n if (!result.ok) {\n return { ok: false, body: buildAipErrorBody(result.reason, requirementsFromOptions(opts)) };\n }\n const weak = checkTrustRequirements(result.ait.payload, opts.requireTrustLevel, opts.requireAmr);\n if (weak !== null) {\n return {\n ok: false,\n body: buildAipWeakAuthBody({\n detail: weak,\n ...(opts.requireTrustLevel !== undefined && { requiredTrustLevel: opts.requireTrustLevel }),\n ...(opts.requireAmr !== undefined && { requiredAmr: opts.requireAmr }),\n ...(opts.trustedIssuers !== undefined && { trustedIssuers: opts.trustedIssuers }),\n }),\n };\n }\n return { ok: true, ait: result.ait };\n};\n\n/** Verify + trust-enforce on a standard Fetch `Request` (Hono / Web / Next.js adapters). */\nexport const evaluateAipRequest = (req: Request, opts: AipGateOptions): Promise<AipGateEvaluation> =>\n evaluateFromContext(buildVerifyContextFromRequest(req, opts.authority), opts);\n\n/** Verify + trust-enforce from Express/Fastify-style parts (Node header map + method + url). */\nexport const evaluateAipParts = (\n parts: { method: string; url: string; headers: Record<string, string | string[] | undefined>; authority?: string },\n opts: AipGateOptions,\n): Promise<AipGateEvaluation> => evaluateFromContext(buildVerifyContextFromParts(partsWithAuthority(parts, opts)), opts);\n","import { createHash } from 'node:crypto';\nimport {\n AgentScore,\n type AipSignatureMaterial,\n InvalidCredentialError,\n PaymentRequiredError,\n QuotaExceededError,\n TimeoutError as SdkTimeoutError,\n TokenExpiredError,\n} from '@agent-score/sdk';\nimport { isFixableDenial } from './_denial';\nimport { QUOTA_EXCEEDED_INSTRUCTIONS } from './_response';\nimport { normalizeAddress } from './address';\nimport { TTLCache } from './cache';\nimport type { PaymentSigner } from './signer';\n\n// Character-based trim avoids a CodeQL polynomial-redos false positive on\n// `/\\/+$/` patterns that report library-input strings.\nfunction stripTrailingSlashes(s: string): string {\n let end = s.length;\n while (end > 0 && s.charCodeAt(end - 1) === 47 /* '/' */) end--;\n return end === s.length ? s : s.slice(0, end);\n}\n\ndeclare const __VERSION__: string;\n\n// ---------------------------------------------------------------------------\n// Public types (framework-agnostic)\n// ---------------------------------------------------------------------------\n\nexport interface AgentIdentity {\n address?: string;\n operatorToken?: string;\n /** Raw AIP Agent Identity Token (a JWT). When set, the gate has verified the token's RFC 9421\n * proof-of-possession at the edge as a fail-fast filter; `evaluate` forwards it to `/v1/assess`\n * as `aip_token` (with {@link aipSignature}) for AUTHORITATIVE server-side re-verification of the\n * IdP signature + proof-of-possession + policy. */\n aipToken?: string;\n /** RFC 9421 signature material accompanying {@link aipToken}, forwarded to `/v1/assess` as\n * `aip_signature` so the API re-verifies proof-of-possession itself (the edge is not trusted as\n * the authority). Always set together with `aipToken`. */\n aipSignature?: AipSignatureMaterial;\n}\n\n/**\n * Session metadata returned from `POST /v1/sessions`. Surfaced to the `onBeforeSession`\n * hook so merchants can correlate an AgentScore session with their own resume token\n * (e.g. a pending-order id).\n */\nexport interface SessionMetadata {\n session_id: string;\n verify_url: string;\n poll_secret: string;\n poll_url: string;\n expires_at?: string;\n}\n\n/**\n * Configuration for auto-creating a verification session when no identity is present.\n *\n * The static `context` / `productName` options are sent on every session request. For\n * per-request context (e.g. the specific product the agent was trying to buy), pass\n * a `getSessionOptions` callback that returns dynamic values; its return is merged\n * over the static defaults.\n *\n * `onBeforeSession` is a side-effect hook that runs after the session is minted but\n * before the 403 is built. Use it to pre-create a reservation/draft/pending-order\n * row in your DB so agents can resume via a merchant-specific id. Return value is\n * merged into `DenialReason.extra`, so it surfaces in both the default 403 body and\n * in a custom `onDenied` handler.\n */\nexport interface CreateSessionOnMissing<TCtx = unknown> {\n apiKey: string;\n baseUrl?: string;\n context?: string;\n productName?: string;\n /** Per-request override of `context` / `productName`. Invoked with the framework context. */\n getSessionOptions?: (ctx: TCtx) => Promise<{ context?: string; productName?: string }>\n | { context?: string; productName?: string };\n /** Side-effect hook that runs after the session is minted. Return value is merged\n * into `DenialReason.extra` so custom `onDenied` handlers can include merchant-specific\n * fields (e.g. `order_id`) in the 403 response. Hook errors are logged and swallowed —\n * a failing side effect should not block the 403 from reaching the agent. */\n onBeforeSession?: (ctx: TCtx, session: SessionMetadata) => Promise<Record<string, unknown>>\n | Record<string, unknown>;\n}\n\nexport interface AgentScoreCoreOptions {\n /** AgentScore API key. Required. */\n apiKey: string;\n /** Require KYC verification. */\n requireKyc?: boolean;\n /** Require operator to be clear of sanctions. */\n requireSanctionsClear?: boolean;\n /** Minimum operator age bracket (18 or 21). */\n minAge?: number;\n /** List of blocked jurisdictions (blocklist). */\n blockedJurisdictions?: string[];\n /** List of allowed jurisdictions (allowlist — only these pass). */\n allowedJurisdictions?: string[];\n /** If true, allow the request through when the API is unreachable. Defaults to false. */\n failOpen?: boolean;\n /** How long to cache results, in seconds. Defaults to 300. */\n cacheSeconds?: number;\n /** AgentScore API base URL. Defaults to \"https://api.agentscore.com\". */\n baseUrl?: string;\n /** Optional chain to filter scoring to. */\n chain?: string;\n /** Prepended to the default User-Agent as `\"{userAgent} (@agent-score/commerce@{version})\"`. Use to attribute API calls to your app. */\n userAgent?: string;\n /** When set and no identity is found, create a verification session instead of denying immediately. */\n createSessionOnMissing?: CreateSessionOnMissing;\n /** Issuers whose AIP Agent Identity Tokens this gate accepts. When set, the missing-identity\n * recovery instructions and the `agent_memory` hint advertise the AIT path so agents holding\n * one can present it. Set by Checkout from `gate.aip.trustedIssuers`; the actual AIT\n * verification happens at the edge (Checkout) before `evaluate`. */\n aipTrustedIssuers?: string[];\n}\n\nexport type DenialCode =\n | 'wallet_not_trusted'\n | 'missing_identity'\n | 'api_error'\n | 'payment_required'\n | 'identity_verification_required'\n // Wallet-signer binding: claimed X-Wallet-Address must resolve to the same operator as\n // the payment signer; wallet-auth is rejected on rails with no wallet signer.\n | 'wallet_signer_mismatch'\n | 'wallet_auth_requires_wallet_signing'\n // Granular credential-state denials passed through from /v1/assess.\n // - `token_expired`: revoked + TTL-expired (the API unifies these). The 401 body carries\n // an auto-minted session, forwarded into DenialReason for one-shot recovery.\n // - `invalid_credential`: the token doesn't exist at all (typo, never minted, fabricated).\n // No auto-session is minted by the API for this case — agents should switch to a\n // different stored token or drop the header to bootstrap a fresh session.\n | 'token_expired'\n | 'invalid_credential';\n\n/**\n * Cross-merchant pattern hint emitted on bootstrap denials and session-create responses.\n * LLM-hosted agents should persist this to long-term memory so future AgentScore encounters skip\n * the cold-start session flow. Contents are the pattern, not secrets.\n */\nexport interface AgentMemoryHint {\n save_for_future_agentscore_gates: true;\n pattern_summary: string;\n quickstart: string;\n identity_check_endpoint: string;\n list_wallets_endpoint?: string;\n identity_paths: { wallet: string; operator_token: string; agent_identity?: string };\n /** Issuers whose AIP Agent Identity Tokens this merchant accepts. Present only when the\n * merchant opted into AIP; an agent holding an AIT from one of these can present it via an\n * `Agent-Identity` header + RFC 9421 signature instead of bootstrapping a fresh credential. */\n aip_trusted_issuers?: string[];\n bootstrap: string;\n do_not_persist_in_memory: string[];\n persist_in_credential_store: string[];\n}\n\nexport interface DenialReason {\n code: DenialCode;\n /** Human-readable explanation. When omitted, `denialReasonToBody` substitutes a per-code default. */\n message?: string;\n decision?: string;\n reasons?: string[];\n verify_url?: string;\n session_id?: string;\n poll_secret?: string;\n poll_url?: string;\n agent_instructions?: string;\n /** Cross-merchant memory hint. Emitted on bootstrap denials only by default. */\n agent_memory?: AgentMemoryHint;\n /** Full assess response when the denial came from `/v1/assess`. Lets consumers access fields\n * not promoted to first-class DenialReason properties (e.g., `policy_result`). Undefined for\n * denials that did not originate from an assess call (missing_identity, api_error,\n * payment_required, identity_verification_required). */\n data?: AssessResult;\n /** Extra fields returned from the `createSessionOnMissing.onBeforeSession` hook. Merged\n * into the default 403 body; custom `onDenied` handlers can spread these into their own\n * response shape (e.g. to include a merchant-minted `order_id`). */\n extra?: Record<string, unknown>;\n // ---------------------------------------------------------------------------\n // Wallet-signer-match fields — populated for wallet_signer_mismatch only.\n // ---------------------------------------------------------------------------\n /** Operator id resolved from `X-Wallet-Address`. */\n claimed_operator?: string;\n /** Operator id the actual payment signer resolves to. `null` when the signer wallet isn't\n * linked to any operator (treat as a different identity). */\n actual_signer_operator?: string | null;\n /** The wallet the agent claimed via header. Echoed back for self-correction. */\n expected_signer?: string;\n /** The wallet that actually signed the payment. */\n actual_signer?: string;\n /** Wallets the claimed operator could sign with (if enumerable). Present when non-empty. */\n linked_wallets?: string[];\n}\n\n/** Operator verification details from the assess response. */\nexport interface OperatorVerification {\n level: string;\n operator_type: string | null;\n verified_at: string | null;\n}\n\n/** Account-level KYC facts that apply to every operator under the same account.\n * Populated when the API returns account_verification (post-KYC operator). */\nexport interface AccountVerification {\n kyc_level?: string;\n sanctions_clear?: boolean;\n age_bracket?: string;\n jurisdiction?: string;\n verified_at?: string | null;\n}\n\n/** A single policy check from the assess response. */\nexport interface PolicyCheck {\n rule: string;\n passed: boolean;\n required?: unknown;\n actual?: unknown;\n}\n\n/** Policy evaluation result from the assess response. */\nexport interface PolicyResult {\n all_passed: boolean;\n checks: PolicyCheck[];\n}\n\nexport interface AssessResult {\n decision: string | null;\n decision_reasons: string[];\n identity_method?: string;\n operator_verification?: OperatorVerification;\n account_verification?: AccountVerification;\n resolved_operator?: string | null;\n /** Wallets linked to the same operator as the resolved identity. Capped at 100 entries\n * by the API. Useful for advertising in 402 challenges so wallet-auth agents know which\n * alt-signers will satisfy `wallet_signer_mismatch`. */\n linked_wallets?: string[];\n verify_url?: string;\n policy_result?: PolicyResult | null;\n /** IdP provenance, present only when `identity_method === 'aip_token'` — which issuer attested\n * the identity and the trust level it asserted. Mirrors the SDK's `AssessResponse.aip`. */\n aip?: {\n issuer: string;\n subject: string;\n trust_level?: 'autonomous' | 'human_present' | 'human_confirmed';\n agent_provider?: string;\n /** True when /v1/assess re-verified the RFC 9421 proof-of-possession (always true on success). */\n pop_verified?: boolean;\n };\n}\n\n/**\n * Reason a failOpen allow short-circuited an evaluate call due to AgentScore-side\n * infrastructure issues. Surfaced on `EvaluateOutcome` so merchants can log/alert when\n * their gate is running in degraded mode (compliance not actually enforced this request).\n *\n * - `quota_exceeded` — AgentScore returned 429\n * - `api_error` — AgentScore returned 5xx or non-2xx that isn't 429\n * - `network_timeout` — request to /v1/assess timed out or failed at the network layer\n */\nexport type FailOpenInfraReason = 'quota_exceeded' | 'api_error' | 'network_timeout';\n\n/** Per-account assess quota observability, captured from `X-Quota-*` response headers\n * on the success path. Mirrors the SDK's `QuotaInfo` shape — re-exported from gate state\n * so merchants can monitor approach-to-cap proactively (warn at 80%, alert at 95%). */\nexport interface GateQuotaInfo {\n limit: number | null;\n used: number | null;\n /** ISO-8601 timestamp, or the literal string `\"never\"` for unlimited tiers. */\n reset: string | null;\n}\n\n/**\n * Outcome from `AgentScoreCore.evaluate()`. Adapters map this to framework-specific responses.\n *\n * - `{ kind: 'allow', data }` — the request passed the policy. `data` is present on a normal\n * allow; `undefined` when fail-open short-circuited (identity missing, API unreachable,\n * timeout, or 402 paid-tier required).\n * - When `failOpen: true` and the allow was the result of an AgentScore-side infrastructure\n * failure (429/5xx/timeout), the result also carries `degraded: true` + `infraReason` so\n * merchants can alert/log without parsing console output.\n * - `quota` propagates the SDK's per-request quota observability when the API emits the\n * `X-Quota-*` headers. Optional; absent on Enterprise / unlimited tiers.\n * - `signerVerdict` carries the per-request wallet-signer verdicts (signer_match + signer_sanctions)\n * composed by this evaluate's assess call. It rides on the RETURN VALUE (not a shared slot on the\n * core) so concurrent same-wallet/different-signer requests can't read each other's verdict —\n * the adapter stashes it on its per-request state for `getSignerVerdict(ctx)` to read back.\n * Present only on wallet-only identity when the response carried either signer block; `undefined`\n * otherwise (operator-token / AIT paths, discovery legs with no signer).\n * - `{ kind: 'deny', reason }` — the request was denied. Adapters should render a 403 with the\n * reason, or invoke the caller's custom denial handler.\n */\nexport type EvaluateOutcome =\n | { kind: 'allow'; data?: AssessResult; degraded?: boolean; infraReason?: FailOpenInfraReason; quota?: GateQuotaInfo; signerVerdict?: SignerVerdict }\n | { kind: 'deny'; reason: DenialReason; signerVerdict?: SignerVerdict };\n\ninterface CaptureWalletOptions {\n /** Operator credential (`opc_...`) that the agent authenticated with. */\n operatorToken: string;\n /** Signer wallet recovered from the payment payload. */\n walletAddress: string;\n /** Key-derivation family — `\"evm\"` for any EVM chain, `\"solana\"` for Solana. */\n network: 'evm' | 'solana';\n /** Optional stable key for the logical payment (e.g., payment intent id, tx hash). When the\n * same key is seen again for the same (credential, wallet, network), the server no-ops —\n * prevents agent retries from inflating transaction_count. */\n idempotencyKey?: string;\n}\n\n/** Combined wallet-signer verdict surfaced by `getSignerVerdict(c)` — both verdicts come\n * through the gate's primary `/v1/assess` call (single round trip). `signer_match` describes\n * the wallet-binding (claimed wallet's operator ≡ signer wallet's operator); `signer_sanctions`\n * describes the OFAC SDN wallet-address check.\n *\n * `signer_match` is projected to the gate's camelCase `VerifyWalletSignerResult` shape so\n * existing `buildSignerMismatchBody(...)` helpers consume it unchanged. `signer_sanctions`\n * passes through in the API's wire shape (already short and stable). Returned `undefined`\n * from `getSignerVerdict` when the gate didn't run with a signer (operator-token-only\n * paths, discovery legs with no payment header). */\nexport interface SignerVerdict {\n signer_match: VerifyWalletSignerResult | null;\n signer_sanctions:\n | { status: 'clear' }\n | { sanctioned: true; ofac_label: string; sdn_uid: string; listed_at: string | null }\n | { status: 'unavailable' }\n | null;\n}\n\nexport type VerifyWalletSignerResult =\n | { kind: 'pass'; claimedOperator: string | null; signerOperator: string | null }\n | {\n kind: 'wallet_signer_mismatch';\n claimedOperator: string | null;\n actualSignerOperator: string | null;\n expectedSigner: string;\n actualSigner: string;\n linkedWallets: string[];\n /** JSON-encoded action copy (action + steps + user_message). Spread into the 403 body\n * verbatim so agents get a concrete recovery path inside the denial response itself. */\n agentInstructions: string;\n }\n | {\n kind: 'wallet_auth_requires_wallet_signing';\n claimedWallet: string;\n agentInstructions: string;\n };\n\nexport interface AgentScoreCore {\n /**\n * Evaluate the request's identity against the configured policy.\n * @param identity - extracted identity (wallet address and/or operator token)\n * @param ctx - optional framework-specific context (Hono c, Express req, etc.) passed\n * through to `createSessionOnMissing` hooks. Opaque to core.\n */\n evaluate(\n identity: AgentIdentity | undefined,\n ctx?: unknown,\n /** Pre-extracted payment signer from the inbound request (the adapter middleware\n * extracts it via `extractPaymentSigner`). When provided, the assess call carries\n * it and the response includes `signer_match` + `signer_sanctions` verdicts in one\n * round trip. */\n signer?: PaymentSigner | null,\n ): Promise<EvaluateOutcome>;\n /** Report a wallet seen paying under an operator credential. Fire-and-forget; silently\n * swallows non-fatal errors because capture is informational, not on the critical path. */\n captureWallet(options: CaptureWalletOptions): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Internal cache entry for the gate's per-`(identity, policy)` assess result memo.\n * Distinct from the public `AssessResult` interface (the typed `/v1/assess` response\n * shape returned to merchants); this carries the cached decision plus the per-signer\n * wallet-match sub-cache. */\ninterface CachedAssessResult {\n allow: boolean;\n decision?: string;\n reasons?: string[];\n raw?: unknown;\n}\n\n/**\n * Build the cross-merchant memory hint emitted on bootstrap denials. Base URLs are\n * derived from the gate's AgentScore API base so self-hosted / staging deployments get\n * correct pointers. Contents describe the AgentScore identity substrate in transferable\n * terms; merchant-specific context lives in other `agent_instructions` fields.\n */\n// Canonical production AgentScore API — used as the authoritative source for endpoint pointers\n// emitted to agent memory regardless of how a given merchant configured their gate's baseUrl.\nconst CANONICAL_AGENTSCORE_API = 'https://api.agentscore.com';\n\n// JSON-encoded action copy emitted on wallet-signer-match denials. Spread into 403 bodies\n// by merchants so agents get a concrete recovery path inside the denial response itself —\n// no discovery-doc round trip required.\nconst WALLET_SIGNER_MISMATCH_INSTRUCTIONS = JSON.stringify({\n action: 'resign_or_switch_to_operator_token',\n steps: [\n 'Preferred: re-submit the payment signed by expected_signer (or any entry in linked_wallets — same-operator wallets are fungible) and retry with the same X-Wallet-Address.',\n 'Alternative: drop X-Wallet-Address and retry with X-Operator-Token. Use a stored opc_... if you have one; otherwise retry this request with NO identity header — the merchant will mint a verification session in the 403 body (verify_url + poll_secret). Share verify_url with the user, poll, receive a fresh opc_...',\n ],\n user_message:\n 'The payment signer resolves to a different operator than X-Wallet-Address. Re-sign from expected_signer or any linked_wallets entry, or switch to X-Operator-Token.',\n});\n\nconst WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS = JSON.stringify({\n action: 'switch_to_operator_token',\n steps: [\n 'This payment rail (Stripe SPT, card) carries no wallet signature — X-Wallet-Address cannot be verified against the payment.',\n 'Drop X-Wallet-Address and retry with X-Operator-Token. If you do not have a stored opc_..., retry with no identity header to receive a verification session.',\n ],\n user_message:\n 'Wallet-address identity is only supported on wallet-signing rails (Tempo MPP, x402). On Stripe or card, use X-Operator-Token instead.',\n});\n\n// `invalid_credential` is permanent — the token doesn't exist (typo, never minted, fabricated).\n// Distinct from `token_expired` (which carries an auto-session for one-shot recovery): the\n// API doesn't auto-mint a session here because the client may simply have a different valid\n// token to try. Agents should switch tokens or drop the header to bootstrap a session.\nconst INVALID_CREDENTIAL_INSTRUCTIONS = JSON.stringify({\n action: 'switch_token_or_restart_session',\n steps: [\n 'The X-Operator-Token you sent does not match any credential. This is a permanent state — retrying with the same token will keep failing.',\n 'If you have other stored opc_... credentials, retry with one of them.',\n 'Otherwise drop X-Operator-Token and retry with no identity header — the merchant will mint a fresh verification session in the 403 body (verify_url + poll_secret) so the user can re-verify and you can poll for a new operator_token.',\n ],\n user_message:\n 'The operator_token is not recognized. Use a different stored token, or restart the verification session flow to mint a new one.',\n});\n\nexport function buildAgentMemoryHint(aipTrustedIssuers?: string[]): AgentMemoryHint {\n // Memory pointers always point at the canonical production API — merchants must not be\n // able to redirect the cross-merchant memory surface, since that would be a phishing\n // vector for the verify URL.\n const api = CANONICAL_AGENTSCORE_API;\n const acceptsAip = aipTrustedIssuers !== undefined && aipTrustedIssuers.length > 0;\n return {\n save_for_future_agentscore_gates: true,\n pattern_summary:\n 'AgentScore is a cross-merchant identity substrate for agent commerce. Any endpoint that ' +\n 'returns 403 missing_identity / identity_verification_required or 402 challenges referencing AgentScore uses ' +\n 'the same identity system. One KYC works across all AgentScore merchants — no re-verification ' +\n 'per site. Save this pattern (and the endpoints below) to persistent memory so future ' +\n 'AgentScore encounters skip the cold-start session flow.',\n quickstart: 'https://docs.agentscore.com/guides/agent-identity',\n identity_check_endpoint: `${api}/v1/credentials`,\n identity_paths: {\n wallet:\n 'If paying from a crypto wallet you have used before on any AgentScore merchant, send ' +\n '`X-Wallet-Address: 0x...`. Shortest path; no token lifecycle to manage.',\n operator_token:\n 'For any rail (Stripe SPT, card, or a wallet you have not linked yet), send ' +\n '`X-Operator-Token: opc_...`. Reusable across merchants until the token expires.',\n ...(acceptsAip && {\n agent_identity:\n 'If you hold an AIP Agent Identity Token from a trusted issuer (see aip_trusted_issuers), ' +\n 'present it: send the JWT in an `Agent-Identity` header plus an RFC 9421 HTTP Message ' +\n 'Signature (Signature-Input + Signature over @method @authority @path agent-identity, ' +\n 'tag=\"agent-identity\") signed with the token-bound cnf key. The merchant verifies it and ' +\n 'applies its policy — no separate AgentScore credential needed.',\n }),\n },\n ...(acceptsAip && { aip_trusted_issuers: aipTrustedIssuers }),\n bootstrap:\n 'If you have neither a linked wallet nor a valid operator_token, follow the session/verify ' +\n 'flow in the per-request `agent_instructions` block. This happens at most once per agent ' +\n 'identity — after first verification, the operator_token and any subsequently used wallet ' +\n 'are reusable everywhere.',\n do_not_persist_in_memory: ['operator_token', 'poll_secret'],\n persist_in_credential_store: ['operator_token'],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Core factory\n// ---------------------------------------------------------------------------\n\nexport function createAgentScoreCore(options: AgentScoreCoreOptions): AgentScoreCore {\n if (!options.apiKey) {\n throw new Error('AgentScore API key is required. Get one at https://www.agentscore.com/sign-up');\n }\n\n const {\n apiKey,\n requireKyc,\n requireSanctionsClear,\n minAge,\n blockedJurisdictions,\n allowedJurisdictions,\n failOpen = false,\n cacheSeconds = 300,\n baseUrl: rawBaseUrl = 'https://api.agentscore.com',\n chain: gateChain,\n userAgent,\n createSessionOnMissing,\n aipTrustedIssuers,\n } = options;\n\n const baseUrl = stripTrailingSlashes(rawBaseUrl);\n const agentMemoryHint = buildAgentMemoryHint(aipTrustedIssuers);\n\n const defaultUa = `@agent-score/commerce@${__VERSION__}`;\n const userAgentHeader = userAgent ? `${userAgent} (${defaultUa})` : defaultUa;\n\n // Single shared SDK instance for every API call this gate makes (assess, sessions,\n // credentials/wallets, telemetry). Connection pooling + typed-error classification +\n // X-Quota-* header capture all flow through here. The SDK owns the transport layer\n // (timeouts, retry-on-429); the gate adds policy semantics on top. Pass the\n // merchant-prefixed UA — SDK appends its own default to produce a chain like\n // `<merchant-app> (@agent-score/commerce@<v>) (@agent-score/sdk@<v>)`.\n const sdk = new AgentScore({ apiKey, baseUrl, userAgent: userAgentHeader });\n\n // createSessionOnMissing can carry its own apiKey + baseUrl (merchants sometimes wire\n // a session-only key for this hook). Lazily build a separate SDK instance keyed on\n // (apiKey, baseUrl) so we don't construct a new client per request.\n const sessionSdkCache = new Map<string, AgentScore>();\n function getSessionSdk(sessionApiKey: string, sessionBaseUrl?: string): AgentScore {\n const key = `${sessionApiKey}|${sessionBaseUrl ?? ''}`;\n let s = sessionSdkCache.get(key);\n if (!s) {\n s = new AgentScore({\n apiKey: sessionApiKey,\n baseUrl: sessionBaseUrl ?? baseUrl,\n userAgent: userAgentHeader,\n });\n sessionSdkCache.set(key, s);\n }\n return s;\n }\n\n const cache = new TTLCache<CachedAssessResult>(cacheSeconds * 1000);\n\n // Mint a verification session via /v1/sessions and return the resulting\n // identity_verification_required DenialReason — or undefined if the mint failed (network\n // error, non-2xx, missing fields). Used for both the missing-identity path and the\n // fixable-wallet bootstrap path: in both cases the UX is identical (agent polls the\n // returned poll_url until it gets a fresh opc_... and retries).\n async function tryMintSessionDenial(ctx: unknown): Promise<DenialReason | undefined> {\n if (!createSessionOnMissing) return undefined;\n try {\n const sessionBody: { context?: string; product_name?: string } = {};\n if (createSessionOnMissing.context != null) sessionBody.context = createSessionOnMissing.context;\n if (createSessionOnMissing.productName != null) sessionBody.product_name = createSessionOnMissing.productName;\n\n if (createSessionOnMissing.getSessionOptions && ctx !== undefined) {\n try {\n const dynamic = await createSessionOnMissing.getSessionOptions(ctx);\n if (dynamic?.context != null) sessionBody.context = dynamic.context;\n if (dynamic?.productName != null) sessionBody.product_name = dynamic.productName;\n } catch (err) {\n console.warn('[gate] createSessionOnMissing.getSessionOptions hook failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // createSessionOnMissing.apiKey may differ from the gate's apiKey (e.g. merchant\n // wires a session-only key for this hook). Build a per-config SDK lazily.\n const sessionSdk = getSessionSdk(createSessionOnMissing.apiKey, createSessionOnMissing.baseUrl);\n const data = (await sessionSdk.createSession({\n ...(sessionBody.context !== undefined ? { context: sessionBody.context } : {}),\n ...(sessionBody.product_name !== undefined ? { product_name: sessionBody.product_name } : {}),\n })) as unknown as Record<string, unknown>;\n\n // Validate required fields before trusting the response. A misbehaving (or mocked-wrong)\n // API could 200 without session_id/poll_secret/verify_url, which would propagate\n // `undefined` into the 403 body and leave the agent stuck — treat as session-create\n // failure and fall back to the caller's bare denial.\n if (\n typeof data.session_id !== 'string' ||\n typeof data.poll_secret !== 'string' ||\n typeof data.verify_url !== 'string'\n ) {\n console.warn('[gate] /v1/sessions returned 200 without required fields — falling back to bare denial');\n return undefined;\n }\n\n // Run onBeforeSession side-effect hook. Errors are swallowed — a failing DB write\n // (e.g. can't insert pending order) should not block the 403.\n let extra: Record<string, unknown> | undefined;\n if (createSessionOnMissing.onBeforeSession && ctx !== undefined) {\n try {\n const sessionMeta = {\n session_id: data.session_id as string,\n verify_url: data.verify_url as string,\n poll_secret: data.poll_secret as string,\n poll_url: data.poll_url as string,\n expires_at: data.expires_at as string | undefined,\n };\n const result = await createSessionOnMissing.onBeforeSession(ctx, sessionMeta);\n if (result && typeof result === 'object') extra = result;\n } catch (err) {\n console.warn('[gate] createSessionOnMissing.onBeforeSession hook failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // The API emits `next_steps` (structured object) on /v1/sessions success. Stringify it\n // into the gate's `agent_instructions` contract so merchants get the same JSON-encoded\n // {action, steps, user_message} envelope as every other gate-emitted denial.\n const apiNextSteps = data.next_steps as Record<string, unknown> | undefined;\n return {\n code: 'identity_verification_required',\n verify_url: data.verify_url as string,\n session_id: data.session_id as string,\n poll_secret: data.poll_secret as string,\n poll_url: data.poll_url as string | undefined,\n agent_instructions: apiNextSteps ? JSON.stringify(apiNextSteps) : undefined,\n agent_memory: agentMemoryHint,\n ...(extra && { extra }),\n };\n } catch (err) {\n // Session-mint failed (network, /v1/sessions returned non-2xx, body parse error,\n // onBeforeSession threw inside the inner try). Caller falls back to a bare denial —\n // agents still get a 403 with a probe-strategy hint. Log loudly so a persistent\n // /v1/sessions outage isn't masked.\n console.warn('[gate] createSessionOnMissing path failed — falling back to bare denial:', err instanceof Error ? err.message : err);\n return undefined;\n }\n }\n\n async function evaluate(\n identity: AgentIdentity | undefined,\n ctx?: unknown,\n signer?: PaymentSigner | null,\n ): Promise<EvaluateOutcome> {\n // Treat \"returned identity object with no usable fields\" the same as \"no identity at all\" —\n // otherwise a misbehaving custom extractIdentity would send an empty body to /v1/assess.\n if (!identity || (!identity.address?.trim() && !identity.operatorToken?.trim() && !identity.aipToken?.trim())) {\n // failOpen short-circuits BEFORE the session mint. This branch isn't an infra failure\n // (no AgentScore call has been made yet) so we don't mark the gate state as degraded —\n // missing identity + failOpen is the explicit opt-in pass-through behavior, not a\n // graceful-degradation event. Merchants who need identity-or-deny on a failOpen gate\n // should add a guard at the handler that checks for X-Wallet-Address / X-Operator-Token\n // before reading the gate state.\n if (failOpen) return { kind: 'allow' };\n\n const sessionReason = await tryMintSessionDenial(ctx);\n if (sessionReason) return { kind: 'deny', reason: sessionReason };\n\n // Bare missing-identity denial (no session was auto-created). Describe the probe\n // strategy so agents without memory can recover: try wallet first on signing rails,\n // fall back to stored opc_..., fall back to session flow (noting that only\n // auto-session merchants return verify_url + poll data on the retry).\n const acceptsAip = aipTrustedIssuers !== undefined && aipTrustedIssuers.length > 0;\n const aipStep = acceptsAip\n ? [\n `If you hold an AIP Agent Identity Token from a trusted issuer (${aipTrustedIssuers.join(', ')}): 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. This satisfies identity in one round trip without an AgentScore credential.`,\n ]\n : [];\n const missingIdentityInstructions = JSON.stringify({\n action: 'probe_identity_then_session',\n steps: [\n ...aipStep,\n 'If you have a wallet AND this merchant accepts a wallet-signing rail (Tempo MPP or x402 — 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 — share it with the user to claim the wallet + complete KYC, then retry.',\n 'If step 1 is denied or you already have a stored operator_token (valid + not expired): send X-Operator-Token: opc_... and retry.',\n '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 — 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 — 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.',\n ],\n user_message:\n '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.',\n });\n return {\n kind: 'deny',\n reason: {\n code: 'missing_identity',\n agent_instructions: missingIdentityInstructions,\n agent_memory: agentMemoryHint,\n },\n };\n }\n\n // operator_token is opaque + ASCII-only — lowercasing is safe. Wallet addresses go\n // through normalizeAddress because Solana base58 is case-sensitive and lowercasing\n // would corrupt the cache key (a Solana cache miss every time, plus collision risk\n // with mixed-case variants of the same operator).\n // AIT cache key: hash the raw token so the (short-lived) JWT isn't held verbatim as a\n // Map key. AITs are seconds-to-minutes TTL anyway; this just dedupes repeated presents\n // within the cache window. Falls through to operator_token / address otherwise.\n const identityKey = identity.aipToken\n ? `aip:${createHash('sha256').update(identity.aipToken).digest('hex')}`\n : identity.operatorToken?.toLowerCase() ?? (identity.address ? normalizeAddress(identity.address) : '');\n\n // The assess response carries per-request, signer-derived verdicts (signer_match +\n // signer_sanctions). The signer is NOT part of the identity, so it must be folded into the\n // response cache key: otherwise a 2nd request with the SAME claimed identity but a DIFFERENT\n // payment signer would hit the cached decision and return the first signer's stale\n // signer_match/signer_sanctions — bypassing wallet-signer binding AND the unconditional OFAC\n // signer screen (a sanctioned 2nd signer would settle on a cached `clear`). Appending the\n // normalized signer (network + address) makes a different signer a cache MISS, forcing a fresh\n // assess that re-screens it. Requests with no signer keep the identity-only key (no behavior\n // change for operator-token / discovery legs).\n //\n // The key is a JSON-encoded parts array, NOT string concatenation: the wallet-path identityKey\n // passes arbitrary (invalid) claimed addresses through lowercased, so a delimiter-bearing\n // X-Wallet-Address could otherwise be crafted to collide with a real (identity, signer) key.\n // JSON escaping + distinct arity make every part injection-proof.\n const cacheKey = signer\n ? JSON.stringify([identityKey, signer.network, normalizeAddress(signer.address)])\n : JSON.stringify([identityKey]);\n\n const cached = cache.get(cacheKey);\n if (cached) {\n // Recompute the per-request verdict from the cached response. The cache key folds in the\n // signer, so a cache hit is the SAME (identity, signer) pair — the cached signer blocks are\n // this request's verdict. Riding it on the return value (vs a shared slot) is what makes\n // concurrent same-wallet/different-signer reads race-free.\n const cachedVerdict = cached.raw\n ? buildSignerVerdict(identity, cached.raw as Record<string, unknown>)\n : undefined;\n if (cached.allow) {\n const cachedRaw = cached.raw as Record<string, unknown> | undefined;\n const cachedQuota = cachedRaw?.quota as GateQuotaInfo | undefined;\n return {\n kind: 'allow',\n data: cachedRaw as unknown as AssessResult,\n ...(cachedQuota !== undefined && { quota: cachedQuota }),\n ...(cachedVerdict !== undefined && { signerVerdict: cachedVerdict }),\n };\n }\n // Fixable compliance denials (kyc_required, kyc_pending, kyc_failed) get the\n // same UX as missing_identity: mint a fresh verification session, agent polls\n // until status=verified, gets a fresh opc_..., retries. Unfixable reasons\n // (sanctions_flagged, age_insufficient, jurisdiction_restricted) keep the bare\n // wallet_not_trusted denial. `jurisdiction_restricted` is unfixable: the API\n // only emits it after KYC is verified (the user's KYC'd country is in the\n // blocked list — re-doing KYC won't change the country).\n if (isFixableDenial(cached.reasons)) {\n const sessionReason = await tryMintSessionDenial(ctx);\n if (sessionReason) {\n return { kind: 'deny', reason: sessionReason, ...(cachedVerdict !== undefined && { signerVerdict: cachedVerdict }) };\n }\n }\n return {\n kind: 'deny',\n reason: {\n code: 'wallet_not_trusted',\n decision: cached.decision,\n reasons: cached.reasons,\n verify_url: (cached.raw as Record<string, unknown> | undefined)?.verify_url as string | undefined,\n data: cached.raw as AssessResult | undefined,\n },\n ...(cachedVerdict !== undefined && { signerVerdict: cachedVerdict }),\n };\n }\n\n const policy: Record<string, unknown> = {};\n if (requireKyc != null) policy.require_kyc = requireKyc;\n if (requireSanctionsClear != null) policy.require_sanctions_clear = requireSanctionsClear;\n if (minAge != null) policy.min_age = minAge;\n if (blockedJurisdictions != null) policy.blocked_jurisdictions = blockedJurisdictions;\n if (allowedJurisdictions != null) policy.allowed_jurisdictions = allowedJurisdictions;\n\n let data: Record<string, unknown>;\n try {\n // Single SDK call: typed-error subclasses (PaymentRequiredError / TokenExpiredError /\n // InvalidCredentialError / QuotaExceededError / TimeoutError) flow through the\n // catch below; success path captures `quota` from X-Quota-* headers automatically.\n const opts = {\n chain: gateChain,\n ...(Object.keys(policy).length > 0 ? { policy: policy as never } : {}),\n // Pre-extracted payment signer (by the adapter middleware). When present, the API\n // composes BOTH signer_match (wallet-binding) and signer_sanctions (OFAC SDN wallet\n // check) verdicts on the response in one round trip. Wallet-OFAC enforcement on the\n // signer block is unconditional — a signer_sanctions hit flips decision -> deny\n // regardless of policy.require_sanctions_clear (which gates the separate NAME screen).\n ...(signer && { signer: { address: signer.address, network: signer.network } }),\n };\n // SDK has overloads — narrow by which identity is set so TS picks the right one.\n // AIT takes precedence: when present it's the sole identity input. The edge already\n // PoP-verified as a fail-fast filter; we forward the token + signature material so the API\n // re-verifies the IdP signature AND the proof-of-possession authoritatively. Checkout always\n // sets both together; a hand-rolled evaluate() with aipToken but no aipSignature is a caller\n // error — fail loudly rather than silently misrouting to the operator-token branch.\n if (identity.aipToken !== undefined && identity.aipSignature === undefined) {\n throw new Error('AgentScoreCore.evaluate: aipToken requires aipSignature (RFC 9421 proof-of-possession material).');\n }\n const result = identity.aipToken !== undefined && identity.aipSignature !== undefined\n ? await sdk.assess(null, { ...opts, aipToken: identity.aipToken, aipSignature: identity.aipSignature })\n : identity.address\n ? await sdk.assess(identity.address, { ...opts, operatorToken: identity.operatorToken })\n : await sdk.assess(null, { ...opts, operatorToken: identity.operatorToken! });\n data = result as unknown as Record<string, unknown>;\n } catch (err) {\n if (err instanceof PaymentRequiredError) {\n if (failOpen) return { kind: 'allow' };\n return { kind: 'deny', reason: { code: 'payment_required' } };\n }\n if (err instanceof TokenExpiredError) {\n // SDK extracts the auto-minted session fields onto the error instance — no body\n // re-parsing needed here.\n return {\n kind: 'deny',\n reason: {\n code: 'token_expired',\n data: err.details as unknown as AssessResult,\n ...(err.verifyUrl ? { verify_url: err.verifyUrl } : {}),\n ...(err.sessionId ? { session_id: err.sessionId } : {}),\n ...(err.pollSecret ? { poll_secret: err.pollSecret } : {}),\n ...(err.pollUrl ? { poll_url: err.pollUrl } : {}),\n ...(err.nextSteps ? { agent_instructions: JSON.stringify(err.nextSteps) } : {}),\n ...(err.agentMemory ? { agent_memory: err.agentMemory as AgentMemoryHint } : {}),\n },\n };\n }\n if (err instanceof InvalidCredentialError) {\n // Permanent — no auto-session, agent should switch tokens or restart.\n return {\n kind: 'deny',\n reason: {\n code: 'invalid_credential',\n agent_instructions: INVALID_CREDENTIAL_INSTRUCTIONS,\n agent_memory: agentMemoryHint,\n },\n };\n }\n if (err instanceof QuotaExceededError) {\n console.warn('[gate] /v1/assess returned 429 quota_exceeded');\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'quota_exceeded' };\n return {\n kind: 'deny',\n reason: { code: 'api_error', agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS },\n };\n }\n if (err instanceof SdkTimeoutError) {\n console.warn('[gate] /v1/assess timed out:', err.message);\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'network_timeout' };\n return { kind: 'deny', reason: { code: 'api_error' } };\n }\n // Status-based fallbacks for AgentScoreError instances the SDK couldn't classify\n // into a typed subclass (e.g. 429 with body that lacked error.code, or a fetch\n // rejection whose .name doesn't match AbortError but whose status code is set).\n // The real API always emits error.code on 429, so this is purely defensive.\n const status = (err as { status?: number } | null)?.status;\n const errName = err instanceof Error ? err.name : '';\n if (status === 429) {\n console.warn('[gate] /v1/assess returned 429 (untyped — defensive)');\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'quota_exceeded' };\n return {\n kind: 'deny',\n reason: { code: 'api_error', agent_instructions: QUOTA_EXCEEDED_INSTRUCTIONS },\n };\n }\n if (errName === 'TimeoutError' || errName === 'AbortError') {\n console.warn('[gate] /v1/assess timed out (by Error.name):', err instanceof Error ? err.message : err);\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'network_timeout' };\n return { kind: 'deny', reason: { code: 'api_error' } };\n }\n // Generic AgentScoreError (rate_limited, 5xx, network_error, body parse, unknown 4xx)\n // or any non-AgentScoreError unexpected throw — surface as api_error.\n // Include the SDK-classified error code (when available) so ops/dev see\n // schema-drift cases like a new 401 error.code rather than a silent 503.\n const errCode = (err as { code?: string } | null)?.code;\n const msg = err instanceof Error ? err.message : String(err);\n const detail = errCode ? `${errCode}: ${msg}` : msg;\n console.warn(`[gate] /v1/assess call failed — surfacing as api_error: ${detail}`);\n if (failOpen) return { kind: 'allow', degraded: true, infraReason: 'api_error' };\n return { kind: 'deny', reason: { code: 'api_error' } };\n }\n\n const decision = data.decision as string | null | undefined;\n const decisionReasons = (data.decision_reasons as string[]) ?? [];\n const allow = decision === 'allow' || decision == null;\n\n cache.set(cacheKey, { allow, decision: decision ?? undefined, reasons: decisionReasons, raw: data });\n\n // Compose the per-request signer verdicts and ride them on the RETURN VALUE so the adapter can\n // stash them on its per-request state (NOT a shared slot — see buildSignerVerdict). guard:\n // wallet-only identity (operator-token / AIT win and signer-match is deliberately not enforced).\n const signerVerdict = buildSignerVerdict(identity, data);\n\n if (allow) {\n // SDK populates `quota` on the assess response from X-Quota-* headers when the\n // API emits them. Surface up to the adapter so merchants can monitor approach-to-cap.\n const quota = data.quota as GateQuotaInfo | undefined;\n return {\n kind: 'allow',\n data: data as unknown as AssessResult,\n ...(quota !== undefined && { quota }),\n ...(signerVerdict !== undefined && { signerVerdict }),\n };\n }\n\n // Fixable compliance denials (kyc_required, kyc_pending, kyc_failed) get the\n // same UX as missing_identity: mint a fresh verification session, agent polls\n // until status=verified, gets a fresh opc_..., retries. Unfixable reasons\n // (sanctions_flagged, age_insufficient, jurisdiction_restricted) keep the bare\n // wallet_not_trusted denial. `jurisdiction_restricted` is unfixable: the API\n // only emits it after KYC is verified (the user's KYC'd country is in the\n // blocked list — re-doing KYC won't change the country).\n if (isFixableDenial(decisionReasons)) {\n const sessionReason = await tryMintSessionDenial(ctx);\n if (sessionReason) {\n return { kind: 'deny', reason: sessionReason, ...(signerVerdict !== undefined && { signerVerdict }) };\n }\n }\n\n return {\n kind: 'deny',\n reason: {\n code: 'wallet_not_trusted',\n decision: decision ?? undefined,\n reasons: decisionReasons,\n verify_url: data.verify_url as string | undefined,\n data: data as unknown as AssessResult,\n },\n ...(signerVerdict !== undefined && { signerVerdict }),\n };\n }\n\n async function captureWallet(options: CaptureWalletOptions): Promise<void> {\n try {\n await sdk.associateWallet({\n operatorToken: options.operatorToken,\n walletAddress: options.walletAddress,\n network: options.network,\n ...(options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}),\n });\n } catch (err) {\n // Fire-and-forget: don't throw. Log so a persistent capture outage is visible\n // to merchant ops — otherwise wallet↔operator linkage silently stops.\n console.warn('[agentscore-commerce] captureWallet failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // Project the API's signer_match block onto the gate's VerifyWalletSignerResult shape.\n // The API authors agent_instructions, claimed/signer operators, and the linked-wallet\n // set (deny-guarded server-side); the gate just shapes those fields into camelCase.\n function projectSignerMatch(\n sm: Record<string, unknown>,\n claimedNorm: string,\n signerNorm: string,\n ): VerifyWalletSignerResult {\n const kind = sm.kind as string;\n if (kind === 'pass') {\n return {\n kind: 'pass',\n claimedOperator: (sm.claimed_operator as string | null | undefined) ?? null,\n signerOperator: (sm.signer_operator as string | null | undefined) ?? null,\n };\n }\n if (kind === 'wallet_auth_requires_wallet_signing') {\n return {\n kind: 'wallet_auth_requires_wallet_signing',\n claimedWallet: (sm.claimed_wallet as string | undefined) ?? claimedNorm,\n agentInstructions:\n (sm.agent_instructions as string | undefined) ?? WALLET_AUTH_REQUIRES_WALLET_SIGNING_INSTRUCTIONS,\n };\n }\n // Default: wallet_signer_mismatch\n const linked = sm.linked_wallets;\n return {\n kind: 'wallet_signer_mismatch',\n claimedOperator: (sm.claimed_operator as string | null | undefined) ?? null,\n actualSignerOperator: (sm.signer_operator as string | null | undefined) ?? null,\n expectedSigner: (sm.expected_signer as string | undefined) ?? claimedNorm,\n actualSigner: (sm.actual_signer as string | undefined) ?? signerNorm,\n linkedWallets: Array.isArray(linked)\n ? (linked as unknown[]).filter((w): w is string => typeof w === 'string')\n : [],\n agentInstructions:\n (sm.agent_instructions as string | undefined) ?? WALLET_SIGNER_MISMATCH_INSTRUCTIONS,\n };\n }\n\n /**\n * Build the per-request signer verdicts (signer_match + signer_sanctions) from an assess\n * response. Returns `undefined` unless the wallet is the EFFECTIVE identity (no operator_token,\n * no AIT — operator-token / AIT wins and signer-match is deliberately NOT enforced) AND the\n * response carried at least one signer block.\n *\n * The verdict is returned on the `EvaluateOutcome` and stashed by each adapter on its\n * PER-REQUEST state (Hono `c`, Express/Fastify `request`, web closure), NOT on a shared slot —\n * so concurrent same-wallet/different-signer requests can never read each other's verdict.\n */\n function buildSignerVerdict(\n identity: AgentIdentity,\n raw: Record<string, unknown>,\n ): SignerVerdict | undefined {\n if (\n identity.address === undefined ||\n identity.operatorToken !== undefined ||\n identity.aipToken !== undefined\n ) {\n return undefined;\n }\n const rawMatch = raw.signer_match as Record<string, unknown> | undefined;\n const rawSanctions = raw.signer_sanctions as SignerVerdict['signer_sanctions'] | undefined;\n if (!rawMatch && !rawSanctions) return undefined;\n const claimedNorm = normalizeAddress(identity.address);\n // The API's signer_match has the actual signer wallet baked in (actual_signer); pass it as\n // signerNorm so the projected shape is consistent.\n const signerNorm = (rawMatch?.actual_signer as string | undefined) ?? claimedNorm;\n return {\n signer_match: rawMatch ? projectSignerMatch(rawMatch, claimedNorm, signerNorm) : null,\n signer_sanctions: rawSanctions ?? null,\n };\n }\n\n return { evaluate, captureWallet };\n}\n","// Network-aware address normalization. EVM addresses (0x + 40 hex) are\n// case-insensitive in the protocol — we lowercase them so DB lookups against\n// `address_lower`-style columns work. Solana addresses are base58 and are\n// case-sensitive — we MUST preserve the input verbatim, never lowercase.\n//\n// Must produce the same normalization the AgentScore API applies, so the gate, API,\n// and merchants resolve wallets the same way. If they drift, captured wallets won't\n// resolve and signer-match silently breaks.\n\nconst SOLANA_BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\nconst EVM_RE = /^0x[0-9a-fA-F]{40}$/;\n\nexport const isValidEvmAddress = (address: string): boolean => EVM_RE.test(address);\n\nexport const isSolanaAddress = (address: string): boolean =>\n SOLANA_BASE58_RE.test(address) && !address.startsWith('0x');\n\nexport const isValidAddress = (address: string): boolean =>\n isValidEvmAddress(address) || isSolanaAddress(address);\n\nexport const normalizeAddress = (address: string): string => {\n if (isSolanaAddress(address)) { return address; }\n return address.toLowerCase();\n};\n","export class TTLCache<T> {\n private store = new Map<string, { value: T; expiresAt: number }>();\n private maxSize: number;\n\n constructor(private defaultTtlMs: number, maxSize = 10000) {\n this.maxSize = maxSize;\n }\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.value;\n }\n\n set(key: string, value: T, ttlMs?: number): void {\n if (this.store.size >= this.maxSize) {\n this.sweep();\n }\n if (this.store.size >= this.maxSize) {\n this.evictOldest(this.store.size - this.maxSize + 1);\n }\n this.store.set(key, {\n value,\n expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs),\n });\n }\n\n /** Remove all expired entries. */\n private sweep(): void {\n const now = Date.now();\n for (const [k, v] of this.store) {\n if (now > v.expiresAt) {\n this.store.delete(k);\n }\n }\n }\n\n /** Evict the oldest `count` entries by insertion order. */\n private evictOldest(count: number): void {\n let removed = 0;\n for (const key of this.store.keys()) {\n if (removed >= count) break;\n this.store.delete(key);\n removed++;\n }\n }\n}\n","/** Detects whether a request is a \"settle leg\" (carries a payment credential)\n * vs a \"discovery leg\" (no payment credential, expects a 402).\n *\n * Used by the gate-conditional mount pattern documented in CLAUDE.md: mount\n * `agentscoreGate` on a route only when payment is being attempted, so the\n * discovery leg flows through unauthenticated and gets a 402 with all rails.\n *\n * Three credential channels are checked:\n * - `Payment-Signature` — MPP credentials (Tempo, Solana, Stripe SPT)\n * - `X-Payment` — x402 v1 EIP-3009 credentials\n * - `Authorization: Payment <jwt>` — x402 v2 / paymentauth.org credentials\n */\n\ntype WebHeaders = { get(name: string): string | null };\ntype RecordHeaders = Record<string, string | string[] | undefined>;\nexport type HeadersLike = WebHeaders | RecordHeaders | Headers;\n\nfunction toTitleCase(name: string): string {\n return name.replace(/(^|-)([a-z])/g, (_m, sep: string, c: string) => sep + c.toUpperCase());\n}\n\nexport function readHeader(headers: HeadersLike, name: string): string | null {\n if (typeof (headers as Partial<WebHeaders>).get === 'function') {\n return (headers as WebHeaders).get(name);\n }\n const rec = headers as RecordHeaders;\n const v = rec[name] ?? rec[name.toLowerCase()] ?? rec[toTitleCase(name)];\n if (typeof v === 'string') return v;\n if (Array.isArray(v) && typeof v[0] === 'string') return v[0];\n return null;\n}\n\nexport function asHeaders(input: Request | HeadersLike): HeadersLike {\n return typeof (input as Partial<Request>).headers === 'object' && input instanceof Request\n ? input.headers\n : (input as HeadersLike);\n}\n\n/** True when the request carries any of the payment-credential headers we\n * recognize. Accepts a Web Fetch `Headers`, a Web Fetch `Request` (uses\n * `request.headers`), or a plain header record (Express/Fastify-shaped).\n *\n * Use this to gate the `agentscoreGate` middleware so anonymous discovery\n * legs flow through and get a 402 with all rails. See CLAUDE.md\n * \"Anonymous discovery\" pattern.\n */\nexport function hasPaymentHeader(input: Request | HeadersLike): boolean {\n const headers = asHeaders(input);\n return Boolean(\n readHeader(headers, 'payment-signature') ||\n readHeader(headers, 'x-payment') ||\n readHeader(headers, 'authorization')?.startsWith('Payment '),\n );\n}\n\n/** True when the request carries an x402 payment credential (`X-Payment` or\n * `Payment-Signature`). Use to dispatch to the x402 settle path. */\nexport function hasX402Header(input: Request | HeadersLike): boolean {\n const headers = asHeaders(input);\n return Boolean(readHeader(headers, 'payment-signature') || readHeader(headers, 'x-payment'));\n}\n\n/** True when the request carries an mppx payment credential\n * (`Authorization: Payment <jwt>`). Use to dispatch to the MPP settle path. */\nexport function hasMppxHeader(input: Request | HeadersLike): boolean {\n const headers = asHeaders(input);\n return Boolean(readHeader(headers, 'authorization')?.startsWith('Payment '));\n}\n\n/** Matches the three-segment base64url shape of a JWT (Stripe SPT and other\n * token-style credentials ride `Authorization: Payment <jwt>`). */\nconst JWT_SHAPE_RE = /^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/;\n\nfunction decodesToJsonObject(token: string): boolean {\n try {\n const parsed: unknown = JSON.parse(Buffer.from(token, 'base64').toString('utf8'));\n return typeof parsed === 'object' && parsed !== null;\n } catch {\n return false;\n }\n}\n\nexport interface MalformedPaymentCredential {\n /** Which credential channel carried the malformed value. */\n channel: 'x402' | 'mpp';\n message: string;\n}\n\n/**\n * Wire-shape gate for payment credentials, cheap enough to run before any\n * merchant hook. A request whose payment header cannot possibly be a\n * credential (not base64/base64url JSON, not a JWT-shaped token) is rejected\n * up front, so junk headers never trigger per-request hooks (`preValidate`,\n * pricing, recipient minting) or the identity-gate API call.\n *\n * This is deliberately a SHAPE check only. Signature verification, payTo\n * binding, and challenge validation stay where they are (the x402 validator\n * and the mppx settle path) — those need per-request state the hooks produce.\n * A well-formed-but-invalid credential still reaches the real validators and\n * fails there.\n *\n * Returns `null` when every present credential channel is plausibly shaped\n * (or no payment header is present).\n */\nexport function malformedPaymentCredential(\n input: Request | HeadersLike,\n): MalformedPaymentCredential | null {\n const headers = asHeaders(input);\n const x402Token = readHeader(headers, 'payment-signature') ?? readHeader(headers, 'x-payment');\n if (x402Token !== null && x402Token.length > 0) {\n if (!decodesToJsonObject(x402Token)) {\n return {\n channel: 'x402',\n message: 'X-Payment header is not decodable base64 JSON.',\n };\n }\n return null;\n }\n const auth = readHeader(headers, 'authorization');\n if (auth !== null && auth.startsWith('Payment ')) {\n const token = auth.slice('Payment '.length).trim();\n if (token.length === 0 || (!decodesToJsonObject(token) && !JWT_SHAPE_RE.test(token))) {\n return {\n channel: 'mpp',\n message:\n 'Authorization: Payment credential is neither base64-encoded JSON nor a token-shaped value.',\n };\n }\n }\n return null;\n}\n","/**\n * Payment-signer extraction.\n *\n * Shared between merchants and the gate. Three paths recover a wallet signer:\n *\n * - **Tempo MPP** — `Authorization: Payment <base64>`; credential `source` is a DID of the\n * form `did:pkh:eip155:<chain>:<address>`.\n * - **Solana MPP `solana/charge`** — `Authorization: Payment <base64>`; recovery via either\n * a `did:pkh:solana:<genesis>:<address>` source (when set by the client) or by decoding\n * the credential's signed-tx payload and reading the SPL `TransferChecked` authority\n * (pull mode only — `payload.type === 'transaction'`).\n * - **x402 EIP-3009 (EVM, e.g. Base/Sepolia)** — `payment-signature` / `x-payment`;\n * decoded payload carries `payload.authorization.from`.\n *\n * Optional peer deps: `mppx` for MPP credentials, `@solana/kit` for the Solana tx-decode\n * fallback. Both dynamic-imported; merchants who don't accept that rail don't need them.\n */\n\nimport { normalizeHeadersToLowercase } from './_headers';\n\nexport type SignerNetwork = 'evm' | 'solana';\n\nconst TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';\nconst TOKEN_2022_PROGRAM = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb';\nconst TRANSFER_CHECKED_DISCRIMINATOR = 12;\n\ninterface SolanaKitMinimal {\n getBase64Codec: () => { encode: (s: string) => Uint8Array };\n getTransactionDecoder: () => { decode: (b: Uint8Array) => { messageBytes: Uint8Array } };\n getCompiledTransactionMessageDecoder: () => {\n decode: (b: Uint8Array) => {\n staticAccounts: ReadonlyArray<string>;\n instructions: ReadonlyArray<{\n programAddressIndex: number;\n accountIndices?: number[];\n data?: Uint8Array;\n }>;\n };\n };\n}\n\n/**\n * Decode a Solana MPP `solana/charge` credential's `payload.transaction` (base64-encoded\n * signed Solana tx) and return the SPL `TransferChecked` authority — the source-ATA owner,\n * which is the buyer's wallet. Pull mode only (`payload.type === 'transaction'`); push mode\n * (`payload.type === 'signature'`) returns null because recovery would require an RPC fetch.\n */\nasync function extractSolanaSignerFromCredential(credential: unknown): Promise<string | null> {\n const payload = (credential as { payload?: { transaction?: string; type?: string } }).payload;\n if (!payload?.transaction || payload.type !== 'transaction') return null;\n\n const moduleName = '@solana/kit';\n const kit = (await import(moduleName).catch(() => null)) as SolanaKitMinimal | null;\n if (!kit?.getBase64Codec || !kit.getTransactionDecoder || !kit.getCompiledTransactionMessageDecoder) {\n return null;\n }\n\n try {\n const txBytes = kit.getBase64Codec().encode(payload.transaction);\n const decoded = kit.getTransactionDecoder().decode(txBytes);\n const message = kit.getCompiledTransactionMessageDecoder().decode(decoded.messageBytes);\n\n // SPL TransferChecked accounts: [source ATA, mint, destination ATA, authority, ...signers].\n // Returns the FIRST matched authority. For multi-recipient `splits` txs, the buyer\n // signs ONE tx with N TransferChecked instructions all sharing the same authority,\n // so first-match is correct; if a tx ever surfaces with mismatched authorities the\n // first one wins (acceptable since both belong to whoever signed the tx).\n for (const ix of message.instructions) {\n const programId = message.staticAccounts[ix.programAddressIndex];\n if (programId !== TOKEN_PROGRAM && programId !== TOKEN_2022_PROGRAM) continue;\n const data = ix.data;\n if (!data || data.length === 0 || data[0] !== TRANSFER_CHECKED_DISCRIMINATOR) continue;\n const accountIndices = ix.accountIndices ?? [];\n const authorityIndex = accountIndices[3];\n if (authorityIndex === undefined) continue;\n // v0 transactions can carry account indices that resolve via address lookup tables;\n // staticAccounts only holds the static set. If the index is out of range, the\n // authority sits in a lookup table we'd need RPC to resolve. Skip cleanly with a\n // warning rather than returning the wrong address.\n if (authorityIndex >= message.staticAccounts.length) {\n console.warn(\n '[gate] Solana TransferChecked authority resolves through an address lookup table; ' +\n 'signer-match recovery requires the static-account form. Skipping.',\n );\n continue;\n }\n const authority = message.staticAccounts[authorityIndex];\n if (authority) return authority;\n }\n return null;\n } catch (err) {\n console.warn('[gate] Solana credential decode failed:', err instanceof Error ? err.message : err);\n return null;\n }\n}\n\nexport interface PaymentSigner {\n /** Recovered wallet address (EVM lowercased; Solana base58 preserved verbatim). */\n address: string;\n /** Network family — used by `captureWallet` and downstream cross-chain attribution. */\n network: SignerNetwork;\n}\n\n/**\n * Recover the signer wallet from the incoming payment credential, including the network\n * family. Returns `null` when no wallet signature is present (e.g. Stripe SPT, card-only\n * payments, or no credential yet).\n *\n * @param request - the inbound `Request`\n * @param x402PaymentHeader - the value of `payment-signature` or `x-payment` header, if any.\n * Extracted separately because some frameworks (Express) don't expose a web `Request` object.\n */\nexport async function extractPaymentSigner(\n request: Request,\n x402PaymentHeader?: string,\n): Promise<PaymentSigner | null> {\n // x402 — base64 JSON, EIP-3009 only. EVM `payload.authorization.from` is the signer.\n // Tried before the MPP path so a request carrying both header families resolves the\n // x402 signer first, consistent with `extractSignerForPrecheck`.\n if (x402PaymentHeader) {\n try {\n const decoded = atob(x402PaymentHeader);\n const parsed = JSON.parse(decoded) as {\n payload?: { authorization?: { from?: string } };\n };\n const from = parsed?.payload?.authorization?.from;\n if (typeof from === 'string' && /^0x[0-9a-fA-F]{40}$/.test(from)) {\n return { address: from.toLowerCase(), network: 'evm' };\n }\n } catch (err) {\n console.warn('[gate] x402 signer extraction failed:', err instanceof Error ? err.message : err);\n }\n }\n\n // MPP — Authorization: Payment <base64>\n const authHeader = request.headers.get('authorization');\n if (authHeader) {\n try {\n const moduleName = 'mppx';\n const mppx = (await import(moduleName).catch(() => null)) as {\n Credential?: {\n extractPaymentScheme: (h: string) => unknown;\n fromRequest: (r: Request) => unknown;\n };\n } | null;\n if (mppx?.Credential?.extractPaymentScheme(authHeader)) {\n const credential = mppx.Credential.fromRequest(request);\n const source = (credential as { source?: string }).source;\n const evmMatch = source?.match(/^did:pkh:eip155:\\d+:(0x[0-9a-fA-F]{40})$/);\n if (evmMatch) return { address: evmMatch[1]!.toLowerCase(), network: 'evm' };\n // Solana CAIP-10: did:pkh:solana:<genesis-base58>:<address-base58>\n const solMatch = source?.match(/^did:pkh:solana:[1-9A-HJ-NP-Za-km-z]{32,44}:([1-9A-HJ-NP-Za-km-z]{32,44})$/);\n if (solMatch) return { address: solMatch[1]!, network: 'solana' };\n // Fallback: source not set by upstream client. Decode the credential's signed-tx\n // payload to find the SPL TransferChecked authority (= source-ATA owner = buyer\n // wallet). Pull mode only.\n const solanaFromTx = await extractSolanaSignerFromCredential(credential);\n if (solanaFromTx) return { address: solanaFromTx, network: 'solana' };\n }\n } catch (err) {\n console.warn('[gate] MPP signer extraction failed:', err instanceof Error ? err.message : err);\n }\n }\n\n return null;\n}\n\n/**\n * Headers-only variant for adapters that don't natively expose a Web Fetch `Request`\n * (Express, Fastify, ASGI-bridged frameworks). Constructs a synthetic Request carrying\n * only the `authorization` header and delegates to {@link extractPaymentSigner}. Works\n * because the MPP and x402 paths only read `request.headers.get('authorization')` and\n * the explicit `x402PaymentHeader` arg — no body, query, or method semantics needed.\n */\nexport async function extractPaymentSignerFromAuth(\n authHeader: string | null | undefined,\n x402PaymentHeader?: string,\n): Promise<PaymentSigner | null> {\n const request = new Request('http://internal.gate/', {\n headers: authHeader ? { authorization: authHeader } : {},\n });\n return extractPaymentSigner(request, x402PaymentHeader);\n}\n\n/**\n * Read the x402 payment header from a `Request`, matching the alternate names merchants might\n * use. Falls back to reading either header directly.\n */\nexport function readX402PaymentHeader(request: Request): string | undefined {\n return (\n request.headers.get('payment-signature') ??\n request.headers.get('x-payment') ??\n undefined\n );\n}\n\n/**\n * One-call signer extraction across both supported credential formats.\n *\n * Tries the x402 `payment-signature` / `x-payment` header first (EIP-3009\n * `payload.authorization.from`), then falls back to the MPP\n * `Authorization: Payment` header DID. Returns the first one that resolves,\n * or `null`.\n *\n * Use this for wallet-cap prechecks and other \"did the agent claim to sign as\n * X?\" checks where you need the signer BEFORE invoking Checkout. Checkout's\n * own settle path runs verification separately and surfaces the verified\n * signer on `SettleOutcome.signerAddress`.\n *\n * Accepts a plain headers dict so it works regardless of which framework the\n * merchant uses (the gate adapters all serialize headers down to a dict by\n * the time they reach the merchant's hooks).\n */\nexport async function extractSignerForPrecheck(\n headers: Record<string, string>,\n): Promise<PaymentSigner | null> {\n const lower = normalizeHeadersToLowercase(headers);\n const x402 = lower['payment-signature'] ?? lower['x-payment'];\n if (x402) {\n const signer = await extractPaymentSignerFromAuth(undefined, x402);\n if (signer !== null) return signer;\n }\n const authorization = lower['authorization'];\n if (authorization && authorization.toLowerCase().startsWith('payment ')) {\n return await extractPaymentSignerFromAuth(authorization);\n }\n return null;\n}\n"],"mappings":"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","names":["import_jose","SdkTimeoutError","options"]}