@astrasyncai/verification-gateway 5.4.2 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -21
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +7 -3
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +7 -3
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +7 -3
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +7 -3
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +7 -3
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +7 -3
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +30 -1
- package/dist/adapters/sdk.d.ts +30 -1
- package/dist/adapters/sdk.js +40 -3
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +40 -3
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +7 -3
- package/dist/bin/astrasync-codex-hook.js +7 -3
- package/dist/bin/astrasync-guard.js +7 -3
- package/dist/bin/astrasync.js +8 -3
- package/dist/browser/background.js +7 -3
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +7 -3
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +7 -3
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +7 -3
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +7 -3
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +7 -3
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +7 -3
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +7 -3
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +7 -3
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +7 -3
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +77 -4
- package/dist/index.d.ts +77 -4
- package/dist/index.js +40 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +40 -3
- package/dist/index.mjs.map +1 -1
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-Bd2O3eX1.d.mts → types-C-hPsi9M.d.mts} +45 -1
- package/dist/{types-DMChboN_.d.ts → types-CKouL1Tv.d.ts} +45 -1
- package/dist/{types-BU04qAAR.d.mts → types-D8DDG-qK.d.mts} +45 -1
- package/dist/{types-BU04qAAR.d.ts → types-D8DDG-qK.d.ts} +45 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +7 -3
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +7 -3
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/trust-levels.ts","../src/version.ts","../src/http.ts","../src/well-known.ts","../src/verify.ts","../src/adapters/stepup-poll.ts","../src/adapters/approval-gate.ts","../src/settlement.ts","../src/adapters/express.ts","../src/transport/http.ts","../src/verified-hop.ts","../src/adapters/http-pdlss.ts","../src/pdlss-pre-check.ts","../src/metadata-capture.ts","../src/edge-config.ts","../src/platform-signatures.ts","../src/edge-core/classify.ts","../src/edge-core/events.ts","../src/adapters/anonymous-beacon.ts","../src/adapters/nextjs.ts","../src/adapters/sdk.ts","../src/transport/index.ts","../src/transport/a2a.ts","../src/transport/mcp.ts","../src/transport/purpose-mapping.ts","../src/transport/transaction-value.ts","../src/transport/rfc9421.ts","../src/transport/rfc9421-verify.ts","../src/transport/nonce-store.ts","../src/transport/ucp.ts","../src/transport/acp.ts","../src/transport/vi.ts","../src/transport/stripe-webhook.ts","../src/transport/constraint-eval.ts","../src/transport/identity-binding.ts","../src/transport/ap2.ts","../src/transport/ap2-verify.ts","../src/transport/acp-verify.ts","../src/transport/mpp.ts","../src/transport/mpp-verify.ts","../src/transport/x402.ts","../src/transport/vi-verify.ts","../src/transport/commerce-pipeline.ts","../src/transport/extractor-registry.ts","../src/transport/registry/visa.ts","../src/transport/registry/mastercard.ts","../src/transport/registry/web-bot-auth.ts","../src/transport/mcp-server.ts","../src/adapters/mcp.ts","../src/registration/errors.ts","../src/registration/api.ts","../src/registration/guidance.ts","../src/agent/index.ts","../src/agent/errors.ts","../src/agent/client.ts","../src/agent/challenge-handler.ts","../src/agent/pdlss-formatter.ts","../src/agent/decision-client.ts","../src/runtime-signatures.ts"],"sourcesContent":["/**\n * AstraSync Universal Verification Gateway — Trust Level helpers.\n *\n * SDK 5.0.0: the `accessLevel` band (`none`/`restricted`/`read-only`/`standard`/\n * `full`/`internal`) was removed entirely — it never gated the access decision\n * (the server does, from a verified ID + runtime challenge + PDLSS match + trust\n * score). What remains here is the coarse trust-level badge derived from the\n * numeric trust score, used only for display.\n */\n\nimport type { TrustLevel } from './types';\n\n/**\n * Trust level score ranges\n */\nexport const TRUST_LEVEL_RANGES: Record<TrustLevel, { min: number; max: number }> = {\n BRONZE: { min: 0, max: 39 },\n SILVER: { min: 40, max: 59 },\n GOLD: { min: 60, max: 79 },\n PLATINUM: { min: 80, max: 100 },\n};\n\n/**\n * Determine trust level from score\n */\nexport function getTrustLevel(score: number): TrustLevel {\n if (score >= 80) return 'PLATINUM';\n if (score >= 60) return 'GOLD';\n if (score >= 40) return 'SILVER';\n return 'BRONZE';\n}\n","/**\n * Single source-of-truth for the SDK's\n * package version emitted on verify-access bodies (and any future\n * telemetry). Bumped alongside `package.json#version` on every release.\n *\n * Why a constant rather than `import pkg from '../package.json'`:\n * - `tsconfig.json` sets `rootDir: ./src`; importing the sibling\n * package.json fails the build with \"outside rootDir\".\n * - Build-time string replacement (tsup `define`, esbuild banner, etc.)\n * adds toolchain coupling for a trivial gain.\n * - Embedded readonly constant works in every environment (Node, browser,\n * bundlers, Deno) without runtime fs / network access.\n *\n * Release discipline: a CI lint can grep `package.json#version` against\n * this constant if the two ever diverge in the wild. A manual bump\n * is fine — bumping both in the release-ceremony commit keeps them\n * lockstep.\n */\nexport const SDK_VERSION = '5.4.1';\n","/**\n * Shared outbound-HTTP wrapper — every request the SDK makes to the\n * AstraSync backend (or anywhere else) goes through `sdkFetch` so it\n * carries an identifying User-Agent.\n *\n * Why: Node's global fetch defaults to `user-agent: node`, which is\n * indistinguishable from every other Node client on the wire. Visit\n * Intelligence observed our own SDK/beacon traffic as anonymous \"node\"\n * visits. Self-identification is the platform's own medicine.\n *\n * Browser note: some browsers filter the User-Agent request header\n * silently (never throwing), so this is a no-op there — which is correct:\n * in a browser the page's real UA is the honest identity.\n */\n\nimport { SDK_VERSION } from './version';\n\nexport const SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;\n\n/**\n * Add the SDK User-Agent without changing the SHAPE of the caller's headers\n * (plain records stay plain records) — interceptors, adapters, and tests\n * read `init.headers` as a record, and `Headers` would also lowercase names.\n */\nfunction withUserAgent(initHeaders: HeadersInit | undefined): HeadersInit {\n if (!initHeaders) return { 'user-agent': SDK_USER_AGENT };\n if (initHeaders instanceof Headers) {\n const copy = new Headers(initHeaders);\n if (!copy.has('user-agent')) copy.set('user-agent', SDK_USER_AGENT);\n return copy;\n }\n if (Array.isArray(initHeaders)) {\n const has = initHeaders.some(([name]) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : [...initHeaders, ['user-agent', SDK_USER_AGENT]];\n }\n const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : { 'user-agent': SDK_USER_AGENT, ...initHeaders };\n}\n\nexport const sdkFetch: typeof fetch = (input, init) =>\n fetch(input, { ...init, headers: withUserAgent(init?.headers) });\n","import { sdkFetch } from './http';\n/**\n * SDK-side discovery of canonical platform URLs via `/.well-known/agentic-commerce`.\n *\n * Fire-and-forget pre-fetch at middleware creation; first verify() awaits\n * the in-flight promise if it hasn't resolved. 60-minute TTL with\n * stale-while-revalidate background refresh.\n */\n\nexport interface WellKnownAgenticCommerce {\n registrationUrl: string;\n documentationUrl: string;\n verifyAccessUrl: string;\n /** 5.1.0: hosted AstraSync MCP bridge endpoint (absent on self-hosted backends). */\n mcpEndpoint?: string;\n /** 5.1.0: bridge connector-discovery doc (absent on self-hosted backends). */\n mcpDiscoveryUrl?: string;\n}\n\ninterface CacheEntry {\n data: WellKnownAgenticCommerce;\n fetchedAt: number;\n}\n\nconst CACHE_TTL_MS = 60 * 60 * 1000; // 60 minutes\n\nconst cache = new Map<string, CacheEntry>();\nconst inflight = new Map<string, Promise<WellKnownAgenticCommerce>>();\n\nfunction wellKnownUrl(apiBaseUrl: string): string {\n // apiBaseUrl is typically 'https://astrasync.ai/api' — strip the /api suffix\n // to get the platform root, then append /.well-known/agentic-commerce.\n const base = apiBaseUrl.replace(/\\/api\\/?$/, '');\n return `${base}/.well-known/agentic-commerce`;\n}\n\nasync function fetchWellKnown(apiBaseUrl: string): Promise<WellKnownAgenticCommerce> {\n const url = wellKnownUrl(apiBaseUrl);\n const response = await sdkFetch(url, {\n method: 'GET',\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) {\n throw new Error(\n `AstraSync platform must expose /.well-known/agentic-commerce; ` +\n `got ${response.status} from ${url}. SDK cannot initialise without it.`\n );\n }\n const data = (await response.json()) as Record<string, unknown>;\n if (!data.registrationUrl || !data.documentationUrl || !data.verifyAccessUrl) {\n throw new Error(\n `/.well-known/agentic-commerce response missing required fields ` +\n `(registrationUrl, documentationUrl, verifyAccessUrl).`\n );\n }\n return data as unknown as WellKnownAgenticCommerce;\n}\n\n/**\n * Start a background fetch. Returns the promise for callers that need\n * to await it (first verify() call).\n */\nexport function prefetchWellKnown(apiBaseUrl: string): Promise<WellKnownAgenticCommerce> {\n const existing = inflight.get(apiBaseUrl);\n if (existing) return existing;\n\n const promise = fetchWellKnown(apiBaseUrl)\n .then((data) => {\n cache.set(apiBaseUrl, { data, fetchedAt: Date.now() });\n inflight.delete(apiBaseUrl);\n return data;\n })\n .catch((err) => {\n inflight.delete(apiBaseUrl);\n throw err;\n });\n\n inflight.set(apiBaseUrl, promise);\n return promise;\n}\n\n/**\n * Get cached well-known URLs. If stale, triggers a background refresh\n * and returns stale data (stale-while-revalidate). If no cache exists,\n * awaits the in-flight fetch or starts a new one.\n */\nexport async function getWellKnownUrls(apiBaseUrl: string): Promise<WellKnownAgenticCommerce> {\n const entry = cache.get(apiBaseUrl);\n\n if (entry) {\n if (Date.now() - entry.fetchedAt > CACHE_TTL_MS) {\n // Stale — trigger background refresh, return stale data\n prefetchWellKnown(apiBaseUrl).catch(() => {\n // Background refresh failed — stale data remains until next request\n });\n }\n return entry.data;\n }\n\n // No cache — must await\n const pending = inflight.get(apiBaseUrl);\n if (pending) return pending;\n\n return prefetchWellKnown(apiBaseUrl);\n}\n\n/**\n * Synchronous cache read — returns cached URLs or undefined.\n * Never triggers a fetch. Used by verify() to avoid extra HTTP calls\n * in the hot path; adapters are responsible for prefetching.\n */\nexport function getCachedWellKnownUrls(apiBaseUrl: string): WellKnownAgenticCommerce | undefined {\n return cache.get(apiBaseUrl)?.data;\n}\n\n/** Reset cache — for testing only. */\nexport function _resetWellKnownCache(): void {\n cache.clear();\n inflight.clear();\n}\n","/**\n * AstraSync Universal Verification Gateway - Core Verification Logic\n *\n * This module handles the core verification logic, calling the AstraSync API\n * and processing the response into a standardized VerificationResult.\n */\n\nimport { sdkFetch } from './http';\nimport type {\n GatewayConfig,\n AgentCredentials,\n VerificationRequest,\n VerificationResult,\n VerifiedAgent,\n VerifiedDeveloper,\n VerifiedOrganization,\n GuidanceInfo,\n EnhancedVerificationResult,\n TokenGuidance,\n RuntimeChallengeResult,\n StepUpApprovalInfo,\n SettlementOutcomeInfo,\n SettlementArtifact,\n AttemptReport,\n} from './types';\nimport { getTrustLevel } from './trust-levels';\nimport type { ObservedMetadata } from './metadata-capture';\nimport { SDK_VERSION } from './version';\nimport { getCachedWellKnownUrls, type WellKnownAgenticCommerce } from './well-known';\n\n/**\n * Default configuration values\n *\n * apiBaseUrl matches the OpenAPI authoritative server (https://astrasync.ai/api\n * for prod, https://staging.astrasync.ai/api for staging). Always include the\n * /api path prefix when overriding — registration / docs URLs are derived by\n * stripping it.\n */\nconst DEFAULT_CONFIG: Partial<GatewayConfig> = {\n apiBaseUrl: 'https://astrasync.ai/api',\n // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.\n // cacheTtl deliberately unset. When undefined, cacheResult applies the 60s\n // default; the caller's explicit value is honoured for cacheable results.\n // Denials and step-up escalations are NEVER cached (3.6.0) regardless of\n // cacheTtl. Set cacheTtl: 0 to disable caching entirely.\n debug: false,\n};\n\n/**\n * Init self-test state. Fires once per process on first verify() call to warn\n * if apiBaseUrl is pointing at the wrong host (e.g. a marketing site that\n * 200s with text/html instead of the API).\n */\nlet initCheckPerformed = false;\n\n/** Test-only: re-arm the one-time init self-check. */\nexport function _resetInitCheck(): void {\n initCheckPerformed = false;\n}\n\n/** One-shot guard for v2.3.0 deprecation warning. */\nlet deprecationWarningShown = false;\n\nasync function performInitCheck(\n apiBaseUrl: string,\n debug?: boolean,\n strictInit?: boolean,\n apiKey?: string\n): Promise<void> {\n initCheckPerformed = true;\n try {\n const probeUrl = `${apiBaseUrl}/agents/verify-access`;\n // HEAD mirrors GET semantics (running the full request pipeline without a\n // body) so the response carries the same content-type the marketing 404\n // would return. OPTIONS often gets short-circuited by CORS-preflight\n // handlers and returns no content-type, defeating the check.\n const response = await sdkFetch(probeUrl, { method: 'HEAD' });\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.startsWith('text/html')) {\n const message =\n `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). ` +\n `This usually means apiBaseUrl is pointing at a marketing site instead of the API. ` +\n `Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;\n // Audit F-A6-33: when strictInit is set, throw on misconfig instead\n // of warning + continuing. Recurring footgun per\n // `[[feedback_astrasync_api_url_canonical]]` — silent warn lets\n // misconfigured prod deploys ship with all verify-access calls\n // silently failing.\n if (strictInit) {\n throw new Error(`${message} (strictInit=true)`);\n }\n console.warn(`${message} Set disableInitChecks: true on GatewayConfig to silence.`);\n } else if (debug) {\n console.log(\n `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`\n );\n }\n\n // 4.0.0: key liveness probe. A dead API key otherwise surfaces only\n // per-request as inbound agents get turned away — the operator should\n // learn at deploy time. 404 = older backend without self-check: silent.\n if (apiKey) {\n const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (selfCheck.status === 401) {\n const body = (await selfCheck.json().catch(() => ({}))) as {\n code?: string;\n message?: string;\n remediation?: { manageUrl?: string };\n };\n const message =\n `[VerificationGateway] the configured AstraSync API key was REJECTED at startup ` +\n `(${body.code ?? 'api_key_invalid'}: ${body.message ?? 'invalid key'}). Every inbound agent ` +\n `will be turned away until the key is rotated` +\n (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : '') +\n `.`;\n if (strictInit) {\n throw new Error(`${message} (strictInit=true)`);\n }\n console.error(message);\n } else if (selfCheck.ok) {\n const body = (await selfCheck.json().catch(() => ({}))) as {\n daysToExpiry?: number | null;\n };\n if (typeof body.daysToExpiry === 'number' && body.daysToExpiry <= 7) {\n console.warn(\n `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) — ` +\n `rotate it at Settings → Developer Tools before integrations start failing.`\n );\n } else if (debug) {\n console.log('[VerificationGateway] API key self-check passed');\n }\n }\n }\n } catch (err) {\n if (strictInit) {\n // strict mode propagates init failures so callers get a clear,\n // synchronous \"your config is broken\" signal at startup.\n throw err;\n }\n if (debug) {\n console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);\n }\n }\n}\n\n/**\n * Simple in-memory cache for verification results\n */\nconst verificationCache = new Map<string, { result: VerificationResult; expiresAt: number }>();\n\n/**\n * Generate cache key from the full request shape.\n *\n * Historically the key was credentials-only (`astraId-apiKey-jwt`),\n * which silently returned the cached result of a prior call even when the\n * subsequent call's purpose/action/counterparty/etc. differed. That was a\n * security gap — a warm cache could serve an allow verdict for a purpose the\n * agent hadn't actually been authorised for. Key now includes every field\n * that affects the backend verdict.\n *\n * MAINTAIN: when adding a field to VerificationRequest that affects the\n * backend verdict, add it to this key. Fields that don't affect verdict\n * (e.g. requestId, timestamps, sdkVersion) don't belong here — including\n * them would needlessly thrash the cache for repeated identical requests.\n *\n * 3.12.0 (Trust Record): `attemptId` and `considerationSet` are\n * deliberately EXCLUDED — like `callerMetadata.observedMetadata` they are\n * observational pass-through that never affects the verdict, and keying on\n * a per-attempt id would defeat verdict caching entirely. Cache hits get\n * their attemptId rewritten in verify() instead (never leak a prior\n * attempt's id from a cached result).\n */\nfunction getCacheKey(request: VerificationRequest, counterpartyId?: string): string {\n const c = request.credentials;\n return [\n c.astraId || '',\n c.apiKey || '',\n c.jwt || '',\n request.purpose || '',\n request.action || '',\n request.resourceType || '',\n request.resource || '',\n request.jurisdiction || '',\n request.transactionValue ?? '',\n request.currency || '',\n // SECURITY (cross-merchant cache leak): the merchant identity is sent via\n // `config.counterpartyId`, NOT on the request, so it was previously absent\n // from the key — two verifies for the SAME agent/purpose/action/value but\n // DIFFERENT merchants collided, and a grant at a permissive merchant (low\n // trust floor) was served for a stricter one. Same bug class as the\n // duration omission (F-A1-07). counterpartyId affects the backend verdict\n // (trust floor / per-route policy), so it MUST key the cache.\n counterpartyId || '',\n request.counterpartyUrl || '',\n request.counterpartyType || '',\n request.isSubAgentRequest ? '1' : '0',\n request.parentAgentId || '',\n request.subAgentDepth ?? '',\n // Audit F-A1-07: previously-missing dimensions that DO affect the\n // backend verdict. Without these, two requests with different\n // durations (e.g. 60s vs 86400s) collided on the same cache key and\n // the shorter-duration allow served the longer-duration request.\n request.durationRequired ?? '',\n request.invocationProtocol || '',\n request.enableRuntimeChallenge ? '1' : '0',\n // callerMetadata fields contribute to risk model; include the ones\n // backend reads. sourceIp/userAgent/forwardedFor change per-request\n // so their inclusion effectively forces a re-check for any varying\n // client (the right behavior — IP-driven anomaly scoring shouldn't\n // be cached across IPs).\n request.callerMetadata?.sourceIp || '',\n request.callerMetadata?.userAgent || '',\n request.callerMetadata?.forwardedFor || '',\n request.callerMetadata?.agentCardUrl || '',\n // UAT2 Bug B (5.4.1): the commerce phase and cart identity DO affect the\n // backend verdict — the confirm leg is the ONLY leg that may execute\n // first-party settlement. Without these, a confirm within the cache TTL of\n // its start_checkout quote was served the cached quote-leg grant (no\n // settlementOutcome) and never reached the backend. Same F-A1-07 bug class.\n request.commercePhase || '',\n request.checkoutSessionId || '',\n ].join('|');\n}\n\n/**\n * Check if cached result is still valid\n */\nfunction getCachedResult(\n request: VerificationRequest,\n counterpartyId?: string\n): VerificationResult | null {\n const key = getCacheKey(request, counterpartyId);\n const cached = verificationCache.get(key);\n\n if (cached && cached.expiresAt > Date.now()) {\n return cached.result;\n }\n\n if (cached) {\n verificationCache.delete(key);\n }\n\n return null;\n}\n\n/**\n * Cache a verification result.\n *\n * 3.6.0: uniform 60s default. The earlier step-up TTL split (300s for\n * step-up verdicts) is gone — step-up verdicts are no longer cached AT ALL\n * (see the write predicate in verify()): a cached step_up_required result\n * carries a pollUrl that goes stale (consumed/expired) and, worse, keeps\n * denying retries that the owner has already approved. When `configuredTtl`\n * is set (truthy positive number), it's honoured for cacheable results.\n */\nconst DEFAULT_CACHE_TTL_SECONDS = 60;\n\nfunction cacheResult(\n request: VerificationRequest,\n result: VerificationResult,\n configuredTtl: number | undefined,\n counterpartyId?: string\n): void {\n const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : DEFAULT_CACHE_TTL_SECONDS;\n const key = getCacheKey(request, counterpartyId);\n verificationCache.set(key, {\n result,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n}\n\n/**\n * Clear the verification cache\n */\nexport function clearCache(): void {\n verificationCache.clear();\n}\n\n/**\n * Extract agent credentials from various sources\n */\nexport function extractCredentials(\n headers: Record<string, string | string[] | undefined>,\n query?: Record<string, string | undefined>\n): AgentCredentials {\n const credentials: AgentCredentials = {};\n\n // Audit F-A1-12: ASTRA-ID shape validation. Accept only the canonical\n // pattern (ASTRA-/ASTRAE- prefix + 1-64 url-safe chars) to prevent CRLF\n // header injection or downstream interpolation surprises. Reject otherwise.\n const ASTRA_ID_PATTERN = /^ASTRAE?-[A-Za-z0-9_-]{1,64}$/;\n\n // Check for ASTRA-ID in headers (case-insensitive). Accepts the historical\n // X-Astra-Id name plus the X-Astra-AgentId / x-astra-agent-id alias the\n // partner asked for in #9a — both surface the same field.\n const astraIdHeader =\n headers['x-astra-id'] ||\n headers['X-Astra-Id'] ||\n headers['X-ASTRA-ID'] ||\n headers['x-astra-agentid'] ||\n headers['X-Astra-AgentId'] ||\n headers['x-astra-agent-id'] ||\n headers['X-Astra-Agent-Id'] ||\n headers['X-ASTRA-AGENT-ID'];\n if (astraIdHeader) {\n // Audit F-A1-11: guard array-confusion. If multiple X-Astra-Id headers\n // were sent (Express collapses to comma-joined string on most paths),\n // take only the first canonical-shaped one.\n const raw = Array.isArray(astraIdHeader)\n ? astraIdHeader[0]\n : typeof astraIdHeader === 'string'\n ? astraIdHeader\n : undefined;\n if (typeof raw === 'string' && ASTRA_ID_PATTERN.test(raw)) {\n credentials.astraId = raw;\n }\n }\n\n // Check for API key in headers\n const apiKeyHeader = headers['x-api-key'] || headers['X-Api-Key'] || headers['X-API-KEY'];\n if (apiKeyHeader) {\n credentials.apiKey = Array.isArray(apiKeyHeader) ? apiKeyHeader[0] : apiKeyHeader;\n }\n\n // Check Authorization header for Bearer token.\n // Audit F-A1-11: defensive type guard — Array.isArray gives a non-string,\n // and Express path quirks can produce undefined despite the truthy check.\n const authHeader = headers['authorization'] || headers['Authorization'];\n if (authHeader) {\n const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;\n if (typeof authValue === 'string') {\n credentials.authorizationHeader = authValue;\n if (authValue.startsWith('Bearer ')) {\n credentials.jwt = authValue.slice(7);\n }\n }\n }\n\n // Check query parameters as fallback\n if (query) {\n if (query.astraId && !credentials.astraId) {\n credentials.astraId = query.astraId;\n }\n if (query.apiKey && !credentials.apiKey) {\n credentials.apiKey = query.apiKey;\n }\n }\n\n return credentials;\n}\n\n/**\n * Check if credentials are present\n */\nexport function hasCredentials(credentials: AgentCredentials): boolean {\n return !!(credentials.astraId || credentials.apiKey || credentials.jwt);\n}\n\n/**\n * Source of a synthesised guidance response. The sources are split — the\n * `'no_credentials'` shape is the original (caller has no AstraSync\n * credentials, suggest registration). The `'api_error'` shape is for when\n * the verify-access HTTP call itself failed (5xx, network, etc.) — DON'T\n * tell a verified-but-currently-blocked partner to \"register your agent\".\n *\n * 4.0.0 adds `'merchant_misconfig'`: the backend rejected THIS INTEGRATION'S\n * own API key (401 api_key_revoked/expired/invalid). Neither the agent's\n * fault nor a platform outage — retrying won't help, and the inbound agent\n * deserves to know the site operator's integration is broken (the\n * gadget-emporium failure mode: a rotated key silently 401ing every\n * credentialed agent for days).\n */\ntype GuidanceSource = 'no_credentials' | 'api_error' | 'merchant_misconfig';\n\n/**\n * MCP-connector steering (5.1.0). Present only when the backend's well-known\n * doc advertises a hosted bridge. The copy must directly counter the observed\n * model refusal (\"go register manually on the dashboard\"): registration via\n * the connector is the agent's own next action, with the human approval built\n * into the flow.\n */\nfunction mcpGuidance(urls?: WellKnownAgenticCommerce): GuidanceInfo['mcp'] {\n if (!urls?.mcpEndpoint) return undefined;\n return {\n endpoint: urls.mcpEndpoint,\n discoveryUrl: urls.mcpDiscoveryUrl,\n message:\n 'If you are operating inside an MCP-capable host (Claude, ChatGPT, Cursor, or any MCP client), ' +\n 'add the AstraSync MCP connector instead of integrating these URLs by hand: registration through ' +\n 'the connector is KEYLESS and HUMAN-APPROVED — your human approves in an in-chat card, and you ' +\n 'never see, hold, or transmit an API key, password, or private key.',\n };\n}\n\n/**\n * Create guidance response for unverified agents or for API-error fallback.\n *\n * The source is split so the `register your agent` template\n * doesn't fire on transient backend failures. Also threads `correlationId`\n * through so adapter `onDenied` handlers can surface it on the merchant's\n * response body for log correlation.\n */\nfunction createGuidanceResponse(\n _config: GatewayConfig,\n reason?: string,\n options: {\n source?: GuidanceSource;\n correlationId?: string;\n /** 3.12.0 (Trust Record): server-echoed attempt handle, threaded like correlationId. */\n attemptId?: string;\n urls?: WellKnownAgenticCommerce;\n /** 4.0.0: backend-provided remediation URLs for the merchant (misconfig source). */\n remediation?: { docsUrl?: string; manageUrl?: string };\n } = {}\n): VerificationResult {\n const source = options.source ?? 'no_credentials';\n const isApiError = source === 'api_error';\n const isMisconfig = source === 'merchant_misconfig';\n const urls = options.urls;\n\n const guidance: GuidanceInfo = isMisconfig\n ? {\n message:\n \"This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). \" +\n 'Your identity and the AstraSync platform are fine — contact the site operator. Retrying will not help.',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? '',\n steps: [\n 'Report the failure to the site operator — their AstraSync API key needs rotating',\n 'Do not retry: the failure is deterministic until the operator updates their key',\n ],\n }\n : isApiError\n ? {\n message:\n 'Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n steps: [\n 'Retry the request with exponential backoff',\n 'If failures persist, share the correlationId with support',\n ],\n }\n : {\n message:\n 'This service verifies AI agents before granting access. Please register your agent with AstraSync.',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n steps: [\n // MCP steering leads when the hosted bridge is advertised — the\n // connector is the agent-actionable path (keyless, human-approved).\n ...(urls?.mcpEndpoint\n ? [\n `Fastest path (inside an MCP host): add the AstraSync MCP connector at ${urls.mcpEndpoint} — keyless, human-approved registration`,\n ]\n : []),\n 'Register for an AstraSync account',\n 'Create and register your agent',\n 'Add your ASTRA-ID to request headers',\n 'Retry your request',\n ],\n ...(mcpGuidance(urls) && { mcp: mcpGuidance(urls) }),\n };\n\n return {\n // Round-18 G4: createGuidanceResponse fires for unverified-agent path or\n // API-error fallback. Identity is not verified (no agent resolved);\n // policy is not evaluated (we never reached the gate).\n identityVerified: false,\n policyAllowed: false,\n guidance,\n denialReasons: reason ? [reason] : ['No valid agent credentials provided'],\n // Round-10 (#47, O5): on API-error fallback, surface a typed failure so\n // partners (and their custom onDenied handlers) can branch on\n // dimension. Without this, the synthesised stub was indistinguishable\n // from a real policy deny.\n failures: isMisconfig\n ? [\n {\n dimension: 'verify_access.merchant_misconfigured',\n message: reason ?? 'The integration API key was rejected by AstraSync',\n guidance: guidance.message,\n },\n ]\n : isApiError\n ? [\n {\n dimension: 'verify_access.api_error',\n message: reason ?? 'Verification temporarily unavailable',\n guidance: guidance.message,\n },\n ]\n : undefined,\n // 4.0.0: typed marker so adapters render the misconfig envelope (503 +\n // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.\n ...(isMisconfig && { misconfigured: true }),\n // 4.6.0: a transient api_error is retryable — mark it so consumers surface\n // \"temporarily unavailable, retry\" (recommendation 'error') instead of\n // coercing the absent recommendation to a policy 'deny'. Misconfig is\n // deterministic and intentionally NOT marked retryable.\n ...(isApiError && { retryable: true }),\n correlationId: options.correlationId,\n attemptId: options.attemptId,\n verifiedAt: new Date(),\n };\n}\n\n/**\n * Call the AstraSync verify-access API\n */\nasync function callVerifyAccessAPI(\n config: GatewayConfig,\n request: VerificationRequest\n): Promise<{\n success: boolean;\n access?: {\n allowed: boolean;\n reason?: string;\n /**\n * Aggregated denial failures (v2.9.8+). Empty / absent when allowed.\n * Each entry is `{ dimension, message, guidance? }` — see\n * `AccessFailure` for the contract.\n */\n failures?: Array<{ dimension: string; message: string; guidance?: string }>;\n requiresStepUp?: boolean;\n requiresApproval?: boolean;\n appliedPolicy?: {\n boundaryName: string;\n policyVersion: string;\n };\n counterparty?: {\n id: string;\n name: string;\n trustScoreRequirement: number;\n };\n };\n agent?: {\n kyaAgentId: string;\n astraId: string;\n name: string;\n trustScore: number;\n trustLevel: string;\n agentStatus: string;\n blockchainStatus: string;\n };\n developer?: {\n kyaOwnerId: string;\n fullName: string;\n email: string;\n identityVerified: boolean;\n trustScore: number;\n };\n organization?: {\n name: string;\n verified: boolean;\n trustScore: number;\n };\n /**\n * Structured explanation of the verification decision. Tells the merchant\n * WHY (id verified? challenge passed? request within PDLSS? trust score?)\n * without exposing thresholds, scope lists, or other-tenant counterparty\n * membership. Empty `attestations` unless the endpoint's access policy\n * declared `required_attestations`.\n */\n verificationContext?: {\n idVerified: boolean;\n runtimeChallenge: {\n status: 'passed' | 'skipped' | 'failed' | 'timeout' | 'not_supported';\n checkedAt: string | null;\n };\n pdlssCheck: {\n result: 'within' | 'exceeded' | 'denied' | 'not_evaluated';\n purpose: 'approved' | 'denied';\n scope: 'approved' | 'denied';\n };\n dynamicTrustScore: number;\n attestations: Array<{\n type: string;\n status: 'passed' | 'failed';\n /** LMAX-POC C1: underlying check timestamp for merchant freshness gates. */\n checkedAt: string;\n validUntil?: string;\n proofType: 'reference' | 'zkp';\n proof: string;\n }>;\n };\n error?: string;\n /**\n * 4.0.0: the backend 401'd this integration's OWN API key (revoked /\n * expired / invalid) — deterministic merchant-side misconfig, not a\n * transient failure. `misconfigCode` carries the backend's api_key_* code\n * and `remediation` its operator-facing URLs when present.\n */\n misconfig?: boolean;\n misconfigCode?: string;\n remediation?: { docsUrl?: string; manageUrl?: string };\n /**\n * When the verify-access server response carries a\n * correlationId on an error envelope, propagate it so the SDK can thread\n * it through createGuidanceResponse → adapter onDenied → merchant body.\n */\n correlationId?: string;\n /**\n * 3.12.0 (Trust Record): the server echoes the attempt-chain\n * handle top-level on every response branch (error envelopes included).\n */\n attemptId?: string;\n}> {\n const { credentials, ...requestData } = request;\n\n // Build the request body. agentId is omitted when not provided so the\n // server treats it as an anonymous canonical-flow call (Branch A/B/C).\n const body: Record<string, unknown> = {\n ...(credentials.astraId && { agentId: credentials.astraId }),\n ...(requestData.purpose && { purpose: requestData.purpose }),\n };\n\n // Add optional fields\n if (requestData.action) body.action = requestData.action;\n if (requestData.resourceType) body.resourceType = requestData.resourceType;\n if (requestData.resource) body.resource = requestData.resource;\n if (requestData.jurisdiction) body.jurisdiction = requestData.jurisdiction;\n if (requestData.transactionValue) body.transactionValue = requestData.transactionValue;\n if (requestData.currency) body.currency = requestData.currency;\n if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;\n if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;\n if (requestData.subAgentDepth !== undefined) body.subAgentDepth = requestData.subAgentDepth;\n // Handshake Protocol v10 additions\n if (requestData.enableRuntimeChallenge)\n body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;\n if (requestData.createSession) body.createSession = requestData.createSession;\n if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;\n if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;\n if (requestData.counterpartyUrl) body.counterpartyUrl = requestData.counterpartyUrl;\n if (config.counterpartyId) body.counterpartyId = config.counterpartyId;\n if (requestData.runtimeChallengeOptions)\n body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;\n // Round-12 (F19): transport-vs-intent separation. MCP middleware sets\n // this to 'mcp'; non-MCP callers leave it unset.\n if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;\n // 5.3.0 (astra-pay): checkout-leg discriminator — first-party settlement\n // fires only on 'confirm'; absent keeps pre-phase server behavior.\n if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;\n // Per-cart idempotency key (checkout session id) forwarded on the confirm\n // leg so concurrent confirms for one cart charge at most once.\n if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;\n // Order-plane cart lines (receipts + fulfillment email) — informational.\n if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;\n // 3.9.0 (§33.5 #1): raw commerce artifacts forwarded verbatim — the\n // backend's Step 0.5 pipeline does the cryptographic verification\n // server-side (adapters forward, never verify locally).\n if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;\n // 3.12.0 (Trust Record, §33.5 #3): attempt-chain handle + consideration set,\n // forwarded skip-when-undefined (observedMetadata precedent) — pure\n // observational pass-through; the server echoes attemptId on every branch.\n if (requestData.attemptId) body.attemptId = requestData.attemptId;\n if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;\n\n // Round-13 (F14 closure / R13-7): emit the SDK package version on every\n // verify-access body so the backend can auto-populate `kya_counterparty.\n // sdk_version` for the calling endpoint. Body field (not User-Agent\n // header) is the canonical channel — works in Node, browser, behind\n // Cloudflare, and across SDK bundlers without environment-specific\n // header gymnastics. Backend's `validation.ts:verifyAccessSchema`\n // accepts the semver regex; the auto-pop logic is forward-only.\n body.sdkVersion = SDK_VERSION;\n\n // Forward caller metadata when present. Merges the legacy top-level\n // clientIp/userAgent into the nested block for backward compatibility.\n if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {\n const meta = {\n ...(requestData.clientIp && { sourceIp: requestData.clientIp }),\n ...(requestData.userAgent && { userAgent: requestData.userAgent }),\n ...requestData.callerMetadata,\n };\n if (Object.keys(meta).length > 0) body.callerMetadata = meta;\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...config.customHeaders,\n };\n\n // verify-access requires authentication. Use ONLY the merchant's\n // configured apiKey for outbound auth. Previously the caller's inbound\n // Authorization header took priority, which pivoted the verify-access\n // call to the caller's identity — letting an attacker who supplied\n // their own Authorization header trigger verify-access calls under\n // THEIR account and observe the resulting verdicts for arbitrary\n // lookups they triggered via the merchant. Audit F-A1-10.\n //\n // The caller-supplied JWT (if any) is already extracted to\n // credentials.jwt and travels in the verify-access request body so\n // backend can evaluate it as the agent's identity claim — separate from\n // the merchant-attribution auth on the outbound HTTPS call.\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n // Legacy header kept for compatibility with any middleware that reads it directly.\n headers['X-API-Key'] = config.apiKey;\n }\n\n try {\n // 4.0.0: hard timeout — without one, a backend that accepts the\n // connection but never answers hangs the merchant's middleware and every\n // inbound agent request behind it (observed live on a partner property).\n // Timeouts land on the catch path below → api_error (fail-closed),\n // NOT misconfig. The edge adapter races its own tighter withBudget.\n const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 10_000),\n });\n\n const data = await response.json();\n\n // v2.3.8 (defect #29): treat 410 Gone as a deterministic deactivated-endpoint\n // signal. Older SDKs may treat any non-2xx as transient and retry; v2.3.8+\n // surfaces it as a structured denial with `reason: 'endpoint_deactivated'`\n // so callers can distinguish \"endpoint gone\" from \"endpoint denied this\".\n if (response.status === 410) {\n return {\n success: true,\n // 3.12.0 (Trust Record): keep the server-echoed attempt handle even on\n // the synthesised 410 deny shape (echoed on every branch).\n attemptId: typeof data?.attemptId === 'string' ? data.attemptId : undefined,\n access: {\n allowed: false,\n reason: 'endpoint_deactivated',\n failures: [\n {\n dimension: 'endpoint.deactivated',\n message:\n typeof data?.message === 'string' ? data.message : 'Endpoint has been deactivated',\n guidance:\n typeof data?.guidance === 'string'\n ? data.guidance\n : 'Reactivate via POST /api/endpoints/{id}/reactivate, or update the URL on the calling agent.',\n },\n ],\n },\n };\n }\n\n if (!response.ok) {\n // 4.0.0: a 401 from verify-access can ONLY mean the backend rejected\n // THIS INTEGRATION'S own API key — agent denials come back as 200 with\n // access.allowed=false. Surface it as merchant-misconfig, not a\n // transient api_error: it is deterministic until the operator rotates\n // the key, and the \"retry with backoff\" template actively misleads.\n // Backends ≥ this round also send code: api_key_* + remediation URLs.\n if (response.status === 401) {\n return {\n success: false,\n error: data.message || data.error || 'Integration API key rejected',\n misconfig: true,\n misconfigCode: typeof data?.code === 'string' ? data.code : undefined,\n remediation:\n data?.remediation && typeof data.remediation === 'object'\n ? (data.remediation as { docsUrl?: string; manageUrl?: string })\n : undefined,\n correlationId: typeof data?.correlationId === 'string' ? data.correlationId : undefined,\n attemptId: typeof data?.attemptId === 'string' ? data.attemptId : undefined,\n };\n }\n // Round-10 (#47, O5): propagate correlationId on the error path too if\n // the server happened to include one (some 5xx error envelopes carry\n // it). Lets the SDK pass it through to the adapter onDenied handler.\n return {\n success: false,\n error: data.message || data.error || `API returned ${response.status}`,\n correlationId: typeof data?.correlationId === 'string' ? data.correlationId : undefined,\n attemptId: typeof data?.attemptId === 'string' ? data.attemptId : undefined,\n };\n }\n\n return data;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n success: false,\n error: `Failed to call verify-access API: ${message}`,\n };\n }\n}\n\n/**\n * Options for a single verify() call (as opposed to GatewayConfig, which is\n * per-gateway). Mirrors the Java SDK's `verify(request, bypassCache)`.\n */\nexport interface VerifyOptions {\n /**\n * Skip the cache READ for this call so the request is guaranteed to reach\n * the backend (the result is still written to the cache if cacheable).\n * Used by the step-up hold-and-poll retry: the re-verify after an approval\n * must hit the server to redeem the single-use approval.\n */\n bypassCache?: boolean;\n}\n\n/**\n * Main verification function\n */\nexport async function verify(\n config: GatewayConfig,\n request: VerificationRequest,\n options?: VerifyOptions\n): Promise<VerificationResult> {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n // v2.5.0: read well-known URLs from cache (prefetched by adapter at middleware creation).\n // Synchronous — never triggers a fetch. If cache is empty, guidance URLs are empty strings.\n const urls = mergedConfig.apiBaseUrl\n ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl)\n : undefined;\n\n // One-time init self-test — fire-and-forget by default, never blocks verify().\n // Audit F-A6-33: when GatewayConfig.strictInit is set, the init promise is\n // awaited and any failure throws synchronously so callers learn about\n // misconfigured apiBaseUrl on the first verify() call rather than silently\n // running with broken auth.\n if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {\n if (mergedConfig.strictInit) {\n await performInitCheck(\n mergedConfig.apiBaseUrl,\n mergedConfig.debug,\n true,\n mergedConfig.apiKey\n );\n } else {\n void performInitCheck(\n mergedConfig.apiBaseUrl,\n mergedConfig.debug,\n false,\n mergedConfig.apiKey\n );\n }\n }\n\n // Deprecation warning for v2.3.0 removed config fields. Fires once per process.\n if (\n !deprecationWarningShown &&\n (config.minTrustScore !== undefined || config.minTrustScoreForFull !== undefined)\n ) {\n deprecationWarningShown = true;\n console.warn(\n '[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 ' +\n 'and have no effect. Server is now the single source of truth for access decisions ' +\n '(verified ID + runtime challenge + PDLSS + trust score). To gate access ' +\n \"to an endpoint, configure the endpoint's trust_score_requirement server-side.\"\n );\n }\n\n // v2.3.0: anonymous traffic no longer short-circuits here. We forward the\n // request to the server with no agentId; the server applies the endpoint's\n // unverifiedAgentPolicy and returns advisory. createGuidanceResponse remains\n // as the offline fallback if the API itself fails (handled below).\n\n // Check cache first. Caching on unless caller explicitly sets cacheTtl: 0\n // to disable. Undefined falls through to the 60s default at cacheResult\n // write time. options.bypassCache skips the read only (hold-and-poll retry\n // must reach the backend to redeem its approval).\n if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {\n const cached = getCachedResult(request, mergedConfig.counterpartyId);\n if (cached) {\n if (mergedConfig.debug) {\n console.log('[VerificationGateway] Returning cached result');\n }\n // 3.12.0 (Trust Record, §33.5 #3): attemptId is excluded from the cache\n // key, so the stored result may carry a PRIOR attempt's id. Overwrite it\n // with this request's own attemptId — or drop it when this request has\n // none — a cached verdict must never leak another attempt's handle.\n // Shallow clone: never mutate the stored entry (a concurrent holder of\n // the same cached object may still be reading it).\n const hit: VerificationResult = { ...cached };\n if (request.attemptId) {\n hit.attemptId = request.attemptId;\n } else {\n delete hit.attemptId;\n }\n return hit;\n }\n }\n\n // Inject counterparty info from config if not already set in request\n const enrichedRequest = { ...request };\n if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {\n enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;\n }\n if (!enrichedRequest.counterpartyType && mergedConfig.counterpartyType) {\n enrichedRequest.counterpartyType = mergedConfig.counterpartyType;\n }\n\n // Call the API\n if (mergedConfig.debug) {\n console.log('[VerificationGateway] Calling verify-access API');\n }\n\n const apiResponse = await callVerifyAccessAPI(mergedConfig, enrichedRequest);\n\n // 3.6.0: the server emits a top-level denialReasons array on every deny\n // path (same strings as the failure messages). Non-empty → authoritative;\n // absent/empty → fall back to the client-side reconstructions below.\n const rawServerDenialReasons = (apiResponse as Record<string, unknown>).denialReasons;\n const serverDenialReasons =\n Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0\n ? (rawServerDenialReasons as string[])\n : undefined;\n\n // Handle API errors\n if (!apiResponse.success) {\n // Round-10 (#47, O5): distinguish API errors from missing-credentials.\n // The previous default tagged any failure with the \"register your\n // agent\" template, which is misleading to a verified partner whose\n // verify-access call hit a 500. The `api_error` source surfaces a\n // typed `verify_access.api_error` failure entry instead.\n // 4.0.0: a rejected merchant key gets its own source — deterministic\n // misconfig must not wear the \"temporarily unavailable, retry\" template.\n return createGuidanceResponse(mergedConfig, apiResponse.error, {\n source: apiResponse.misconfig ? 'merchant_misconfig' : 'api_error',\n correlationId: (apiResponse as { correlationId?: string }).correlationId,\n attemptId: (apiResponse as { attemptId?: string }).attemptId,\n remediation: apiResponse.remediation,\n urls,\n });\n }\n\n // Check access result\n if (!apiResponse.access?.allowed) {\n // v2.9.8 (defect M1): aggregated failures across every gate that\n // denied. Surface them on the result so the integrator can see every\n // blocker in one go instead of the previous fail-fast cascade.\n const aggregatedFailures = (apiResponse.access as Record<string, unknown> | undefined)\n ?.failures as Array<{ dimension: string; message: string; guidance?: string }> | undefined;\n // Round-18 G4: backend denied access (PDLSS or other gate); identity status\n // depends on whether the backend resolved the caller. Read from\n // verificationContext.idVerified; default false if absent (anonymous or\n // identity-fail paths land here too). policyAllowed is false by definition\n // in this branch (apiResponse.access.allowed === false).\n const idVerifiedFromBackend =\n (apiResponse.verificationContext as { idVerified?: boolean } | undefined)?.idVerified ===\n true;\n const result: EnhancedVerificationResult = {\n identityVerified: idVerifiedFromBackend,\n policyAllowed: false,\n // 3.6.0: the server now emits top-level denialReasons on every deny\n // path — prefer it verbatim; the failure-message reconstruction remains\n // as the fallback for older backends.\n denialReasons:\n serverDenialReasons ??\n (aggregatedFailures && aggregatedFailures.length > 0\n ? aggregatedFailures.map((f) => f.message)\n : apiResponse.access?.reason\n ? [apiResponse.access.reason]\n : ['Access denied']),\n failures: aggregatedFailures,\n requiresStepUp: apiResponse.access?.requiresStepUp,\n requiresApproval: apiResponse.access?.requiresApproval,\n guidance: {\n message: apiResponse.access?.reason || 'Access denied by PDLSS policy',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n // 5.1.0: anonymous callers land on this branch — steer MCP-hosted\n // agents to the connector (this is what the edge deny body surfaces).\n ...(mcpGuidance(urls) && { mcp: mcpGuidance(urls) }),\n },\n verifiedAt: new Date(),\n // Extract sessionId so decisions can be recorded for denials too\n sessionId: (apiResponse as Record<string, unknown>).sessionId as string | undefined,\n // Anonymous traffic has no session → correlationId is the per-attempt\n // linking key (the sessionId-equivalent for anonymous callers).\n correlationId: (apiResponse as Record<string, unknown>).correlationId as string | undefined,\n // 3.12.0 (Trust Record): server echoes the attempt-chain handle on\n // every branch — denials included (the funnel outlives one deny).\n attemptId: (apiResponse as Record<string, unknown>).attemptId as string | undefined,\n recommendation: (apiResponse as Record<string, unknown>)\n .recommendation as EnhancedVerificationResult['recommendation'],\n recommendationReasons: (apiResponse as Record<string, unknown>).recommendationReasons as\n | string[]\n | undefined,\n stepUpApproval: (apiResponse as Record<string, unknown>).stepUpApproval as\n | StepUpApprovalInfo\n | undefined,\n settlement: (apiResponse as Record<string, unknown>).settlement as\n | SettlementArtifact\n | undefined,\n settlementOutcome: (apiResponse as Record<string, unknown>).settlementOutcome as\n | SettlementOutcomeInfo\n | undefined,\n };\n\n return result;\n }\n\n // Build successful result\n const agent: VerifiedAgent | undefined = apiResponse.agent\n ? {\n astraId: apiResponse.agent.astraId,\n name: apiResponse.agent.name,\n trustScore: apiResponse.agent.trustScore,\n trustLevel: getTrustLevel(apiResponse.agent.trustScore),\n blockchainVerified: apiResponse.agent.blockchainStatus === 'verified',\n status: apiResponse.agent.agentStatus as VerifiedAgent['status'],\n }\n : undefined;\n\n const developer: VerifiedDeveloper | undefined = apiResponse.developer\n ? {\n astradId: apiResponse.developer.kyaOwnerId,\n name: apiResponse.developer.fullName,\n trustScore: apiResponse.developer.trustScore || 0,\n verified: apiResponse.developer.identityVerified,\n }\n : undefined;\n\n const organization: VerifiedOrganization | undefined = apiResponse.organization\n ? {\n name: apiResponse.organization.name,\n verified: apiResponse.organization.verified,\n trustScore: apiResponse.organization.trustScore,\n }\n : undefined;\n\n // Verification context — structured \"why\" the merchant gets in v2.2.4+.\n // Carries appliedPolicy (no UUIDs), pdlssCheck summary, dynamic trust score,\n // and policy-driven attestations. Replaces the old over-sharing `pdlss` block.\n const verificationContext = apiResponse.verificationContext;\n\n const result: EnhancedVerificationResult = {\n // 4.5.0 (probe F1): read idVerified from verificationContext with the\n // SAME absent⇒false default as the deny branch. The previous `!== false`\n // default manufactured `identityVerified: true` for anonymous\n // allow_full/allow_partial/audit responses (which allow access but omit\n // verificationContext entirely) — the \"anonymous caller labelled\n // verified\" defect. Every authenticated success response has carried\n // `verificationContext.idVerified: true` since v2.2.4, so a truth claim\n // this load-bearing must never be defaulted on.\n identityVerified:\n (apiResponse.verificationContext as { idVerified?: boolean } | undefined)?.idVerified ===\n true,\n policyAllowed: true,\n agent,\n developer,\n organization,\n appliedPolicy: apiResponse.access?.appliedPolicy,\n verificationContext,\n requiresStepUp: apiResponse.access?.requiresStepUp,\n requiresApproval: apiResponse.access?.requiresApproval,\n verifiedAt: new Date(),\n cacheTtl: mergedConfig.cacheTtl,\n // Handshake Protocol v10 enhanced fields (present when backend returns them)\n sessionId: (apiResponse as Record<string, unknown>).sessionId as string | undefined,\n // v2.3.10 (defect #34, round-4): anonymous responses surface correlationId\n // (no session row exists for unverified callers).\n correlationId: (apiResponse as Record<string, unknown>).correlationId as string | undefined,\n // 3.12.0 (Trust Record): server-echoed attempt-chain handle.\n attemptId: (apiResponse as Record<string, unknown>).attemptId as string | undefined,\n runtimeChallenge: (apiResponse as Record<string, unknown>).runtimeChallenge as\n | RuntimeChallengeResult\n | undefined,\n tokenGuidance: (apiResponse as Record<string, unknown>).tokenGuidance as\n | TokenGuidance\n | undefined,\n recommendation: (apiResponse as Record<string, unknown>)\n .recommendation as EnhancedVerificationResult['recommendation'],\n recommendationReasons: (apiResponse as Record<string, unknown>).recommendationReasons as\n | string[]\n | undefined,\n warningHeader: (apiResponse as Record<string, unknown>).warningHeader as\n | { name: string; value: string }\n | undefined,\n stepUpApproval: (apiResponse as Record<string, unknown>).stepUpApproval as\n | StepUpApprovalInfo\n | undefined,\n settlement: (apiResponse as Record<string, unknown>).settlement as\n | SettlementArtifact\n | undefined,\n settlementOutcome: (apiResponse as Record<string, unknown>).settlementOutcome as\n | SettlementOutcomeInfo\n | undefined,\n };\n\n // Enforce AstraSync recommendation\n if (result.recommendation === 'deny') {\n // Round-18 G4: recommendation-driven deny lands on the success-path\n // construction (identity was resolved). Flip policy only — identity stays\n // verified — so adapters return 403 (re-auth won't help; the policy\n // decision is the blocker).\n result.policyAllowed = false;\n // 3.6.0: server-sent top-level denialReasons wins; recommendationReasons\n // reconstruction is the fallback for older backends.\n result.denialReasons = serverDenialReasons ??\n result.recommendationReasons ?? ['Access denied by AstraSync recommendation'];\n result.guidance = result.runtimeChallenge\n ? {\n message: `Verification failed: ${result.runtimeChallenge.reason || 'runtime challenge failed'}`,\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n }\n : {\n message: result.recommendationReasons?.[0] || 'Access denied by AstraSync recommendation',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n };\n } else if (result.recommendation === 'step_up_required') {\n // The escalation signal rides on `requiresStepUp` / `stepUpApproval`, not\n // on any masquerade of the (now-removed) access band.\n result.requiresStepUp = true;\n result.denialReasons = serverDenialReasons ??\n result.recommendationReasons ?? ['Step-up verification required'];\n }\n\n // Cache the result. Never cache denials (agent may fix challenge endpoint\n // and retry) NOR step-up escalations (3.6.0 — the same bug the Java SDK\n // had: a cached step_up_required verdict keeps denying retries the owner\n // has already approved, and its pollUrl goes stale once consumed/expired).\n // Escalations stay uncached even when the caller pins an explicit cacheTtl.\n const escalates =\n result.requiresStepUp === true ||\n result.requiresApproval === true ||\n result.recommendation === 'step_up_required';\n if (mergedConfig.cacheTtl !== 0 && result.recommendation !== 'deny' && !escalates) {\n cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);\n }\n\n return result;\n}\n\n/**\n * Record a counterparty's grant/deny decision for a verification session.\n * Fire-and-forget — errors are silently swallowed.\n */\nexport async function recordDecision(\n config: GatewayConfig,\n sessionId: string,\n decision: 'granted' | 'denied',\n reason?: string\n): Promise<void> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n\n await sdkFetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ decision, reason }),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Report post-hoc consideration/outcome data for an attempt chain (Trust\n * Record). Use when the signal never reached verify-access: a\n * catalog served from a local cache, a transport-side deny (sku not found,\n * over budget), or a terminal outcome (settled / blocked on step-up).\n * Authenticated with the same credentials as verify(); the backend responds\n * 202 and folds the data into the attempt chain keyed by `attemptId`.\n *\n * Fire-and-forget — errors are silently swallowed, never throws.\n */\nexport async function reportAttempt(config: GatewayConfig, report: AttemptReport): Promise<void> {\n const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl!;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n\n // counterpartyId resolution mirrors reportUnregisteredAttempt: an explicit\n // report value wins; otherwise attribute to the configured endpoint.\n const body = {\n ...report,\n ...(!report.counterpartyId &&\n config.counterpartyId && { counterpartyId: config.counterpartyId }),\n };\n\n await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Fetch the per-route policy for an endpoint from the AstraSync backend.\n * v2.9.7 moved policy authority into the dashboard — the SDK no longer\n * accepts `routes` from merchant-side source code, it fetches them from\n * here on init (and refreshes periodically).\n *\n * Returns `null` when the request fails for any reason — the caller decides\n * how to fall back (the middleware allows-all when no policy is loaded so\n * a misconfigured init doesn't take down the merchant's API).\n */\nexport async function fetchRoutes(\n config: GatewayConfig,\n counterpartyId: string\n): Promise<RouteAccessConfigShape[] | null> {\n if (!counterpartyId) return null;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n try {\n const response = await sdkFetch(\n `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,\n { method: 'GET', headers }\n );\n if (!response.ok) return null;\n const body = (await response.json()) as { data?: { routes?: RouteAccessConfigShape[] } };\n return body.data?.routes ?? [];\n } catch {\n return null;\n }\n}\n\n/**\n * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the\n * server's `EndpointRoute` type and the SDK's `RouteAccessConfig` — same\n * JSON moves between server and SDK unchanged.\n */\nexport interface RouteAccessConfigShape {\n pattern: string;\n method: string;\n /** Pass through unenforced (observe). Replaces `minAccessLevel: 'none'`. */\n observe?: boolean;\n minTrustScore?: number;\n requiredPurposes?: string[];\n allowedPurposes?: string[];\n allowedJurisdictions?: string[];\n maxDuration?: number;\n maxTransactionValue?: number;\n requirePurpose?: boolean;\n /** Send-mapping — see RouteAccessConfig in types.ts. */\n purpose?: string;\n action?: string;\n}\n\n/**\n * Verify an agent AND automatically record the grant/deny decision.\n *\n * This is the recommended entry point for counterparties that call verify()\n * directly (e.g. MCP servers) rather than using createMiddleware().\n * It adds createSession: true, then fire-and-forgets the decision.\n */\nexport async function verifyAndRecord(\n config: GatewayConfig,\n request: VerificationRequest,\n options?: VerifyOptions\n): Promise<VerificationResult> {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n const result = await verify(mergedConfig, { ...request, createSession: true }, options);\n const sessionId = (result as EnhancedVerificationResult).sessionId;\n\n if (sessionId) {\n // Round-18 G4: a session is \"granted\" only if identity verified AND\n // policy allowed; either failing is a deny.\n if (result.identityVerified && result.policyAllowed) {\n recordDecision(mergedConfig, sessionId, 'granted').catch(() => {});\n } else {\n recordDecision(mergedConfig, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n }\n\n return result;\n}\n\n/**\n * Report an unregistered agent attempt (no AstraSync credentials).\n * Called by SDK adapters when an agent is redirected to /docs/agent-access.\n * Fire-and-forget — errors are silently swallowed.\n */\nexport async function reportUnregisteredAttempt(\n config: GatewayConfig,\n data: {\n /**\n * 3.6.0: optional — the backend attributes by counterpartyId first (sent\n * from config below) and requires at least ONE of counterpartyId/URL.\n * A null/undefined URL is omitted from the body, not sent as null.\n */\n counterpartyUrl?: string;\n counterpartyType?: string;\n sourceIp?: string;\n userAgent?: string;\n requestPath?: string;\n requestMethod?: string;\n /**\n * 3.9.0 — edge-adapter evidence fields, persisted into the\n * event's eventData by the backend: `protocol` = detected transport/\n * credential protocol; `evidence` = light crypto-free detection detail.\n */\n protocol?: string;\n evidence?: Record<string, unknown>;\n /**\n * Maximal metadata capture — the full sanitised metadata for an\n * unregistered caller (every signal legitimately visible on the wire).\n * Persisted into eventData; feeds platform attribution and (via\n * correlationId) registration auto-fill. Fire-and-forget, so free.\n */\n observedMetadata?: ObservedMetadata;\n }\n): Promise<void> {\n const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl!;\n\n const { counterpartyUrl, ...rest } = data;\n const body = {\n ...rest,\n ...(counterpartyUrl && { counterpartyUrl }),\n ...(config.counterpartyId && { counterpartyId: config.counterpartyId }),\n };\n\n await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Report a counterparty-side PDLSS pre-check failure.\n * Called by SDK adapters when the agent's requested PDLSS exceeds\n * counterparty-defined maximums BEFORE calling verify-access.\n * Fire-and-forget — errors are silently swallowed.\n */\nexport async function reportCounterpartyPreCheckFailure(\n config: GatewayConfig,\n data: {\n agentId: string;\n counterpartyUrl: string;\n counterpartyType?: string;\n failures: Array<{\n field: string;\n requested: string | number;\n limit: string | number | string[];\n message: string;\n }>;\n requestPath?: string;\n requestMethod?: string;\n }\n): Promise<void> {\n const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl!;\n\n await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Quick verification — checks credentials and policy in one call.\n *\n * The return shape mirrors `VerificationResult`'s split — partners\n * writing custom handlers around `quickVerify` get the same identity/policy\n * distinction as those calling `verify()` directly. Map to HTTP status the\n * same way: `!identityVerified` → 401; `identityVerified && !policyAllowed`\n * → 403.\n */\nexport async function quickVerify(\n config: GatewayConfig,\n credentials: AgentCredentials\n): Promise<{\n identityVerified: boolean;\n policyAllowed: boolean;\n reason?: string;\n}> {\n const result = await verify(config, {\n credentials,\n purpose: 'verification',\n });\n\n return {\n identityVerified: result.identityVerified,\n policyAllowed: result.policyAllowed,\n reason: result.denialReasons?.[0],\n };\n}\n","/**\n * Step-up hold-and-poll (3.6.0) — the synchronous half of the MFA-style gate,\n * mirroring the Java SDK's `awaitStepUpApproval` / `pollStepUpStatus`.\n *\n * A verify() that comes back step_up_required carries a `stepUpApproval`\n * handle: `{ approvalId, pollUrl, expiresAt }`. The adapter HOLDS the original\n * request, polls the approval status, and on 'approved' re-verifies the same\n * request once (cache-bypassed) so the backend redeems the single-use approval\n * and returns a grant. Any other terminal outcome falls into the adapter's\n * normal fail-closed deny path.\n *\n * The poll endpoint is deliberately unauthenticated (it sits above the\n * backend router's `authenticate` middleware): the unguessable UUIDv4\n * approvalId is the capability token, and the route is rate-limited\n * (60/min/IP). No Authorization header is sent.\n */\n\nimport { sdkFetch } from '../http';\nimport { GatewayConfig, StepUpApprovalInfo, StepUpApprovalStatus, StepUpOutcome } from '../types';\n\nconst DEFAULT_POLL_INTERVAL_MS = 3000;\nconst MIN_POLL_INTERVAL_MS = 250;\nconst FALLBACK_MAX_WAIT_MS = 5 * 60 * 1000;\nconst EXPIRY_GRACE_MS = 5000;\nconst POLL_REQUEST_TIMEOUT_MS = 10_000;\n\n/** Resolve the absolute poll URL. pollUrl is server-relative\n * (`/api/step-up-approvals/poll/:id`), so join it to apiBaseUrl minus its\n * `/api` suffix (the origin) — same idiom as well-known.ts. Absolute URLs\n * pass through untouched. */\nfunction resolvePollUrl(config: GatewayConfig, pollUrl: string): string {\n if (pollUrl.startsWith('http')) return pollUrl;\n const origin = (config.apiBaseUrl ?? '').replace(/\\/api\\/?$/, '');\n return origin + pollUrl;\n}\n\n/**\n * One GET of the approval's poll endpoint. Returns the status string, or\n * null on any error / non-2xx / unparsable body — the hold loop treats null\n * as transient and just polls again.\n */\nexport async function pollStepUpStatus(\n config: GatewayConfig,\n approval: StepUpApprovalInfo\n): Promise<StepUpApprovalStatus | null> {\n if (!approval.pollUrl) return null;\n try {\n const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {\n method: 'GET',\n signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as Record<string, unknown>;\n // Envelope shape: { success, data: { status, resolvedAt } } — a flat\n // `status` read hangs every hold (live-UAT catch). Envelope-first with a\n // flat fallback for forward compatibility, exactly like the Java SDK.\n const data = body?.data;\n const status =\n data && typeof data === 'object' ? (data as Record<string, unknown>).status : body?.status;\n return typeof status === 'string' ? (status as StepUpApprovalStatus) : null;\n } catch {\n return null; // transient poll failure — the loop just polls again\n }\n}\n\nfunction resolveDeadline(config: GatewayConfig, approval: StepUpApprovalInfo): number {\n const now = Date.now();\n const maxWait = config.stepUpMaxWaitMs ?? 0;\n if (maxWait > 0) return now + maxWait;\n // stepUpMaxWaitMs === 0: hold until the approval itself expires (+ a small\n // grace so an approval landing at the buzzer still resolves on the next\n // poll). Missing/unparsable expiresAt → fixed 5-min fallback (Java parity).\n if (approval.expiresAt) {\n const expiry = Date.parse(approval.expiresAt);\n if (!Number.isNaN(expiry)) return Math.max(now, expiry) + EXPIRY_GRACE_MS;\n }\n return now + FALLBACK_MAX_WAIT_MS;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Block until a pending step-up approval reaches a terminal state or the wait\n * budget runs out. Returns the terminal status, or 'timeout'.\n *\n * Unknown non-pending statuses (a future backend state) still terminate the\n * hold — they are returned as-is and land in the deny path, which is the safe\n * reading of \"not approved\".\n */\nexport async function awaitStepUpApproval(\n config: GatewayConfig,\n approval: StepUpApprovalInfo\n): Promise<StepUpOutcome> {\n const deadline = resolveDeadline(config, approval);\n const pollInterval = Math.max(\n MIN_POLL_INTERVAL_MS,\n config.stepUpPollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS\n );\n\n while (Date.now() < deadline) {\n const status = await pollStepUpStatus(config, approval);\n if (status && status !== 'pending') {\n return status as StepUpOutcome;\n }\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await sleep(Math.min(pollInterval, remaining));\n }\n return 'timeout';\n}\n","/**\n * Direct-path step-up approval gate (post-3.1.0 F2 follow-up).\n *\n * The verify-access spending-Limit ladder returns an \"allowed-but-escalate\"\n * outcome for a transaction value in the human-in-the-loop band\n * `[autonomousThreshold, hardLimit)`: `policyAllowed: true` (it is NOT a deny)\n * plus `requiresStepUp` / `requiresApproval`. The bridge blocks these; the\n * direct-path adapters historically gated on `identityVerified && policyAllowed`\n * alone and would therefore ADMIT (and let the merchant settle) the very\n * purchase the bridge blocks - a cross-path bypass.\n *\n * The backend now creates a pending step-up approval record and returns a\n * `stepUpApproval` object with `{ approvalId, pollUrl, expiresAt }` in the\n * verify-access response. The owner can approve/deny from the dashboard\n * (Activity → Pending Verifications). Future channels: mobile push, browser\n * extension.\n *\n * Direct-path adapters (Express/MCP/Next.js) fail closed BY DEFAULT. The\n * `stepUpApproval` info is included in the deny response so integrations can\n * surface it (\"your agent owner needs to approve this\") or poll it themselves.\n * 3.6.0 adds an opt-in hold-and-poll (`stepUpMaxWaitMs` on GatewayConfig, see\n * ./stepup-poll.ts): the adapter holds the request, polls the approval, and on\n * 'approved' re-verifies once (cache-bypassed) so the backend redeems the\n * single-use approval — the MFA model the Java SDK ships default-on. Opt-in\n * here because a minor release must not silently convert instant 403s into\n * multi-minute holds (client timeouts, connection pools, edge wall-clocks).\n *\n * Detection keys on the granular Limit flags (`requiresStepUp` /\n * `requiresApproval`, set from the verify-access `access` block) rather than\n * the `recommendation` umbrella - both because those flags ARE what drive a\n * `step_up_required` recommendation server-side, and because it keeps the\n * unverified-agent-policy `audit` outcome (a deliberate allow-and-log) from\n * being caught here.\n */\nimport type { VerificationResult, StepUpApprovalInfo } from '../types';\n\nconst APPROVAL_REASON =\n 'Transaction is above the autonomous limit and requires human approval. The agent owner can approve or deny this transaction in the AstraSync dashboard.';\n\n/** True when the outcome needs human step-up/approval. */\nexport function requiresHumanApproval(result: VerificationResult): boolean {\n return result.requiresStepUp === true || result.requiresApproval === true;\n}\n\n/**\n * Annotate a result in place with the structured approval-required failure +\n * denial reason, so the adapters' existing deny renderers surface it like any\n * other failure. Mirrors the bridge's `commerce.intent.approval_required`.\n */\nexport function annotateApprovalRequired(result: VerificationResult): void {\n result.failures = [\n ...(result.failures ?? []),\n { dimension: 'commerce.intent.approval_required', message: APPROVAL_REASON },\n ];\n result.denialReasons = [APPROVAL_REASON, ...(result.denialReasons ?? [])];\n}\n\n/**\n * Extract step-up approval polling info from the verification result, if\n * present. Returns undefined when no approval was created (e.g. transaction\n * below the autonomous threshold, or the backend couldn't create one).\n */\nexport function getApprovalPollingInfo(result: VerificationResult): StepUpApprovalInfo | undefined {\n return result.stepUpApproval;\n}\n","/**\n * Settlement authorization — the value-aware, FAIL-CLOSED gate a direct merchant\n * MUST call before settling a priced cart (post-#447 partner round, finding #1).\n *\n * The bug it closes: the SDK request middleware performs a header-only ACCESS\n * check and never sends the transaction VALUE to verify-access, so the limit\n * engine never evaluates value and returns `grant` — a fully SDK-compliant\n * merchant settles every band, with the agent's PDLSS spend limits silently\n * unenforced. The bridge is safe only because `confirm_purchase` re-verifies\n * with the authoritative session total.\n *\n * The authoritative value exists ONLY after the merchant prices the cart (in the\n * handler, after the middleware), and it must be the MERCHANT's priced total —\n * never an agent-suppliable header (spoofable). So value enforcement is a\n * settlement-time, merchant-invoked call that mirrors the bridge: verify the\n * priced value against the agent's limits and refuse settlement unless it\n * cleanly grants.\n */\nimport type {\n GatewayConfig,\n VerificationResult,\n EnhancedVerificationResult,\n AccessFailure,\n StepUpApprovalInfo,\n} from './types';\nimport { verify } from './verify';\nimport { requiresHumanApproval } from './adapters/approval-gate';\n\nexport interface SettlementRequest {\n /** The agent's ASTRA-id (the caller you are about to settle for). */\n agentId: string;\n /** The MERCHANT's authoritative priced total for the cart. Never an agent-supplied amount. */\n value: number;\n /** ISO-4217 currency of `value`. */\n currency: string;\n /** Defaults to the canonical commerce pair; override for custom categories (e.g. 'trading' / 'trading.execute'). */\n purpose?: string;\n action?: string;\n}\n\nexport interface SettlementDecision {\n /** TRUE only on a clean grant. A step-up/approval outcome, any deny, a missing value, or a verify error all → false. */\n authorized: boolean;\n recommendation?: EnhancedVerificationResult['recommendation'];\n reason?: string;\n failures?: AccessFailure[];\n correlationId?: string;\n /** Present when the transaction is in the human-approval band — the owner can approve via the poll URL. */\n stepUpApproval?: StepUpApprovalInfo;\n}\n\n/**\n * Authorize a settlement of `value` for `agentId` against the agent's PDLSS\n * limits. FAIL-CLOSED: returns `authorized:false` on a missing/invalid value,\n * a verify-access error, a step-up/approval outcome (the value is in the\n * human-approval band and cannot complete autonomously), or any policy deny.\n * Settle ONLY when `authorized === true`.\n */\nexport async function authorizeSettlement(\n config: GatewayConfig,\n req: SettlementRequest\n): Promise<SettlementDecision> {\n // Fail closed on a missing/invalid authoritative value — never settle without one.\n if (typeof req.value !== 'number' || !Number.isFinite(req.value) || req.value <= 0) {\n return {\n authorized: false,\n recommendation: 'deny',\n reason:\n 'No valid transaction value supplied to authorizeSettlement; settlement refused (fail-closed). Pass the merchant-priced cart total as `value`.',\n failures: [\n {\n dimension: 'commerce.settlement.value_missing',\n message:\n 'A positive, authoritative transaction value is required to authorize settlement.',\n },\n ],\n };\n }\n\n let result: VerificationResult;\n try {\n result = await verify(config, {\n credentials: { astraId: req.agentId },\n purpose: req.purpose ?? 'shopping',\n action: req.action ?? 'shopping.purchase',\n transactionValue: req.value,\n currency: req.currency,\n });\n } catch (err) {\n // Fail closed on any verify error — do not settle on an unknown decision.\n return {\n authorized: false,\n recommendation: 'deny',\n reason: `Settlement verification failed (${\n err instanceof Error ? err.message : String(err)\n }); settlement refused (fail-closed).`,\n failures: [\n {\n dimension: 'commerce.settlement.verify_error',\n message:\n 'verify-access could not be reached or returned an error; settlement is refused.',\n },\n ],\n };\n }\n\n const recommendation = (result as EnhancedVerificationResult).recommendation;\n // Authorized ONLY on a clean grant: identity verified, policy allowed, NOT in\n // the human-approval band, and the recommendation (when present) is `grant`.\n const authorized =\n result.identityVerified === true &&\n result.policyAllowed === true &&\n !requiresHumanApproval(result) &&\n (recommendation === undefined || recommendation === 'grant');\n\n return {\n authorized,\n recommendation,\n reason: authorized\n ? undefined\n : (result.denialReasons?.[0] ??\n (requiresHumanApproval(result)\n ? 'Transaction is above the autonomous limit and requires human approval; settlement cannot be authorized automatically.'\n : \"Settlement not authorized by the agent's PDLSS limits.\")),\n failures: result.failures,\n correlationId: result.correlationId,\n stepUpApproval: requiresHumanApproval(result) ? result.stepUpApproval : undefined,\n };\n}\n","/**\n * AstraSync Universal Verification Gateway - Express Middleware\n *\n * Express.js middleware for verifying AI agents on API endpoints.\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { createMiddleware } from '@astrasyncai/verification-gateway/express';\n *\n * const app = express();\n *\n * app.use(createMiddleware({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * apiKey: process.env.ASTRASYNC_API_KEY,\n * counterpartyId: 'ASTRAE-...', // your registered endpoint id\n * }));\n * ```\n *\n * Per-route policy (which paths are gated, trust floors, PDLSS purposes) is\n * configured in the AstraSync dashboard, not in code — the middleware\n * fetches it automatically on init and refreshes periodically. There is no\n * `routes` option; a `routes` key in the config object is ignored (with a\n * warning) since v2.9.7.\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport type {\n ExpressMiddlewareOptions,\n AgentCredentials,\n VerificationResult,\n EnhancedVerificationResult,\n RouteAccessConfig,\n AstraSyncCredentials,\n VerificationRequest,\n} from '../types';\nimport { awaitStepUpApproval } from './stepup-poll';\nimport {\n verify,\n extractCredentials,\n recordDecision,\n reportCounterpartyPreCheckFailure,\n fetchRoutes,\n} from '../verify';\nimport { extractHttpCredentials } from '../transport/http';\nimport { MCP_VERIFIED_HOP_HEADER, parseVerifiedHop, isVerifiedHopValidFor } from '../verified-hop';\nimport { resolveHttpPdlss, type HttpPdlssResolution } from './http-pdlss';\nimport { requiresHumanApproval, annotateApprovalRequired } from './approval-gate';\nimport { performCounterpartyPreCheck } from '../pdlss-pre-check';\nimport { prefetchWellKnown, getWellKnownUrls } from '../well-known';\nimport { buildSdkObservedMetadata } from '../metadata-capture';\nimport { createAnonymousBeacon } from './anonymous-beacon';\n\n/**\n * Extend Express Request with verification result\n */\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n agentVerification?: VerificationResult;\n }\n }\n}\n\n/**\n * Default credential extractor\n */\nfunction defaultExtractCredentials(req: Request): AgentCredentials {\n return extractCredentials(\n req.headers as Record<string, string | string[] | undefined>,\n req.query as Record<string, string | undefined>\n );\n}\n\n/**\n * Extract extended AstraSync credentials (X-Astra-* headers) from Express request.\n * Returns null if no AstraSync headers are present.\n */\nexport function extractAstraSyncCredentials(req: Request): AstraSyncCredentials | null {\n return extractHttpCredentials(req.headers as Record<string, string | string[] | undefined>);\n}\n\n/** Read a possibly-array header value as a single string. */\nfunction headerValue(value: string | string[] | undefined): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value[0];\n return undefined;\n}\n\n/**\n * Resolve the canonical {purpose, action} pair for a request.\n * Replaces the gen-1 `defaultExtractPurpose` method-inference (`read_data`/\n * `write_data`) and the hardwired `action: req.method.toUpperCase()` — the\n * transport verb never travels as a PDLSS action. Full precedence chains\n * live in http-pdlss.ts.\n */\nfunction resolveRequestPdlss(\n req: Request,\n routeConfig: { purpose?: string; action?: string } | null,\n customExtractPurpose: ((req: Request) => string | undefined) | undefined,\n customExtractAction: ((req: Request) => string | undefined) | undefined\n): HttpPdlssResolution {\n return resolveHttpPdlss({\n method: req.method,\n astraPurpose: headerValue(req.headers['x-astra-purpose']),\n astraAction: headerValue(req.headers['x-astra-action']),\n legacyPurpose: headerValue(req.headers['x-purpose'] ?? req.headers['X-Purpose']),\n queryPurpose: typeof req.query.purpose === 'string' ? req.query.purpose : undefined,\n routePurpose: routeConfig?.purpose,\n routeAction: routeConfig?.action,\n hasCustomPurposeExtractor: !!customExtractPurpose,\n customPurpose: customExtractPurpose?.(req),\n hasCustomActionExtractor: !!customExtractAction,\n customAction: customExtractAction?.(req),\n });\n}\n\n/**\n * Match a route pattern against a path.\n *\n * Historically the SDK's\n * matchRoute was case-sensitive while Express's default `case sensitive\n * routing` is FALSE. A customer policy `/api/admin/*` did NOT match\n * `/api/ADMIN/users` → SDK returned `no-match` → request passed ungated →\n * Express routed it to the admin handler. The case-insensitive codepath\n * below closes the bypass.\n *\n * Ships in SHADOW MODE in SDK 2.4.13: by default the case-sensitive\n * regex is still authoritative; the case-insensitive variant is\n * computed in parallel and logged when results diverge. Follow-up\n * release flips the default to case-insensitive after 1-week\n * observation. Customers can flip early by setting\n * `caseInsensitiveRouteMatch: true` on the middleware options.\n */\nfunction matchRoute(\n pattern: string,\n path: string,\n opts?: { caseInsensitive?: boolean; correlationId?: string; logShadowDivergence?: boolean }\n): boolean {\n // Convert pattern to regex\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\//g, '\\\\/');\n\n const caseSensitiveRegex = new RegExp(`^${regexPattern}$`);\n const caseSensitiveResult = caseSensitiveRegex.test(path);\n\n if (!opts?.caseInsensitive && !opts?.logShadowDivergence) {\n return caseSensitiveResult;\n }\n\n const caseInsensitiveRegex = new RegExp(`^${regexPattern}$`, 'i');\n const caseInsensitiveResult = caseInsensitiveRegex.test(path);\n\n // Shadow logging: emit only when results diverge so operators can grep\n // their own logs for the bypass class without log volume spam.\n if (opts?.logShadowDivergence && caseSensitiveResult !== caseInsensitiveResult) {\n // eslint-disable-next-line no-console\n console.warn(\n `[SHADOW] matchRoute case-insensitive would change result: pattern=${pattern} path=${path} ` +\n `caseSensitive=${caseSensitiveResult} caseInsensitive=${caseInsensitiveResult} correlationId=${opts.correlationId ?? 'unknown'}`\n );\n }\n\n return opts?.caseInsensitive ? caseInsensitiveResult : caseSensitiveResult;\n}\n\n/**\n * Find the route configuration for a request\n */\nfunction findRouteConfig(\n routes: RouteAccessConfig[],\n path: string,\n method: string,\n opts?: { caseInsensitive?: boolean; correlationId?: string; logShadowDivergence?: boolean }\n): RouteAccessConfig | undefined {\n return routes.find((route) => {\n const methodMatches =\n route.method === '*' || route.method.toUpperCase() === method.toUpperCase();\n const pathMatches = matchRoute(route.pattern, path, opts);\n return methodMatches && pathMatches;\n });\n}\n\n/**\n * Default denied handler\n *\n * The response body carries the full `failures[]`\n * array and the `correlationId` so partners can render per-dimension UX\n * and tie a denial back to a server log line. Previously the merchant only\n * got the first denialReason — meaningful detail was thrown away before\n * the response left the SDK. Also stamps `X-Astra-Gateway-Mode: enforced`\n * so partners can tell a gate-evaluated denial apart from a gate-skipped\n * pass-through (the `unenforced` complement).\n */\nfunction dedupeFailures(result: VerificationResult): void {\n if (result.failures && result.failures.length > 1) {\n const seen = new Set<string>();\n result.failures = result.failures.filter((f) => {\n const key = `${f.dimension}|${f.message}|${(f as { guidance?: string }).guidance ?? ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n }\n if (result.denialReasons && result.denialReasons.length > 1) {\n result.denialReasons = [...new Set(result.denialReasons)];\n }\n}\n\nfunction defaultOnDenied(result: VerificationResult, _req: Request, res: Response): void {\n // 4.0.0 BREAKING: when this integration's OWN API key was rejected by the\n // backend (misconfigured marker), the inbound agent did nothing wrong and\n // re-authenticating won't help — a 401 both blames the agent and invites\n // re-auth loops. Answer 503: this site's verification layer is down, by\n // the operator's own configuration. No Retry-After — retrying is futile\n // until the operator rotates the key.\n if (result.misconfigured) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.status(503).json({\n success: false,\n error: {\n code: 'MERCHANT_VERIFICATION_MISCONFIGURED',\n message: result.denialReasons?.[0] || \"This site's AstraSync integration is misconfigured\",\n guidance: result.guidance,\n failures: result.failures,\n correlationId: result.correlationId,\n },\n });\n return;\n }\n\n // Round-18 G4: identity-verification failures → 401 (re-authenticate);\n // identity-verified-but-policy-denied → 403 (re-auth won't help; update\n // PDLSS scope or escalate to step-up). Maps to the two distinct recovery\n // actions that HTTP middleware acts on without parsing bodies. The\n // impossible state `!identityVerified && policyAllowed` falls into the\n // `!identityVerified` branch — identity is the more-fundamental missing\n // precondition.\n const statusCode = !result.identityVerified ? 401 : 403;\n\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n\n res.status(statusCode).json({\n success: false,\n error: {\n code: !result.identityVerified ? 'UNAUTHORIZED' : 'INSUFFICIENT_ACCESS',\n message: result.denialReasons?.[0] || 'Access denied',\n guidance: result.guidance,\n // Round-10: aggregated per-dimension detail + correlation handle.\n failures: result.failures,\n correlationId: result.correlationId,\n stepUpApproval: result.stepUpApproval,\n // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /\n // expired / consumed / timeout). Absent when the feature is off.\n ...(result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }),\n },\n });\n}\n\n/**\n * Refresh interval for the remote-fetched route policy. Default: every 5\n * minutes. Override via `routesRefreshMs` on the middleware options. Each\n * middleware instance keeps its own cache; multiple instances pointing at the\n * same endpoint will each fetch independently.\n */\nconst DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1000;\n\n/**\n * Create Express middleware for agent verification.\n *\n * v2.9.7 moved per-route policy authority out of merchant-side source code\n * into the AstraSync dashboard. `createMiddleware` no longer accepts a\n * `routes` array — it fetches the endpoint's stored policy via\n * `GET /endpoints/:counterpartyId/routes` on init and refreshes\n * periodically. Policy edits in the dashboard take effect on the next\n * refresh (or sooner if the operator manually restarts the SDK).\n *\n * `counterpartyId` is required: the SDK can't know which endpoint's policy\n * to fetch without it. Local-development workflows that don't have an\n * AstraSync endpoint registered can omit it — the middleware logs a\n * one-time warning and falls through (allows all) until a policy is\n * fetchable.\n */\nexport function createMiddleware(options: ExpressMiddlewareOptions): RequestHandler {\n // Guard against configs authored for pre-2.9.7 SDKs: a `routes` array in\n // merchant source is silently dead config (the type contract rejects it at\n // literal call sites, but variable-typed configs slip through) — and dead\n // route config means the author believes paths are gated that aren't.\n if ('routes' in options) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored — ' +\n 'configure route policy in your AstraSync dashboard.'\n );\n }\n const {\n extractCredentials: customExtractCredentials,\n extractPurpose: customExtractPurpose,\n extractAction: customExtractAction,\n skipPaths = [],\n onDenied = defaultOnDenied,\n recordDecisions,\n enableRuntimeChallenge = true,\n routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,\n failOnError = 'open',\n caseInsensitiveRouteMatch = false,\n anonymousBeacon = true,\n trustVerifiedHop = false,\n verifiedHopMaxAgeMs,\n ...config\n } = options;\n\n // v2.5.0: fire-and-forget pre-fetch of well-known URLs\n if (config.apiBaseUrl) {\n prefetchWellKnown(config.apiBaseUrl).catch(() => {});\n }\n\n // Dashboard-driven anonymous-traffic beacon for the pass-through paths\n // (no matching route / route gated at `none`). Fire-and-forget: never\n // awaited, never delays next(). See ./anonymous-beacon.ts.\n const emitAnonymousBeacon = anonymousBeacon\n ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? 'api' })\n : undefined;\n const beaconPassThrough = emitAnonymousBeacon\n ? (req: Request): void => {\n const xff = req.headers['x-forwarded-for'];\n const xffStr = Array.isArray(xff) ? xff.join(', ') : xff;\n emitAnonymousBeacon({\n requestPath: req.path,\n requestMethod: req.method,\n counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get('host')}`,\n sourceIp: req.ip ?? (xffStr ? xffStr.split(',')[0].trim() : undefined),\n rawHeaders: req.headers as Record<string, string | string[] | undefined>,\n });\n }\n : undefined;\n\n // Per-middleware-instance route cache. Populated on first fetch; refreshed\n // every `routesRefreshMs`. Until first successful fetch we hold an empty\n // array which means \"no per-route gating active\" — the middleware falls\n // through. Pre-fix the array came from merchant source, which both broke\n // the auth-boundary story (defect 24) and silently disagreed with the\n // dashboard.\n let cachedRoutes: RouteAccessConfig[] = [];\n let lastFetchAt = 0;\n let refreshing: Promise<void> | null = null;\n let warnedNoCounterparty = false;\n let warnedEmptyRoutes = false;\n\n async function refreshRoutes(): Promise<void> {\n if (!config.counterpartyId) {\n if (!warnedNoCounterparty) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway] No counterpartyId configured — falling through (allow all). ' +\n 'Per-route policy lives in the AstraSync dashboard now; register the endpoint and ' +\n 'set counterpartyId in your middleware config to enforce policy.'\n );\n warnedNoCounterparty = true;\n }\n return;\n }\n const fetched = await fetchRoutes(config, config.counterpartyId);\n if (fetched) {\n cachedRoutes = fetched;\n lastFetchAt = Date.now();\n // v2.3.8 (defect #25): if the fetch succeeded but returned an empty\n // policy, the endpoint is registered correctly but the operator hasn't\n // configured any routes yet — every request will fall through ungated.\n // Surface this loudly once so silent pass-through can't go unnoticed.\n if (cachedRoutes.length === 0 && !warnedEmptyRoutes) {\n // Audit F-PROBE-01: app.astrasync.ai doesn't resolve in DNS today;\n // dashboard actually lives at astrasync.ai/dashboard. Use that as\n // the fallback. If DevOps provisions app.astrasync.ai later, the\n // dashboardUrl config option lets merchants override.\n const dashboard = config.dashboardUrl ?? 'https://astrasync.ai/dashboard';\n // eslint-disable-next-line no-console\n console.warn(\n `[VerificationGateway] No route policy configured for ${config.counterpartyId}. ` +\n `Gateway is in pass-through mode for ALL traffic until you add at least one route. ` +\n `Configure at ${dashboard}/dashboard/endpoints/${config.counterpartyId}/routes`\n );\n warnedEmptyRoutes = true;\n }\n }\n }\n\n // Eager first fetch so the first request after init has policy loaded.\n // Errors are swallowed (handled by fetchRoutes returning null).\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n try {\n // Check if path should be skipped\n const shouldSkip = skipPaths.some((pattern) => matchRoute(pattern, req.path));\n if (shouldSkip) {\n return next();\n }\n\n // Wait for in-flight init fetch (only on the very first request) so we\n // don't admit traffic with no policy loaded.\n if (refreshing) {\n await refreshing.catch(() => {});\n }\n // Time-based refresh: kick off a background refresh if the cache is\n // stale. Doesn't block the current request — readers see whatever is\n // cached at this moment; the next request will see the refreshed copy.\n if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n }\n\n // Find route configuration\n // Audit F-A6-31 shadow-mode wiring: pass caseInsensitive flag (default\n // false in 2.4.13) + always log divergences so merchants can grep for\n // would-have-matched results during the 1-week observation window.\n const correlationId =\n (req.headers['x-request-id'] as string | undefined) ||\n (req.headers['x-correlation-id'] as string | undefined);\n const routeConfig = findRouteConfig(cachedRoutes, req.path, req.method, {\n caseInsensitive: caseInsensitiveRouteMatch,\n logShadowDivergence: true,\n correlationId,\n });\n\n // If no route config, skip verification (allow through)\n if (!routeConfig) {\n if (config.setPassThroughHeader) {\n // Round-10 (#49, O10): `unenforced` replaces the previous\n // `pass-through` label. The previous name conflated \"gateway\n // didn't evaluate policy\" with \"request succeeded end-to-end\" —\n // the downstream handler may still return any status. The new\n // semantic describes the GATE state only.\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader(\n 'X-Astra-Gateway-Reason',\n cachedRoutes.length === 0 ? 'no-policy' : 'no-match'\n );\n }\n // Anonymous-traffic beacon: this request never reaches verify-access,\n // so bot/agent-shaped callers would otherwise be invisible to the\n // dashboard. Fire-and-forget — does not delay next().\n beaconPassThrough?.(req);\n return next();\n }\n\n // v2.5.0: resolve well-known URLs (cached; prefetched at middleware creation)\n const wellKnownUrls = config.apiBaseUrl\n ? await getWellKnownUrls(config.apiBaseUrl).catch(() => undefined)\n : undefined;\n\n // Extract credentials (hoisted from below the route-none check so the\n // round-12 F9 evaluateAlwaysIfCredentialed flag can decide whether to\n // evaluate vs short-circuit).\n const credentials = customExtractCredentials\n ? customExtractCredentials(req)\n : defaultExtractCredentials(req);\n\n // Round-12 (F9): route-none short-circuit unless the caller wants\n // evaluation-without-enforcement. With evaluateAlwaysIfCredentialed\n // set to true AND credentials present, the middleware calls\n // verify-access for audit + req.agentVerification population, then\n // proceeds without gating. Default behaviour (flag off) preserves\n // pre-F9 short-circuit semantics.\n const shouldEnforce = !routeConfig.observe;\n if (routeConfig.observe && (!config.evaluateAlwaysIfCredentialed || !credentials.astraId)) {\n if (config.setPassThroughHeader) {\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader('X-Astra-Gateway-Reason', 'route-observe');\n }\n // Anonymous-traffic beacon (see the no-route-match branch above).\n beaconPassThrough?.(req);\n return next();\n }\n\n // Inner-hop dedupe: a trusted upstream AstraSync hop (edge gateway or\n // MCP outer hop) already verified this exact ASTRA-id moments ago —\n // accept the fresh marker and skip the duplicate verify-access call.\n // Mirrors the MCP adapter contract: no req.agentVerification on a\n // hop-skip. The marker must match the request's own X-Astra-Id.\n if (trustVerifiedHop && credentials.astraId) {\n const hopRaw = req.headers[MCP_VERIFIED_HOP_HEADER.toLowerCase()];\n const hopValue =\n typeof hopRaw === 'string' ? hopRaw : Array.isArray(hopRaw) ? hopRaw[0] : undefined;\n const marker = parseVerifiedHop(hopValue);\n if (\n isVerifiedHopValidFor(marker, credentials.astraId, {\n ...(verifiedHopMaxAgeMs !== undefined ? { maxAgeMs: verifiedHopMaxAgeMs } : {}),\n })\n ) {\n return next();\n }\n }\n\n // v2.3.0: anonymous traffic no longer short-circuits client-side.\n // The server applies the endpoint's `unverifiedAgentPolicy` (deny /\n // allow_partial / allow_full) and emits the verification event +\n // blockchain record per the canonical flow. SDK forwards verbatim.\n\n // Resolve the canonical {purpose, action} pair (Bug 14, §4.6): dashboard\n // route mapping → custom extractors → agent X-Astra-* headers →\n // method-table fallback. The transport verb never travels as the action.\n const pdlssPair = resolveRequestPdlss(\n req,\n routeConfig,\n customExtractPurpose,\n customExtractAction\n );\n const purpose = pdlssPair.purpose;\n if (config.debug) {\n // Same telemetry shape as the MCP adapter — adoption tracking and\n // support triage read the *_source fields to see which integration\n // path each partner uses (route mapping vs headers vs fallback).\n // eslint-disable-next-line no-console\n console.debug('[express-middleware] pdlss resolved', {\n purpose_source: pdlssPair.purposeSource,\n resolved_purpose: pdlssPair.purpose,\n action_source: pdlssPair.actionSource,\n resolved_action: pdlssPair.action,\n });\n }\n\n // Extract full AstraSync credentials (includes PDLSS from X-Astra-* headers)\n const astraCreds = extractAstraSyncCredentials(req);\n\n // Auto-detect counterparty URL from the request if not explicitly configured.\n // Since the SDK is installed at this endpoint, we always know the origin.\n const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get('host')}`;\n\n // Step 2: Counterparty-side PDLSS pre-check — compare agent's requested PDLSS\n // against counterparty-defined maximums on the route config.\n // Rejects immediately if outside limits, BEFORE calling verify-access.\n const preCheckFailures = performCounterpartyPreCheck(routeConfig, astraCreds, purpose);\n if (preCheckFailures.length > 0) {\n // Round-18 G4: counterparty pre-check failure — request rejected\n // before reaching verify-access. Neither identity nor policy was\n // remotely verified; both axes truthfully false.\n const result: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: preCheckFailures.map((f) => f.message),\n guidance: {\n message: 'Request exceeds counterparty-defined PDLSS limits.',\n registrationUrl: wellKnownUrls?.registrationUrl ?? '',\n documentationUrl: wellKnownUrls?.documentationUrl ?? '',\n },\n verifiedAt: new Date(),\n };\n\n req.agentVerification = result;\n\n // Fire-and-forget: notify AstraSync of the pre-check failure\n reportCounterpartyPreCheckFailure(config, {\n agentId: astraCreds?.agentId || credentials.astraId || 'unknown',\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'api',\n failures: preCheckFailures,\n requestPath: req.path,\n requestMethod: req.method,\n }).catch(() => {});\n\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // Step 3: Call AstraSync verify-access with runtime challenge enabled\n const shouldRecordDecisions = recordDecisions !== false;\n const forwardedFor = req.headers['x-forwarded-for'];\n const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(', ') : forwardedFor;\n // Audit F-A6-34: previously the LEFTMOST X-Forwarded-For entry was\n // taken as the original client IP. That value is attacker-controlled\n // whenever the customer's reverse proxy doesn't strip\n // client-supplied X-Forwarded-For — an attacker prepends\n // `X-Forwarded-For: 1.1.1.1` and we audit the spoofed IP. Now we\n // prefer req.ip (which Express resolves via configured `trust proxy`\n // hop count — the customer's responsibility to set correctly per\n // their actual hop chain). XFF still provides a fallback for\n // customers without `trust proxy` configured, but emits a one-time\n // warning when used so they know to fix.\n const originalClientIp =\n req.ip ?? (forwardedForStr ? forwardedForStr.split(',')[0].trim() : undefined);\n if (!req.ip && forwardedForStr) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway] req.ip unset — falling back to leftmost X-Forwarded-For. ' +\n 'Configure Express trust proxy correctly to avoid spoofable client IPs in audit logs.'\n );\n }\n const agentCardUrl =\n typeof req.headers['x-astrasync-agent-card'] === 'string'\n ? (req.headers['x-astrasync-agent-card'] as string)\n : undefined;\n\n // P1 (SDK 3.5.0): when extractTransactionValue is configured, include\n // the value in verify-access so PDLSS limit evaluation runs at\n // middleware time. Must return major units (dollars, not cents).\n let txValue: number | undefined;\n let txCurrency: string | undefined;\n if (config.extractTransactionValue) {\n try {\n const extracted = config.extractTransactionValue(req);\n if (extracted) {\n txValue = extracted.value;\n txCurrency = extracted.currency;\n }\n } catch (e) {\n if (config.debug) {\n // eslint-disable-next-line no-console\n console.warn('[VerificationGateway] extractTransactionValue threw:', e);\n }\n }\n }\n\n const verificationRequest: VerificationRequest = {\n credentials,\n purpose,\n action: pdlssPair.action,\n resource: req.path,\n createSession: shouldRecordDecisions,\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'api',\n enableRuntimeChallenge,\n durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,\n ...(txValue !== undefined && { transactionValue: txValue }),\n ...(txCurrency && { currency: txCurrency }),\n callerMetadata: {\n sourceIp: originalClientIp,\n userAgent: req.headers['user-agent'] as string | undefined,\n referer: req.headers.referer as string | undefined,\n host: req.headers.host as string | undefined,\n forwardedFor: forwardedForStr,\n agentCardUrl,\n // Workstream D — capture EVERY inbound header (SDK-only merchants\n // have no edge to do it upstream) plus the CDN-derived connection\n // block. Local string work, secrets stripped; out of the verify\n // cache key so it doesn't defeat caching.\n observedMetadata: buildSdkObservedMetadata(req.headers),\n },\n };\n let result = await verify(config, verificationRequest);\n\n // Attach result to request\n req.agentVerification = result;\n let sessionId = (result as EnhancedVerificationResult).sessionId;\n\n // 3.6.0 hold-and-poll (opt-in via stepUpMaxWaitMs): HOLD a step-up\n // outcome, poll the approval, and on 'approved' re-verify the same\n // request once (cache-bypassed — the retry must reach the backend to\n // redeem the single-use approval). Every non-approved outcome falls\n // through to the existing fail-closed branches below with\n // result.stepUpOutcome stamped for the deny body.\n if (\n config.stepUpMaxWaitMs !== undefined &&\n result.policyAllowed &&\n requiresHumanApproval(result) &&\n result.stepUpApproval?.pollUrl\n ) {\n const outcome = await awaitStepUpApproval(config, result.stepUpApproval);\n res.setHeader('X-Astra-Step-Up', outcome);\n if (outcome === 'approved') {\n result = await verify(config, verificationRequest, { bypassCache: true });\n req.agentVerification = result;\n sessionId = (result as EnhancedVerificationResult).sessionId;\n } else {\n result.stepUpOutcome = outcome;\n }\n }\n\n // Denied verifications short-circuit here: failing either identity OR\n // policy already means \"deny.\" We check that first.\n // 4.5.0 (probe F1 follow-through): the gate is the SERVER's decision —\n // `policyAllowed` is true exactly when the backend allowed the call\n // (every deny/guidance/api-error shape sets it false), so gating on it\n // alone preserves the endpoint policy verbatim. `identityVerified` no\n // longer gates here: anonymous callers granted by an\n // audit/allow_partial/allow_full endpoint policy are honestly\n // identity-unverified yet server-allowed, and re-deriving a deny from\n // identity would override the backend evaluator (the SDK-pre-check\n // asymmetry antipattern). Identity still picks 401-vs-403 in the deny\n // body builder.\n if (!result.policyAllowed) {\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // F2 direct-path fail-closed: an \"allowed-but-escalate\" outcome\n // (step-up / requires-approval, policyAllowed:true) cannot be completed\n // autonomously. The backend creates a step-up approval record and returns\n // it on `result.stepUpApproval`; deny here — symmetric with the bridge —\n // and surface the polling info in the deny response body.\n if (requiresHumanApproval(result)) {\n annotateApprovalRequired(result);\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // Round-12 (F9): evaluation-without-enforcement. When the route is\n // 'none' but we ran verify-access for audit, skip the gates and call\n // next() — the result is on req.agentVerification for the handler\n // to render tier-aware responses (e.g. anonymous vs verified\n // catalog view on the same path).\n if (!shouldEnforce) {\n if (config.setPassThroughHeader) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.setHeader('X-Astra-Gateway-Reason', 'evaluated-not-enforced');\n }\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n return next();\n }\n\n // The access decision is the server's (identityVerified / policyAllowed,\n // above) — resting on a verified ID + runtime challenge + PDLSS match +\n // trust score. The only client-side refinement is the per-route trust\n // floor below; there is no access-level band (removed in SDK 5.0.0).\n\n // Per-route trust tightening (only refinement that still gates).\n if (routeConfig.minTrustScore && result.agent) {\n if (result.agent.trustScore < routeConfig.minTrustScore) {\n // 3.2.0: qualitative — never embed the score or the threshold in an\n // agent-visible message (trust is a system-internal signal; exposing\n // the number is a gaming vector — post-3.1.0 feedback #2).\n const trustFailure = {\n dimension: 'endpoint.trust',\n message: 'Trust below the route requirement for this endpoint.',\n guidance:\n \"Trust is below this route's floor. Trust is not overridable — the agent either meets the endpoint's trust policy or it doesn't. Raise the agent's trust via real signals (KYD, blockchain registration, agent-card), or have the operator lower the route's minTrustScore.\",\n };\n result.failures = [...(result.failures ?? []), trustFailure];\n result.denialReasons = [trustFailure.message];\n if (!result.guidance && wellKnownUrls) {\n result.guidance = {\n message: trustFailure.message,\n registrationUrl: wellKnownUrls.registrationUrl,\n documentationUrl: wellKnownUrls.documentationUrl,\n };\n }\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', trustFailure.message).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n }\n\n // All checks passed — record grant decision\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n // v2.3.8 (defect #26): if the endpoint's `unverifiedAgentPolicy` is\n // `'audit'` (allow + soft-launch warning), the server returns the\n // header to relay. Lift it onto the merchant's response BEFORE\n // calling next() so downstream handlers and the eventual response\n // back to the agent both carry it.\n const enhancedResult = result as EnhancedVerificationResult;\n if (enhancedResult.warningHeader) {\n res.setHeader(enhancedResult.warningHeader.name, enhancedResult.warningHeader.value);\n }\n next();\n } catch (error) {\n // Audit F-A1-06: shadow-mode logging for fail-closed default migration.\n // Always log `[SHADOW] would-have-denied` so merchants can grep their\n // own application logs for would-have-been-denied impact during the\n // observation window. Actual deny/admit behavior controlled by\n // failOnError option (default 'open' for backward compatibility).\n const errorClass = error instanceof Error ? error.constructor.name : typeof error;\n const correlationId =\n (req.headers['x-request-id'] as string | undefined) ||\n (req.headers['x-correlation-id'] as string | undefined) ||\n `gen-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n // eslint-disable-next-line no-console\n console.error('[VerificationGateway] Middleware error:', error);\n // eslint-disable-next-line no-console\n console.warn(\n `[SHADOW] would-have-denied: errorClass=${errorClass} route=${req.method}:${req.path} merchantId=${config.counterpartyId ?? 'unknown'} correlationId=${correlationId}`\n );\n\n if (failOnError === 'closed') {\n const result: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: [`Verification middleware internal error: ${errorClass}`],\n failures: [\n {\n dimension: 'middleware.internal_error',\n message: `Middleware threw ${errorClass} — failing closed`,\n },\n ],\n verifiedAt: new Date(),\n correlationId,\n };\n const catchUrls = config.apiBaseUrl\n ? await getWellKnownUrls(config.apiBaseUrl).catch(() => undefined)\n : undefined;\n if (catchUrls) {\n result.guidance = {\n message: `Middleware threw ${errorClass} — failing closed`,\n registrationUrl: catchUrls.registrationUrl,\n documentationUrl: catchUrls.documentationUrl,\n };\n }\n dedupeFailures(result);\n return onDenied(result, req, res);\n }\n\n next();\n }\n };\n}\n\n// `requireAccess` and `verifyOnly` were removed in v2.9.7. Both injected a\n// local `routes` array into the merchant's source code, which is the exact\n// dual-config attack vector defect 24 closed. Per-route policy now lives in\n// the AstraSync dashboard (gated by team.role admin auth + audit + alerts).\n// To tighten a route, set its `minTrustScore` (+ purpose/jurisdiction/value\n// gates) in the dashboard. For \"verify but don't block,\" set the route to\n// `observe` (or run the endpoint in an audit `unverifiedAgentPolicy`).\n","/**\n * HTTP Transport Adapter\n *\n * Maps AstraSync credentials to/from HTTP headers (X-Astra-* convention).\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\nconst HEADER_PREFIX = 'X-Astra-';\n\n/**\n * Inject AstraSync credentials into HTTP headers.\n */\nexport function setHttpHeaders(\n headers: Record<string, string>,\n credentials: AstraSyncCredentials\n): Record<string, string> {\n const result = { ...headers };\n\n result[`${HEADER_PREFIX}ID`] = credentials.agentId;\n\n if (credentials.verifyUrl) {\n result[`${HEADER_PREFIX}Verify`] = credentials.verifyUrl;\n }\n\n if (credentials.challengeUrl) {\n result[`${HEADER_PREFIX}Challenge`] = credentials.challengeUrl;\n }\n\n if (credentials.pdlss?.purpose) {\n // 3.1.0 (Bug 14, §4.6): the action ALSO travels on its own dedicated\n // header so new-SDK receivers get the clean two-axis pair. The colon\n // form below is kept as the back-compat channel — pre-3.1.0 receivers\n // split on ':' and take the category prefix.\n const purposeValue = credentials.pdlss.purpose.action\n ? `${credentials.pdlss.purpose.category}:${credentials.pdlss.purpose.action}`\n : credentials.pdlss.purpose.category;\n result[`${HEADER_PREFIX}Purpose`] = purposeValue;\n if (credentials.pdlss.purpose.action) {\n result[`${HEADER_PREFIX}Action`] = credentials.pdlss.purpose.action;\n }\n }\n\n if (credentials.pdlss?.duration?.maxSessionDuration) {\n result[`${HEADER_PREFIX}Duration`] = String(credentials.pdlss.duration.maxSessionDuration);\n }\n\n if (credentials.pdlss?.scope?.jurisdiction) {\n result[`${HEADER_PREFIX}Scope`] = credentials.pdlss.scope.jurisdiction;\n }\n\n return result;\n}\n\n/**\n * Extract AstraSync credentials from HTTP headers.\n */\nexport function extractHttpCredentials(\n headers: Record<string, string | string[] | undefined>\n): AstraSyncCredentials | null {\n const getValue = (key: string): string | undefined => {\n const v = headers[key] ?? headers[key.toLowerCase()];\n return Array.isArray(v) ? v[0] : v;\n };\n\n const agentId = getValue(`${HEADER_PREFIX}ID`) ?? getValue('x-astra-id');\n if (!agentId) return null;\n\n const credentials: AstraSyncCredentials = { agentId };\n\n const verifyUrl = getValue(`${HEADER_PREFIX}Verify`) ?? getValue('x-astra-verify');\n if (verifyUrl) credentials.verifyUrl = verifyUrl;\n\n const challengeUrl = getValue(`${HEADER_PREFIX}Challenge`) ?? getValue('x-astra-challenge');\n if (challengeUrl) credentials.challengeUrl = challengeUrl;\n\n const purpose = getValue(`${HEADER_PREFIX}Purpose`) ?? getValue('x-astra-purpose');\n if (purpose) {\n const [category, action] = purpose.split(':');\n credentials.pdlss = {\n ...credentials.pdlss,\n purpose: { category, action },\n };\n }\n\n // 3.1.0 (Bug 14, §4.6): dedicated action header — overrides any colon-form\n // remainder parsed above (the dedicated header is the canonical channel).\n const astraAction = getValue(`${HEADER_PREFIX}Action`) ?? getValue('x-astra-action');\n if (astraAction) {\n credentials.pdlss = {\n ...credentials.pdlss,\n purpose: { category: credentials.pdlss?.purpose?.category ?? '', action: astraAction },\n };\n }\n\n const duration = getValue(`${HEADER_PREFIX}Duration`) ?? getValue('x-astra-duration');\n if (duration) {\n credentials.pdlss = {\n ...credentials.pdlss,\n duration: { maxSessionDuration: parseInt(duration, 10) },\n };\n }\n\n const scope = getValue(`${HEADER_PREFIX}Scope`) ?? getValue('x-astra-scope');\n if (scope) {\n credentials.pdlss = {\n ...credentials.pdlss,\n scope: { jurisdiction: scope },\n };\n }\n\n return credentials;\n}\n","/**\n * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.\n *\n * Header carrying upstream verify-access proof so an inner-hop endpoint can\n * dedupe (skip verify-access when the same ASTRA-id was already verified a\n * few ms earlier). Emitted by the MCP adapter toward tool fetches and by the\n * edge gateway toward the origin at authenticate/authorize depth. Value\n * format:\n *\n * {astraId};{sessionId};{checkedAt-ms}\n *\n * Receivers MUST validate that `checkedAt` is recent (≤ 60s window\n * recommended) and that `astraId` matches the agent identity claimed on the\n * inner hop. The header alone is NOT proof-of-identity — it's an UNSIGNED\n * dedupe advisory: trust it (`trustVerifiedHop`) only where every network\n * path to the inner hop crosses a stripping gateway or an equivalent trusted\n * boundary, exactly like the unsigned X-AstraSync-* attestation headers.\n * Pair with the existing X-Astra-Id auth.\n */\n\nexport const MCP_VERIFIED_HOP_HEADER = 'X-Astra-Verified-Hop';\n\n/** Default acceptable age (ms) for an X-Astra-Verified-Hop header. */\nexport const MCP_VERIFIED_HOP_MAX_AGE_MS = 60_000;\n\nexport interface VerifiedHopMarker {\n astraId: string;\n sessionId?: string;\n checkedAt: number; // epoch ms\n}\n\nexport function serializeVerifiedHop(marker: VerifiedHopMarker): string {\n return `${marker.astraId};${marker.sessionId ?? ''};${marker.checkedAt}`;\n}\n\nexport function parseVerifiedHop(value: string | undefined | null): VerifiedHopMarker | null {\n if (!value) return null;\n const parts = value.split(';');\n if (parts.length !== 3) return null;\n const [astraId, sessionId, checkedAtRaw] = parts;\n if (!astraId) return null;\n const checkedAt = Number(checkedAtRaw);\n if (!Number.isFinite(checkedAt) || checkedAt <= 0) return null;\n return {\n astraId,\n ...(sessionId ? { sessionId } : {}),\n checkedAt,\n };\n}\n\n/**\n * Returns true when `marker.astraId` matches the inner-hop's claimed\n * ASTRA-id AND the marker is recent enough. Inner-hop middleware uses this\n * to skip a duplicate verify-access call.\n */\nexport function isVerifiedHopValidFor(\n marker: VerifiedHopMarker | null,\n expectedAstraId: string,\n opts: { maxAgeMs?: number; now?: number } = {}\n): boolean {\n if (!marker) return false;\n if (marker.astraId !== expectedAstraId) return false;\n const maxAge = opts.maxAgeMs ?? MCP_VERIFIED_HOP_MAX_AGE_MS;\n const now = opts.now ?? Date.now();\n return now - marker.checkedAt <= maxAge && now >= marker.checkedAt;\n}\n","/**\n * Shared purpose/action resolver for the HTTP adapters (express + nextjs) —\n * the vocabulary-unification layer.\n *\n * The PDLSS two-axis contract: `purpose` = bare category noun (`shopping`,\n * `data`, custom nouns like `trading`); `action` = dotted verb\n * (`shopping.search`) or an enumerated transport token. Transport verbs\n * (GET/POST/...) NEVER travel as PDLSS actions — they map through the pinned\n * method table below.\n *\n * SELF-CONTAINED on purpose: this published package cannot depend on the\n * private @astrasyncai/pdlss-vocab workspace package, so the constants are\n * duplicated here and pinned strictly equal by a monorepo CI test\n * (vocab-equality.test.ts). Change them in BOTH places or that test fails.\n */\n\n/** Pinned method→action derivation table. */\nexport const HTTP_METHOD_ACTION_TABLE: Readonly<Record<string, string>> = {\n GET: 'data.read',\n HEAD: 'data.read',\n OPTIONS: 'data.read',\n POST: 'data.write',\n PUT: 'data.write',\n PATCH: 'data.write',\n DELETE: 'data.delete',\n};\n\n/** Unknown methods are treated as mutating until proven otherwise. */\nexport const DEFAULT_HTTP_ACTION = 'data.write';\n\n/** Generic category emitted when nothing supplies a domain purpose. */\nexport const DEFAULT_HTTP_PURPOSE = 'data';\n\nexport function actionForHttpMethod(method: string): string {\n return HTTP_METHOD_ACTION_TABLE[method.toUpperCase()] ?? DEFAULT_HTTP_ACTION;\n}\n\nexport type HttpPurposeSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'legacy_header'\n | 'query'\n | 'action_derived'\n | 'transport_default';\n\nexport type HttpActionSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'purpose_header_derived'\n | 'method_table';\n\nexport interface HttpPdlssInput {\n method: string;\n /** `X-Astra-Purpose` header value (agent's declaration). */\n astraPurpose?: string;\n /** `X-Astra-Action` header value (agent's declaration, symmetric with MCP). */\n astraAction?: string;\n /** Legacy `x-purpose` header — deprecated, removal scheduled for 4.0.0. */\n legacyPurpose?: string;\n /** Legacy `?purpose` query param (express only) — deprecated, removal 4.0.0. */\n queryPurpose?: string;\n /** Dashboard route config send-mapping (RouteAccessConfig.purpose/.action). */\n routePurpose?: string;\n routeAction?: string;\n /** Results of the merchant's extractPurpose/extractAction options. */\n customPurpose?: string;\n hasCustomPurposeExtractor?: boolean;\n customAction?: string;\n hasCustomActionExtractor?: boolean;\n}\n\nexport interface HttpPdlssResolution {\n purpose: string;\n action: string;\n purposeSource: HttpPurposeSource;\n actionSource: HttpActionSource;\n}\n\n/**\n * Normalize an `X-Astra-Purpose` header value.\n * - colon form `\"category:action\"` (legacy wire shape): take the prefix; the\n * remainder is free-text and exists in no vocabulary — discard it and let\n * the method table supply the action (matches pre-3.1.0 discard behavior).\n * - dotted form `\"shopping.purchase\"` (the shape older docs taught): prefix\n * becomes the purpose, the WHOLE token becomes an action candidate.\n * - bare token: purpose verbatim.\n */\nexport function normalizePurposeHeader(value: string): {\n purpose: string;\n actionCandidate?: string;\n} {\n const colon = value.indexOf(':');\n if (colon >= 0) {\n return { purpose: value.slice(0, colon) };\n }\n const dot = value.indexOf('.');\n if (dot > 0 && dot < value.length - 1) {\n return { purpose: value.slice(0, dot), actionCandidate: value };\n }\n return { purpose: value };\n}\n\n/**\n * Resolve the {purpose, action} pair for one HTTP request.\n *\n * Precedence (both axes):\n * action: route mapping → extractAction option → X-Astra-Action header →\n * candidate from a dotted X-Astra-Purpose → pinned method table\n * purpose: route mapping → extractPurpose option → X-Astra-Purpose →\n * legacy x-purpose / ?purpose → category prefix of the resolved\n * action → 'data'\n *\n * A configured custom extractor masks the header/legacy/query steps of its\n * axis (it replaces the default chain, as extractPurpose always has); when it\n * returns undefined the axis falls through to the table/prefix fallback.\n * The route mapping is merchant policy fetched from the dashboard — it\n * outranks agent-supplied headers the way MCP toolGates do.\n */\nexport function resolveHttpPdlss(input: HttpPdlssInput): HttpPdlssResolution {\n const fromHeader = input.astraPurpose ? normalizePurposeHeader(input.astraPurpose) : undefined;\n\n // ── Action axis ──\n let action: string;\n let actionSource: HttpActionSource;\n if (input.routeAction) {\n action = input.routeAction;\n actionSource = 'route_config';\n } else if (input.hasCustomActionExtractor && input.customAction) {\n action = input.customAction;\n actionSource = 'custom_extractor';\n } else if (!input.hasCustomActionExtractor && input.astraAction) {\n action = input.astraAction;\n actionSource = 'header';\n } else if (!input.hasCustomActionExtractor && fromHeader?.actionCandidate) {\n action = fromHeader.actionCandidate;\n actionSource = 'purpose_header_derived';\n } else {\n action = actionForHttpMethod(input.method);\n actionSource = 'method_table';\n }\n\n // ── Purpose axis ──\n let purpose: string | undefined;\n let purposeSource: HttpPurposeSource | undefined;\n if (input.routePurpose) {\n purpose = input.routePurpose;\n purposeSource = 'route_config';\n } else if (input.hasCustomPurposeExtractor) {\n if (input.customPurpose) {\n purpose = input.customPurpose;\n purposeSource = 'custom_extractor';\n }\n } else if (fromHeader) {\n purpose = fromHeader.purpose;\n purposeSource = 'header';\n } else if (input.legacyPurpose) {\n purpose = input.legacyPurpose;\n purposeSource = 'legacy_header';\n } else if (input.queryPurpose) {\n purpose = input.queryPurpose;\n purposeSource = 'query';\n }\n\n if (!purpose) {\n // Keep the pair coherent: an agent that sent only X-Astra-Action (or a\n // route that mapped only the action) gets that action's own category.\n const dot = action.indexOf('.');\n if (dot > 0) {\n purpose = action.slice(0, dot);\n purposeSource = 'action_derived';\n } else {\n purpose = DEFAULT_HTTP_PURPOSE;\n purposeSource = 'transport_default';\n }\n }\n\n return { purpose, action, purposeSource: purposeSource!, actionSource };\n}\n","/**\n * Counterparty-side PDLSS pre-check.\n *\n * Compares the agent's requested PDLSS dimensions (from X-Astra-* headers)\n * against the counterparty-defined maximums on the route config.\n * Returns an array of failures — empty means all checks passed.\n *\n * This runs BEFORE calling verify-access on AstraSync. If it fails,\n * the request is rejected immediately without calling the platform.\n */\n\nimport type { RouteAccessConfig, AstraSyncCredentials, CounterpartyPreCheckFailure } from './types';\n\nexport function performCounterpartyPreCheck(\n routeConfig: RouteAccessConfig,\n astraCreds: AstraSyncCredentials | null,\n purpose: string | undefined\n): CounterpartyPreCheckFailure[] {\n const failures: CounterpartyPreCheckFailure[] = [];\n\n // Check purpose against allowedPurposes whitelist. Route allow-lists are an\n // OPTIONAL per-route refinement — undefined/empty = \"skip, let the backend\n // evaluator be the authoritative gate\". The backend's PDLSS evaluator\n // enforces the agent's own declared policy (round-18.5 F3 fail-closed there\n // is correct: the agent declared its allowlist or didn't). Treating an\n // undefined route allow-list as fail-closed breaks every partner that hasn't\n // enumerated allowedPurposes (which is most of them — round-18.5 originally\n // shipped this and was reverted in 2.4.11 after partner-wide auth break).\n if (routeConfig.allowedPurposes && routeConfig.allowedPurposes.length > 0 && purpose) {\n if (!routeConfig.allowedPurposes.includes(purpose)) {\n failures.push({\n field: 'purpose',\n requested: purpose,\n limit: routeConfig.allowedPurposes,\n message: `Purpose \"${purpose}\" is not in the allowed list: [${routeConfig.allowedPurposes.join(', ')}]`,\n });\n }\n }\n\n // Check purpose against requiredPurposes (legacy field — agent must declare one of these)\n if (routeConfig.requiredPurposes && routeConfig.requiredPurposes.length > 0 && purpose) {\n if (!routeConfig.requiredPurposes.includes(purpose)) {\n failures.push({\n field: 'purpose',\n requested: purpose,\n limit: routeConfig.requiredPurposes,\n message: `Purpose \"${purpose}\" is not in the required list: [${routeConfig.requiredPurposes.join(', ')}]`,\n });\n }\n }\n\n // Check duration against maxDuration — range-check (unchanged; undefined =\n // no upper bound is conventional for opt-in range fields, not a request-\n // driven allow-list).\n if (routeConfig.maxDuration && astraCreds?.pdlss?.duration?.maxSessionDuration) {\n const requested = astraCreds.pdlss.duration.maxSessionDuration;\n if (requested > routeConfig.maxDuration) {\n failures.push({\n field: 'duration',\n requested,\n limit: routeConfig.maxDuration,\n message: `Requested duration ${requested}s exceeds maximum ${routeConfig.maxDuration}s`,\n });\n }\n }\n\n // Check jurisdiction against allowedJurisdictions. Same reasoning as\n // allowedPurposes above — route allow-lists are an optional per-route\n // refinement; undefined/empty = skip and defer to the backend evaluator.\n if (\n routeConfig.allowedJurisdictions &&\n routeConfig.allowedJurisdictions.length > 0 &&\n astraCreds?.pdlss?.scope?.jurisdiction\n ) {\n const requested = astraCreds.pdlss.scope.jurisdiction;\n if (!routeConfig.allowedJurisdictions.includes(requested)) {\n failures.push({\n field: 'jurisdiction',\n requested,\n limit: routeConfig.allowedJurisdictions,\n message: `Jurisdiction \"${requested}\" is not in the allowed list: [${routeConfig.allowedJurisdictions.join(', ')}]`,\n });\n }\n }\n\n return failures;\n}\n","/**\n * Maximal metadata capture — the shared, edge-safe sanitiser.\n *\n * AstraSync's thesis is total metadata capture: every header and connection\n * signal an inbound agent presents is a signal we want to keep. This module is\n * the ONE place that decides what is safe to store verbatim, what is a secret\n * to drop, and what credential headers reduce to a safe *format prefix* (a\n * platform signal, never the secret itself).\n *\n * It runs in three places that must agree byte-for-byte:\n * - the edge adapter (`@astrasyncai/adapter-lambda`) — the richest capture\n * point (full CloudFront header arrays),\n * - the SDK adapters (express / nextjs) — for SDK-only merchants with no edge,\n * - (indirectly) the backend, which stores whatever the above forward.\n *\n * Pure — no Node built-ins, no I/O — so it is safe in Lambda@Edge, the browser\n * build, and Deno. Capture is cheap: at the edge and SDK it is local string\n * work, and the backend stores it on a fire-and-forget event insert, so it adds\n * ZERO verify-access decision latency. Detection (which few signals imply which\n * vendor) is a separate, curated concern — see `platform-signatures.ts`.\n */\n\n/**\n * Version of the capture semantics (what is kept, dropped, reduced, or\n * derived — and under which key names).\n *\n * Capture semantics are FROZEN within a package major version: a given\n * `schemaVersion` always means the same field vocabulary and the same\n * keep/drop/reduce rules. The number bumps only on a SEMANTIC change to\n * capture (a renamed key, a changed reduction rule) — never for additive\n * signals, and never merely because the package version moved. To tell\n * builds apart, use the `sdkVersion` already present on the verify body;\n * `schemaVersion` answers the different question \"how do I interpret this\n * stored metadata?\".\n */\nexport const CAPTURE_SCHEMA_VERSION = 1;\n\n/**\n * The captured, sanitised view of an inbound agent's request metadata. Attached\n * to verify-access / beacon payloads as `callerMetadata.observedMetadata`.\n */\nexport interface ObservedMetadata {\n /** Header name → value, secrets removed, verbatim otherwise. */\n headers: Record<string, string>;\n /**\n * Safe key-format prefix of a credential header (e.g. `sk-ant-api03`,\n * `sk-proj`, `AIza`) — a platform signal, NEVER the secret. Absent if no\n * credential header was present or none matched a known format.\n */\n apiKeyFormat?: string;\n /**\n * The subset of `headers` that are known platform-signal headers\n * (`openai-organization`, `x-goog-user-project`, `anthropic-version`, …),\n * pulled out for convenient detection + display. Values are the same\n * sanitised strings as in `headers`.\n */\n platformHeaders?: Record<string, string>;\n /**\n * Connection-layer signals (IP, ASN, country, TLS version, HTTP version,\n * device class, TLS fingerprint). Edge adapters populate this from the\n * platform's native connection surface — the authoritative source. SDK\n * adapters populate it as a fallback via {@link deriveConnectionFromHeaders}\n * when a CDN in front of the merchant injected the equivalent headers;\n * absent when neither source had anything.\n */\n connection?: Record<string, string>;\n /**\n * Number of cookie pairs the caller sent. The `cookie` header VALUE is a\n * secret and is always dropped; the COUNT is a client-shape signal\n * (browsers carry cookies, most automation carries none) that would\n * otherwise be unobservable downstream. Absent when no cookie header\n * arrived.\n */\n cookieCount?: number;\n /**\n * Query-string parameter NAMES (deduped, lowercased) — values are NEVER\n * captured (they routinely carry OAuth codes, tokens, and PII, and no\n * deny-list is complete). Names alone fingerprint client shape. Populated\n * by the edge path, which sees the raw query string.\n */\n queryKeys?: string[];\n /**\n * Version of the capture semantics this object was produced under — see\n * {@link CAPTURE_SCHEMA_VERSION}. Optional for backward compatibility with\n * metadata captured before the field existed.\n */\n schemaVersion?: number;\n}\n\n/**\n * Result of sanitising a raw header map. `headers` is always present (possibly\n * empty); `apiKeyFormat` / `platformHeaders` only when a signal was found.\n */\nexport interface SanitizeHeadersResult {\n headers: Record<string, string>;\n apiKeyFormat?: string;\n platformHeaders?: Record<string, string>;\n /** Cookie-pair count; the cookie value itself is always dropped. */\n cookieCount?: number;\n}\n\n/**\n * Header names dropped entirely — genuine secrets or our own credentials that\n * describe the request's transport, not the agent. Matched case-insensitively\n * on the exact header name.\n */\nconst SECRET_HEADER_NAMES = new Set([\n 'cookie',\n 'set-cookie',\n 'x-csrf-token',\n 'proxy-authorization',\n 'x-astrasync-signature',\n 'x-astrasync-secret',\n 'x-hub-signature',\n 'x-hub-signature-256',\n // Short-lived verify dedupe token — must never persist in stored metadata.\n 'x-astra-verified-hop',\n]);\n\n/**\n * Header-name prefixes dropped entirely — our own credential / signing surface\n * (`x-astrasync-*`, `kya-*`) must never round-trip into stored metadata.\n */\nconst SECRET_HEADER_PREFIXES = ['x-astrasync-', 'kya-', 'kya_'];\n\n/**\n * Credential headers whose VALUE is a secret but whose FORMAT is a signal. We\n * keep the leading format prefix (up to the random tail) and drop the rest.\n */\nconst CREDENTIAL_HEADER_NAMES = new Set([\n 'authorization',\n 'x-api-key',\n 'x-goog-api-key',\n 'api-key',\n]);\n\n/**\n * Header names that carry a raw signature value (drop the value; the presence\n * is not worth a bloat risk). Matched as a suffix so `x-*-signature` variants\n * are covered without an exhaustive list.\n */\nfunction isSignatureHeader(name: string): boolean {\n return name === 'signature' || name.endsWith('-signature') || name.endsWith('-signature-256');\n}\n\n/**\n * Known platform-signal headers — pulled into `platformHeaders` for convenient\n * detection + display. Exact names plus a few prefixes (`x-goog-`,\n * `x-stainless-` — the OpenAI/Anthropic SDK client fingerprint headers).\n */\nconst PLATFORM_HEADER_NAMES = new Set([\n 'openai-organization',\n 'openai-project',\n 'openai-version',\n 'openai-processing-ms',\n 'anthropic-version',\n 'anthropic-beta',\n 'x-goog-user-project',\n 'x-goog-api-client',\n 'user-agent',\n 'x-agent-card-url',\n 'x-agent-provider',\n]);\n// `sec-ch-*` client hints are platform signals: Chromium forks (agentic\n// browsers included) often carry their real brand in `sec-ch-ua` even when\n// the UA string mimics stock Chrome.\nconst PLATFORM_HEADER_PREFIXES = [\n 'x-goog-',\n 'x-stainless-',\n 'x-anthropic-',\n 'x-openai-',\n 'sec-ch-',\n];\n\n/**\n * Known API-key format prefixes, longest-first so `sk-ant-api03` wins over\n * `sk-ant` and `sk-`. Each is the SAFE, non-secret leading token of a\n * credential; the random tail is never captured.\n */\nconst KEY_FORMAT_PREFIXES = [\n 'sk-ant-api03',\n 'sk-ant-api',\n 'sk-ant',\n 'sk-proj',\n 'sk-svcacct',\n 'sk-or-v1',\n 'sk-or',\n 'sk-lf',\n 'sk-',\n 'gsk_',\n 'aiza',\n 'ya29',\n 'ghp_',\n 'gho_',\n 'github_pat_',\n 'xai-',\n 'pplx-',\n 'r8_',\n 'hf_',\n 'astra-',\n 'astrae-',\n];\n\n/** Size caps — the only guard against jsonb bloat from a hostile POST. */\nexport const MAX_HEADERS = 64;\nexport const MAX_HEADER_VALUE_BYTES = 1024;\nexport const MAX_TOTAL_BYTES = 16 * 1024;\n\nfunction byteLength(s: string): number {\n // Edge-safe (no Buffer): count UTF-8 bytes without allocating a Buffer.\n let bytes = 0;\n for (let i = 0; i < s.length; i++) {\n const code = s.charCodeAt(i);\n if (code < 0x80) bytes += 1;\n else if (code < 0x800) bytes += 2;\n else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4;\n i++; // surrogate pair\n } else bytes += 3;\n }\n return bytes;\n}\n\n/**\n * Extract the safe key-format prefix from a credential header value. Strips a\n * leading `Bearer ` / `Basic ` scheme, then returns the longest known prefix\n * that the (lowercased) value starts with. Returns undefined for opaque values\n * (e.g. a bare UUID token) so we never guess a format we don't recognise.\n */\nexport function extractApiKeyFormat(rawValue: string): string | undefined {\n if (!rawValue) return undefined;\n let value = rawValue.trim();\n const spaceIdx = value.indexOf(' ');\n if (spaceIdx > 0) {\n const scheme = value.slice(0, spaceIdx).toLowerCase();\n if (scheme === 'bearer' || scheme === 'basic' || scheme === 'token') {\n value = value.slice(spaceIdx + 1).trim();\n }\n }\n const lower = value.toLowerCase();\n for (const prefix of KEY_FORMAT_PREFIXES) {\n if (lower.startsWith(prefix)) {\n // Return the prefix as-declared in the list (canonical casing).\n return prefix;\n }\n }\n return undefined;\n}\n\nfunction isSecretHeader(name: string): boolean {\n if (SECRET_HEADER_NAMES.has(name)) return true;\n if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;\n if (isSignatureHeader(name)) return true;\n return false;\n}\n\nfunction isPlatformHeader(name: string): boolean {\n if (PLATFORM_HEADER_NAMES.has(name)) return true;\n return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));\n}\n\n/**\n * Sanitise a raw header map for storage. Deny-lists genuine secrets, reduces\n * credential headers to a safe format prefix, keeps everything else verbatim,\n * and enforces the size caps that bound jsonb growth.\n *\n * Accepts any string→(string|string[]|undefined) map (Node's `req.headers`,\n * CloudFront's flattened headers, a plain object). Multi-value headers are\n * joined with `, ` per RFC 7230.\n */\nexport function sanitizeHeaders(\n raw: Record<string, string | string[] | undefined> | undefined | null\n): SanitizeHeadersResult {\n const headers: Record<string, string> = {};\n const platformHeaders: Record<string, string> = {};\n let apiKeyFormat: string | undefined;\n let cookieCount: number | undefined;\n let totalBytes = 0;\n let count = 0;\n\n if (!raw) return { headers };\n\n for (const rawName of Object.keys(raw)) {\n if (count >= MAX_HEADERS) break;\n const name = rawName.toLowerCase();\n const rawValue = raw[rawName];\n if (rawValue === undefined) continue;\n const joined = Array.isArray(rawValue) ? rawValue.join(', ') : String(rawValue);\n\n // Credential headers: capture the format prefix, drop the secret.\n if (CREDENTIAL_HEADER_NAMES.has(name)) {\n const fmt = extractApiKeyFormat(joined);\n if (fmt && !apiKeyFormat) apiKeyFormat = fmt;\n continue;\n }\n\n // Cookie: the value is a secret (dropped below), but the PAIR COUNT is a\n // client-shape signal worth keeping.\n if (name === 'cookie') {\n cookieCount = joined.split(';').filter((s) => s.trim().length > 0).length;\n }\n\n // Genuine secrets: drop entirely.\n if (isSecretHeader(name)) continue;\n\n // Everything else describing the agent: keep, bounded.\n let value = joined;\n if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {\n value = value.slice(0, MAX_HEADER_VALUE_BYTES);\n }\n const entryBytes = byteLength(name) + byteLength(value);\n if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;\n totalBytes += entryBytes;\n count++;\n headers[name] = value;\n if (isPlatformHeader(name)) platformHeaders[name] = value;\n }\n\n const result: SanitizeHeadersResult = { headers };\n if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;\n if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;\n if (cookieCount !== undefined) result.cookieCount = cookieCount;\n return result;\n}\n\n/**\n * Pull the known platform-signal headers out of an ALREADY-sanitised header\n * map. `sanitizeHeaders` already computes this as a by-product; this standalone\n * form is exported for call-sites (edge, tests) that hold a sanitised map and\n * want only the platform subset. Never re-run over raw (unsanitised) headers.\n */\nexport function extractPlatformHeaders(\n sanitized: Record<string, string> | undefined | null\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!sanitized) return out;\n for (const name of Object.keys(sanitized)) {\n if (isPlatformHeader(name.toLowerCase())) out[name.toLowerCase()] = sanitized[name];\n }\n return out;\n}\n\n/**\n * Precedence-ordered CDN header sources for each derived `connection` key.\n * First present header wins; the special `x-forwarded-for` source takes the\n * LEFTMOST (client) entry of the comma-separated chain.\n */\nconst CONNECTION_HEADER_SOURCES: ReadonlyArray<readonly [key: string, headers: readonly string[]]> =\n [\n ['ip', ['cf-connecting-ip', 'fastly-client-ip', 'true-client-ip', 'x-real-ip']],\n [\n 'country',\n ['cf-ipcountry', 'x-vercel-ip-country', 'cloudfront-viewer-country', 'fastly-geo-country'],\n ],\n ['region', ['x-vercel-ip-country-region', 'cloudfront-viewer-country-region']],\n ['countryRegionName', ['cloudfront-viewer-country-region-name']],\n ['city', ['x-vercel-ip-city', 'cloudfront-viewer-city']],\n ['latitude', ['x-vercel-ip-latitude', 'cloudfront-viewer-latitude']],\n ['longitude', ['x-vercel-ip-longitude', 'cloudfront-viewer-longitude']],\n ['postalCode', ['x-vercel-ip-postal-code', 'cloudfront-viewer-postal-code']],\n ['asn', ['cloudfront-viewer-asn']],\n ['tlsVersion', ['cloudfront-viewer-tls']],\n ['httpVersion', ['cloudfront-viewer-http-version']],\n ['timeZone', ['x-vercel-ip-timezone', 'cloudfront-viewer-time-zone']],\n ['metroCode', ['cloudfront-viewer-metro-code']],\n // TLS fingerprints can only be computed where TLS terminates. When a CDN\n // terminates TLS in front of the merchant, its fingerprint headers ARE the\n // connection-layer truth — normalising them here is the permanent design.\n // CloudFront delivers JA3/JA4 only via an origin request policy and only\n // for HTTPS viewer connections.\n ['tlsFingerprint', ['cf-ja3-hash', 'cloudfront-viewer-ja3-fingerprint']],\n ['ja4', ['cf-ja4', 'cloudfront-viewer-ja4-fingerprint']],\n // Header-structure fingerprint: browser/SDK-distinctive header ordering.\n ['headerOrder', ['cloudfront-viewer-header-order']],\n ['headerCount', ['cloudfront-viewer-header-count']],\n ];\n\n/**\n * Backend bound: observedMetadata.connection values longer than this fail\n * the platform's zod parse outright (boundedStringRecord(32, 256)), so every\n * emitter truncates — headerOrder routinely exceeds it.\n */\nexport const MAX_CONNECTION_VALUE_CHARS = 256;\n\n/**\n * Derive the connection-layer block from CDN-injected request headers.\n *\n * When a merchant's SDK-gated origin sits behind a CDN (Cloudflare, Fastly,\n * Vercel, CloudFront), the CDN has already seen the connection layer and\n * injected it as headers. This promotes those headers to the same\n * `connection` keys the edge adapters populate natively, so SDK-only\n * deployments still get IP / geo / TLS attribution. Precedence per key:\n *\n * - `ip`: `cf-connecting-ip` > `fastly-client-ip` > `true-client-ip` >\n * `x-real-ip` > `cloudfront-viewer-address` (port stripped) > leftmost\n * `x-forwarded-for`\n * - `country`: `cf-ipcountry` > `x-vercel-ip-country` >\n * `cloudfront-viewer-country` > `fastly-geo-country`\n * - `region` / `city` / `timeZone`: Vercel then CloudFront viewer headers\n * - `countryRegionName` / `asn` / `tlsVersion` / `httpVersion` /\n * `metroCode` / `headerOrder` / `headerCount`: `cloudfront-viewer-*`\n * - `tlsFingerprint`: `cf-ja3-hash` > `cloudfront-viewer-ja3-fingerprint`\n * - `ja4`: `cf-ja4` > `cloudfront-viewer-ja4-fingerprint`\n *\n * All keys are additive under `schemaVersion` 1 (the frozen-capture doctrine\n * bumps only for changed semantics, never for additive signals). Values are\n * truncated to MAX_CONNECTION_VALUE_CHARS — the platform's hard bound.\n *\n * Edge adapters keep their richer native collectors — native platform\n * signals are authoritative; this header derivation is the SDK-level\n * fallback. Header names are matched case-insensitively. Returns undefined\n * when no source header is present, so the `connection` key is simply\n * omitted (matching edge behaviour).\n */\nexport function deriveConnectionFromHeaders(\n headers: Record<string, string> | undefined | null\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n const lower: Record<string, string> = {};\n for (const name of Object.keys(headers)) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) lower[name.toLowerCase()] = value;\n }\n\n const connection: Record<string, string> = {};\n for (const [key, sources] of CONNECTION_HEADER_SOURCES) {\n for (const source of sources) {\n const value = lower[source]?.trim();\n if (value) {\n connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);\n break;\n }\n }\n }\n // ip fallback 1: cloudfront-viewer-address arrives as ip:port — strip the\n // trailing port only (IPv6-safe), unlike the dedicated client-ip headers.\n // The port itself is kept as its own key: ephemeral-port patterns signal\n // NAT/proxy connection reuse.\n {\n const addr = lower['cloudfront-viewer-address']?.trim();\n const portMatch = addr?.match(/:(\\d+)$/);\n if (portMatch) connection.sourcePort = portMatch[1];\n if (!connection.ip && addr) connection.ip = addr.replace(/:\\d+$/, '');\n }\n // ip fallback 2: leftmost (client) hop of the x-forwarded-for chain.\n if (!connection.ip) {\n const xff = lower['x-forwarded-for'];\n const client = xff?.split(',')[0]?.trim();\n if (client) connection.ip = client;\n }\n // tlsCipher: CloudFront folds the cipher into the viewer-tls string\n // (`TLSv1.3:TLS_AES_128_GCM_SHA256:fullHandshake`). `tlsVersion` stays\n // verbatim (reducing it would be a semantic change → schema v2); the\n // cipher is pulled out additively so it is queryable on its own.\n if (!connection.tlsCipher) {\n const cipher = connection.tlsVersion?.split(':')[1];\n if (cipher) connection.tlsCipher = cipher;\n }\n\n return Object.keys(connection).length > 0 ? connection : undefined;\n}\n\n/**\n * The FULL metadata capture for one request at an SDK adapter (express /\n * nextjs / mcp): sanitised headers, the safe credential format prefix, the\n * platform-signal subset, the CDN-derived connection block, and the capture\n * schema version. This is the ONE builder all SDK adapters share, so their\n * verify-access bodies agree byte-for-byte.\n *\n * Connection derivation runs over the RAW header map (pre-cap) — the size\n * caps guard storage growth and must never hide a geo/IP header that\n * happened to arrive late in an oversized map.\n */\nexport function buildSdkObservedMetadata(\n rawHeaders: Record<string, string | string[] | undefined> | undefined | null\n): ObservedMetadata {\n const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);\n const flat: Record<string, string> = {};\n if (rawHeaders) {\n for (const name of Object.keys(rawHeaders)) {\n const value = rawHeaders[name];\n if (value === undefined) continue;\n flat[name.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value);\n }\n }\n const connection = deriveConnectionFromHeaders(flat);\n return {\n headers,\n ...(apiKeyFormat && { apiKeyFormat }),\n ...(platformHeaders && { platformHeaders }),\n ...(connection && { connection }),\n ...(cookieCount !== undefined && { cookieCount }),\n schemaVersion: CAPTURE_SCHEMA_VERSION,\n };\n}\n","/**\n * Edge verification config — the per-endpoint policy the Trusted Agent\n * Gateway edge adapters (e.g. `@astrasyncai/adapter-lambda`) fetch from the\n * AstraSync dashboard to decide how much verification friction to apply\n * to inbound traffic, and where.\n *\n * Fetch pattern mirrors `well-known.ts`: TTL cache + stale-while-revalidate\n * + in-flight dedupe, with a `_reset*` hook for tests. Fail posture is\n * deliberately asymmetric: this module can NEVER put a site into enforce\n * mode on its own — enforce only ever originates from a successfully\n * fetched config, and a config that has gone stale past `maxStaleMs`\n * degrades back to observe.\n *\n * Which EdgeConfig fields each integration consumes:\n *\n * | Field | Edge adapters | SDK adapters (express/nextjs/mcp) |\n * | ------------------------------ | ------------- | --------------------------------- |\n * | `mode` (observe/enforce) | yes | — |\n * | `depth` | yes | — |\n * | `pathRules` | yes | — |\n * | `sampling.anonymousBeaconRate` | yes | yes — the SDK anonymous beacon |\n * | `failurePosture` | yes | — |\n *\n * The observe/enforce × depth posture is EDGE-ONLY by design: SDK adapters\n * enforce via the dashboard route policy (`fetchRoutes`), not via this\n * config, and consume only the `sampling` block for their anonymous\n * traffic beacon.\n */\n\nimport { sdkFetch } from './http';\nimport type { GatewayConfig } from './types';\n\n/**\n * Edge posture. Canonical Trusted Agent Gateway vocabulary:\n * `observe` ≈ the gateway's `passive` posture (verify +\n * record, enforce nothing), `enforce` ≈ `active`. New value set on a new\n * field name — do NOT reuse `GatewayPosture`'s `active`/`passive` here\n * (different field, different meaning: posture governs an agent-side\n * gateway; mode governs counterparty-side edge interception).\n */\nexport type EdgeMode = 'observe' | 'enforce';\n\n/**\n * How deep the edge checks each request — what is it → who is it → are\n * they allowed:\n * - `classify` — UA / platform-fingerprint classification only; no\n * credential handling.\n * - `authenticate` — establish who is calling: detect and parse agent\n * credentials (X-Astra-*, VI SD-JWT, RFC 9421, ACP,\n * UCP, AP2…) and verify presented AstraSync identities.\n * - `authorize` — full policy decision: credentials cryptographically\n * proven and PDLSS-evaluated via a verify-access round\n * trip. (US spelling on the wire, matching\n * `authorizeSettlement` and HTTP `Authorization`.)\n */\nexport type EdgeVerificationDepth = 'classify' | 'authenticate' | 'authorize';\n\nexport interface EdgePathRule {\n /**\n * `*`-wildcard glob matched against the request path. Matching is\n * case-INsensitive and all regex metacharacters except `*` are\n * escaped. (Deliberately diverges from the express adapter's\n * `matchRoute`, which is historically case-sensitive by default —\n * new surface ships case-insensitive matching as the default.)\n */\n pattern: string;\n /** Pass the request through untouched (static assets); mode/depth ignored. */\n skip?: boolean;\n /** Override the top-level mode for this path. */\n mode?: EdgeMode;\n /** Override the top-level depth for this path. */\n depth?: EdgeVerificationDepth;\n}\n\nexport interface EdgeConfig {\n /** Shape version — bump on breaking changes. */\n version: 1;\n /** Default posture for paths no rule matches. */\n mode: EdgeMode;\n /** Default check depth for paths no rule matches. */\n depth: EdgeVerificationDepth;\n /** Ordered, first-match-wins. */\n pathRules: EdgePathRule[];\n sampling: {\n /** Fraction (0..1) of anonymous-bot requests that emit a beacon. */\n anonymousBeaconRate: number;\n };\n /**\n * 4.5.0: the EFFECTIVE failure posture is derived from the effective\n * mode — fail posture follows success posture. Observe fails open\n * (unreachable backend = pass-through, site never breaks); enforce fails\n * closed on verification-infrastructure failure (503\n * `VERIFICATION_UNAVAILABLE`, retry-later — see edge-core/pipeline). This\n * field is retained on the wire for adapter compatibility and as a future\n * explicit override; it is not consulted by the 4.5.x pipeline. Note the\n * distinction from CONFIG staleness: a config stale past 24h still has\n * enforce degraded to observe (`degradeToObserve`) — that is config-trust\n * hygiene, independent of runtime verification availability.\n */\n failurePosture: 'open' | 'closed';\n}\n\n/**\n * The safe default: observe-only, classification depth, nothing enforced.\n * Served by the backend when an endpoint has never been configured, and\n * used by `getEdgeConfig` whenever no config can be fetched.\n */\nexport const DEFAULT_EDGE_CONFIG: EdgeConfig = Object.freeze({\n version: 1,\n mode: 'observe',\n depth: 'classify',\n pathRules: [],\n sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),\n failurePosture: 'open',\n}) as EdgeConfig;\n\nconst EDGE_MODES: readonly string[] = ['observe', 'enforce'];\nconst EDGE_DEPTHS: readonly string[] = ['classify', 'authenticate', 'authorize'];\n\n/** Structural guard for configs arriving over the wire. */\nexport function isEdgeConfig(value: unknown): value is EdgeConfig {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n if (v.version !== 1) return false;\n if (!EDGE_MODES.includes(v.mode as string)) return false;\n if (!EDGE_DEPTHS.includes(v.depth as string)) return false;\n if (!Array.isArray(v.pathRules)) return false;\n for (const rule of v.pathRules) {\n if (typeof rule !== 'object' || rule === null) return false;\n const r = rule as Record<string, unknown>;\n if (typeof r.pattern !== 'string' || r.pattern.length === 0) return false;\n if (r.mode !== undefined && !EDGE_MODES.includes(r.mode as string)) return false;\n if (r.depth !== undefined && !EDGE_DEPTHS.includes(r.depth as string)) return false;\n }\n const sampling = v.sampling as Record<string, unknown> | undefined;\n if (\n typeof sampling !== 'object' ||\n sampling === null ||\n typeof sampling.anonymousBeaconRate !== 'number' ||\n sampling.anonymousBeaconRate < 0 ||\n sampling.anonymousBeaconRate > 1\n ) {\n return false;\n }\n return v.failurePosture === 'open';\n}\n\nexport interface FetchEdgeConfigSuccess {\n edgeConfig: EdgeConfig;\n etag?: string;\n}\n\nexport type FetchEdgeConfigResult = FetchEdgeConfigSuccess | { notModified: true } | null;\n\n/**\n * Fetch the edge config for an endpoint from the AstraSync backend.\n * `GET {apiBaseUrl}/endpoints/:counterpartyId/edge-config` with the same\n * auth headers as `fetchRoutes`. Pass the cached `etag` to get a cheap\n * `{ notModified: true }` on 304. Returns `null` on any failure —\n * the caller decides how to fall back.\n */\nexport async function fetchEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { etag?: string; timeoutMs?: number }\n): Promise<FetchEdgeConfigResult> {\n if (!counterpartyId) return null;\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n if (opts?.etag) headers['If-None-Match'] = opts.etag;\n try {\n const response = await sdkFetch(\n `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,\n { method: 'GET', headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5000) }\n );\n if (response.status === 304) return { notModified: true };\n if (!response.ok) return null;\n const body = (await response.json()) as { data?: { edgeConfig?: unknown } };\n const edgeConfig = body.data?.edgeConfig;\n if (!isEdgeConfig(edgeConfig)) return null;\n return { edgeConfig, etag: response.headers.get('etag') ?? undefined };\n } catch {\n return null;\n }\n}\n\ninterface CacheEntry {\n config: EdgeConfig;\n etag?: string;\n /** When the entry was last confirmed fresh (fetch or 304). */\n lastSuccessAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 1000;\nconst DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1000;\n\nconst cache = new Map<string, CacheEntry>();\nconst inflight = new Map<string, Promise<void>>();\n\nfunction cacheKey(apiBaseUrl: string, counterpartyId: string): string {\n return `${apiBaseUrl}|${counterpartyId}`;\n}\n\n/** Copy of `config` with every enforce (top-level and per-rule) degraded to observe. */\nexport function degradeToObserve(config: EdgeConfig): EdgeConfig {\n if (config.mode !== 'enforce' && !config.pathRules.some((r) => r.mode === 'enforce')) {\n return config;\n }\n return {\n ...config,\n mode: 'observe',\n pathRules: config.pathRules.map((r) => (r.mode === 'enforce' ? { ...r, mode: 'observe' } : r)),\n };\n}\n\nasync function revalidate(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string\n): Promise<void> {\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n const existing = inflight.get(key);\n if (existing) return existing;\n\n const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache.get(key)?.etag })\n .then((result) => {\n if (result === null) return; // failure — cache untouched, caller falls back\n const now = Date.now();\n if ('notModified' in result) {\n const entry = cache.get(key);\n if (entry) entry.lastSuccessAt = now;\n return;\n }\n cache.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });\n })\n .finally(() => {\n inflight.delete(key);\n });\n\n inflight.set(key, promise);\n return promise;\n}\n\n/**\n * Get the edge config for an endpoint, cached. Never throws, never blocks\n * longer than one fetch.\n *\n * - Fresh cache (within `ttlMs`) → cached config, no network.\n * - Stale cache → cached config immediately + background revalidate\n * (stale-while-revalidate). If the last successful fetch is older than\n * `maxStaleMs` (default 24h), any enforce is degraded to observe — a\n * long-dead backend can never keep a site enforcing.\n * - No cache → await one fetch; on failure return `DEFAULT_EDGE_CONFIG`\n * (observe-only). Defaults never enforce.\n */\nexport async function getEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { ttlMs?: number; maxStaleMs?: number }\n): Promise<EdgeConfig> {\n const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;\n const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n\n const entry = cache.get(key);\n if (entry) {\n const age = Date.now() - entry.lastSuccessAt;\n if (age > ttlMs) {\n revalidate(config, counterpartyId).catch(() => {\n // background refresh failed — stale entry remains until next call\n });\n }\n return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;\n }\n\n await revalidate(config, counterpartyId).catch(() => {\n // fetch failed — fall through to defaults\n });\n return cache.get(key)?.config ?? DEFAULT_EDGE_CONFIG;\n}\n\n/**\n * First-match-wins path-rule lookup. Case-insensitive `*` globs with all\n * other regex metacharacters escaped (a literal `.` in a pattern matches\n * only `.`). Returns `undefined` when no rule matches — the caller applies\n * the config's top-level mode/depth.\n */\nexport function matchEdgePathRule(rules: EdgePathRule[], path: string): EdgePathRule | undefined {\n for (const rule of rules) {\n if (globToRegExp(rule.pattern).test(path)) return rule;\n }\n return undefined;\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`, 'i');\n}\n\n/** Reset cache — for testing only. */\nexport function _resetEdgeConfigCache(): void {\n cache.clear();\n inflight.clear();\n}\n","/**\n * Platform-agent fingerprint signatures — the shared registry of known\n * platform-agent UA / agent-card patterns (Claude / ChatGPT / Gemini /\n * Cursor / Goose).\n *\n * Single source of truth, lifted verbatim from the backend's\n * `platform-agent-detector.service` (which now imports detection from\n * here): the backend's verify-access anonymous handler and the edge\n * adapter (`@astrasyncai/adapter-lambda`) must classify identically or\n * the three-tier visibility numbers drift between capture points.\n *\n * Pure regex — no Node built-ins, edge-safe. Detection is regex-only for\n * v2.9 — TLS fingerprinting / behavioural signatures are deferred.\n */\n\nexport type PlatformAgentVendor =\n | 'claude'\n | 'chatgpt'\n | 'gemini'\n | 'cursor'\n | 'goose'\n | 'perplexity'\n | 'chatgpt-atlas'\n | 'perplexity-comet'\n | 'astrasync-sdk'\n | 'unknown';\n\nexport interface PlatformFingerprint {\n vendor: PlatformAgentVendor;\n /** A stable identifier used as the orphan-agent dedup key. */\n fingerprintKey: string;\n /** Human-readable name surfaced in the admin panel. */\n displayName: string;\n}\n\nexport interface PlatformDetectionInput {\n userAgent?: string;\n agentCardUrl?: string;\n /**\n * A safe API-key format prefix observed on the caller's\n * credential header (e.g. `sk-ant-api03`, `sk-proj`, `aiza`). A strong\n * platform signal; never the secret. Matched against `apiKeyFormatPatterns`.\n */\n apiKeyFormat?: string;\n /**\n * The sanitised platform-signal headers (lowercased names →\n * values), e.g. `openai-organization`, `x-goog-user-project`. Matched\n * against `headerPatterns` (which test on `name` and `name: value`).\n */\n platformHeaders?: Record<string, string>;\n /**\n * The caller's JA4 TLS-client fingerprint (from the connection capture).\n * Matched against `ja4Patterns`. A JA4 identifies the client TLS stack,\n * so signatures should pair it with other evidence when attributing a\n * vendor.\n */\n ja4?: string;\n /**\n * The caller's origin ASN (from the connection capture). Matched against\n * `asnList` by exact membership. An ASN alone attributes an entire cloud\n * provider — registry validation rejects ASN-only signatures.\n */\n asn?: string;\n}\n\n/**\n * A signature definition, generic over the vendor key. The seed constant\n * below uses the closed `PlatformAgentVendor` union; DB-promoted signatures\n * (backend dynamic registry, console round) carry arbitrary string vendors —\n * `matchPlatformSignature` accepts both.\n */\nexport interface PlatformSignatureDef<V extends string = string> {\n vendor: V;\n displayName: string;\n uaPatterns?: RegExp[];\n agentCardPatterns?: RegExp[];\n /**\n * Patterns tested against an observed API-key format prefix\n * (e.g. `/^sk-ant/i` → claude). A credential-header format is a stronger\n * platform signal than a spoofable User-Agent.\n */\n apiKeyFormatPatterns?: RegExp[];\n /**\n * Patterns tested against each observed platform-signal\n * header, as both `name` and `name: value` (so `/openai-organization/i` and\n * `/x-goog-user-project/i` match on presence).\n */\n headerPatterns?: RegExp[];\n /** Patterns tested against the observed JA4 TLS-client fingerprint. */\n ja4Patterns?: RegExp[];\n /** Exact ASN strings this signature matches (never regex). */\n asnList?: string[];\n}\n\n/**\n * A fingerprint whose vendor may be a dynamically-promoted (non-seed) key.\n * Structurally a superset of `PlatformFingerprint`.\n */\nexport interface DynamicPlatformFingerprint {\n vendor: string;\n fingerprintKey: string;\n displayName: string;\n}\n\n/**\n * Registry of known platform-agent signatures. Order matters — first match wins.\n *\n * Patterns are intentionally permissive (case-insensitive substring match) since\n * platform UA strings drift between versions. False positives are tolerable —\n * the orphan record is informational, not enforcement.\n */\nexport const PLATFORM_AGENT_SIGNATURES: ReadonlyArray<PlatformSignatureDef<PlatformAgentVendor>> = [\n {\n vendor: 'claude',\n displayName: 'Anthropic Claude',\n uaPatterns: [/claude/i, /anthropic/i],\n agentCardPatterns: [/anthropic\\.com/i, /claude\\.ai/i],\n apiKeyFormatPatterns: [/^sk-ant/i],\n headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i],\n },\n {\n vendor: 'chatgpt',\n displayName: 'OpenAI ChatGPT',\n uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\\d/i],\n agentCardPatterns: [/openai\\.com/i, /chatgpt\\.com/i],\n apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],\n headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i],\n },\n {\n vendor: 'gemini',\n displayName: 'Google Gemini',\n uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],\n agentCardPatterns: [/gemini\\.google\\.com/i, /ai\\.google\\.dev/i],\n apiKeyFormatPatterns: [/^aiza/i],\n headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i],\n },\n {\n vendor: 'cursor',\n displayName: 'Cursor',\n uaPatterns: [/cursor/i],\n agentCardPatterns: [/cursor\\.sh/i, /cursor\\.com/i],\n },\n {\n vendor: 'goose',\n displayName: 'Block Goose',\n uaPatterns: [/goose/i, /block-goose/i],\n agentCardPatterns: [/block\\.xyz\\/goose/i, /goose\\.tools/i],\n },\n {\n vendor: 'perplexity',\n displayName: 'Perplexity',\n uaPatterns: [/perplexity/i],\n agentCardPatterns: [/perplexity\\.ai/i],\n apiKeyFormatPatterns: [/^pplx-/i],\n },\n // Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must\n // never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the\n // browser product is a different surface than the assistant service, and\n // the DB registry mirrors one row per vendor. These sit after the primary\n // vendor entries so a UA carrying an explicit vendor token keeps its\n // primary attribution; a browser-shaped UA with the agentic token is\n // caught here BEFORE classify's human tier, which is what makes these\n // visits observable at all. Token drift is real (some builds mimic Chrome\n // outright) — re-verify against captured events when a new browser ships,\n // and check `sec-ch-ua` platformHeaders for the real brand.\n {\n vendor: 'chatgpt-atlas',\n displayName: 'ChatGPT Atlas browser',\n uaPatterns: [/\\batlas\\/\\d/i],\n headerPatterns: [/^sec-ch-ua: .*atlas/i],\n },\n {\n vendor: 'perplexity-comet',\n displayName: 'Perplexity Comet browser',\n uaPatterns: [/\\bcomet\\/\\d/i],\n headerPatterns: [/^sec-ch-ua: .*comet/i],\n },\n // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party\n // traffic must never pollute the unknown/anonymous pool it exists to audit.\n {\n vendor: 'astrasync-sdk',\n displayName: 'AstraSync SDK',\n uaPatterns: [/^astrasync-sdk\\//i],\n },\n];\n\n/**\n * Generic first-match-wins matcher over an arbitrary signature set. The\n * backend's dynamic registry merges the seed constant with DB-promoted\n * signatures and calls this — ONE matching implementation everywhere\n * (fingerprint-key rule included: vendor + lowercased UA basename before\n * the first space/slash, falling back to the agent-card host).\n */\nexport function matchPlatformSignature(\n signatures: ReadonlyArray<PlatformSignatureDef>,\n input: PlatformDetectionInput\n): DynamicPlatformFingerprint | undefined {\n const ua = input.userAgent ?? '';\n const cardUrl = input.agentCardUrl ?? '';\n const apiKeyFormat = input.apiKeyFormat ?? '';\n const ja4 = input.ja4 ?? '';\n const asn = input.asn ?? '';\n // Flatten platform headers to `name` and `name: value` lines for matching.\n const headerLines: string[] = [];\n if (input.platformHeaders) {\n for (const [name, value] of Object.entries(input.platformHeaders)) {\n headerLines.push(name, `${name}: ${value}`);\n }\n }\n\n for (const sig of signatures) {\n const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));\n const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));\n const keyMatch =\n apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));\n const headerMatch =\n headerLines.length > 0 &&\n sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));\n const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));\n const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);\n if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {\n const uaBase = ua.split(/[\\s/]/)[0]?.toLowerCase() ?? '';\n const cardHost = (() => {\n try {\n return cardUrl ? new URL(cardUrl).host : '';\n } catch {\n return '';\n }\n })();\n // Prefer a UA/card basename for the dedup key; fall back to the\n // credential format, then the connection fingerprint (still stable\n // per-vendor keys) when only a key/header/ja4/asn matched.\n const keyBasis =\n uaBase || cardHost || apiKeyFormat || ja4 || (asn && `asn${asn}`) || 'unknown';\n return {\n vendor: sig.vendor,\n fingerprintKey: `${sig.vendor}:${keyBasis}`,\n displayName: sig.displayName,\n };\n }\n }\n\n return undefined;\n}\n\n/**\n * Inspect caller metadata for a known SEED platform-agent fingerprint.\n * Returns undefined if no signature matches. (Backends with the dynamic\n * registry should call `matchPlatformSignature` over their merged set\n * instead — same semantics, live signature additions included.)\n */\nexport function detectPlatformFingerprint(\n input: PlatformDetectionInput\n): PlatformFingerprint | undefined {\n // Seed vendors are all members of the PlatformAgentVendor union, so the\n // narrowing cast is sound by construction.\n return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input) as\n | PlatformFingerprint\n | undefined;\n}\n","/**\n * Three-tier traffic classification (verified / identified-but-unregistered\n * / anonymous) plus the two non-tiers the gateway touches as little as\n * possible: `human` (zero network calls, zero logging) and `skipped`\n * (static assets / excluded paths).\n *\n * Cheapest checks first — the human path must add microseconds, not\n * milliseconds. Platform signatures are shared with the backend so the\n * edge and verify-access's anonymous handler classify identically.\n */\n\nimport { matchEdgePathRule, type EdgeConfig } from '../edge-config';\nimport { sanitizeHeaders } from '../metadata-capture';\nimport { detectPlatformFingerprint } from '../platform-signatures';\nimport { extractCredentials } from '../verify';\nimport { detectCommerce } from './detect';\nimport { headerValue } from './request';\nimport type { Classification, EffectivePolicy, NormalizedRequest } from './types';\n\n/** Extensions the gateway never classifies — static assets. */\nconst STATIC_EXTENSIONS =\n /\\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i;\n\n/**\n * AstraSync's own SDK traffic (`sdkFetch` stamps this UA on every outbound\n * SDK request). Whenever a deployment's API URL transits a gateway-fronted\n * distribution, the SDK's beacon/verify calls re-enter the gateway — and a\n * beacon that gets beaconed is a self-sustaining invocation loop (the 4.4.0\n * staging outage). Self-traffic is therefore a first-class tier: pass\n * through with ZERO beacons, verify calls, or logging, checked BEFORE the\n * credentials step (SDK verify calls carry a Bearer key and would otherwise\n * tier `verified` and re-enter at authenticate/authorize depth).\n *\n * Spoofing: a caller forging this UA gets pass-through — the same treatment\n * anonymous bots already get in both modes (they only dodge the sampled\n * anonymous beacon), and the origin's own auth still applies. No new bypass.\n */\nconst SELF_UA_PATTERN = /^astrasync-sdk\\//i;\n\n/** Non-browser, non-platform CLI/library UA tokens → anonymous bot. */\nconst BOT_UA_PATTERN =\n /curl|wget|python-requests|python-urllib|node-fetch|axios|got|okhttp|go-http-client|libwww|httpie|java\\/|ruby|php|scrapy|headless|phantomjs|selenium|playwright|puppeteer|bot|crawler|spider|slurp/i;\n\n/** Browser-shaped UA. */\nconst BROWSER_UA_PATTERN = /mozilla\\/\\d/i;\n\n/**\n * Resolve the effective mode/depth for a path from the EdgeConfig — ordered\n * first-match-wins rules with case-insensitive globs; no match falls through\n * to the config's top-level defaults. Static extensions are always skipped\n * regardless of rules (a rule can only skip MORE, never un-skip an asset).\n */\nexport function resolvePolicy(config: EdgeConfig, path: string): EffectivePolicy {\n if (STATIC_EXTENSIONS.test(path)) {\n return { mode: config.mode, depth: config.depth, skip: true };\n }\n const rule = matchEdgePathRule(config.pathRules, path);\n if (!rule) return { mode: config.mode, depth: config.depth, skip: false };\n return {\n mode: rule.mode ?? config.mode,\n depth: rule.depth ?? config.depth,\n skip: rule.skip === true,\n };\n}\n\n/**\n * Classify one request. Order (cheapest sufficient evidence wins):\n * 0. AstraSync SDK UA → `self` (own plumbing; never beaconed — loop-proof)\n * 1. X-Astra-* credentials → `verified` candidate\n * 2. commerce-protocol credentials on the wire → `identified`\n * 3. platform UA fingerprint (Claude/ChatGPT/Gemini/…) → `identified`\n * 4. bot-shaped UA / headerless non-browser → `anonymous-bot`\n * 5. everything browser-shaped → `human`\n *\n * `depth: 'classify'` skips step 2 (no body inspection, no header sniffing\n * beyond UA) — that is the zero-friction setting.\n */\nexport function classify(\n req: NormalizedRequest,\n host: string,\n depth: 'classify' | 'authenticate' | 'authorize'\n): Classification {\n const userAgent = headerValue(req, 'user-agent') ?? '';\n\n // 0. Our own SDK's outbound calls (beacons, verify-access, config\n // fetches). MUST precede the credentials check — see SELF_UA_PATTERN.\n if (SELF_UA_PATTERN.test(userAgent)) {\n return { tier: 'self' };\n }\n\n // 1. Native AstraSync credentials.\n const credentials = extractCredentials(req.headers, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { tier: 'verified', protocol: 'x-astra' };\n }\n\n // The key-format prefix + platform-signal headers are stronger,\n // less-spoofable platform signals than the UA. Compute once (cheap\n // string work) and feed every fingerprint call below.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);\n const detectionInput = { userAgent, apiKeyFormat, platformHeaders };\n\n // 2. Commerce-protocol credentials (skipped entirely at classify depth).\n if (depth !== 'classify') {\n const commerce = detectCommerce(req, host);\n if (commerce) {\n return {\n tier: 'identified',\n protocol: commerce.protocol,\n artifacts: commerce.artifacts,\n evidence: commerce.evidence,\n fingerprint: detectPlatformFingerprint(detectionInput),\n };\n }\n }\n\n // 3. Platform-agent fingerprint (UA, key-format, or platform header).\n const fingerprint = detectPlatformFingerprint(detectionInput);\n if (fingerprint) {\n return { tier: 'identified', protocol: 'platform-ua', fingerprint };\n }\n\n // 4. Bot-shaped: CLI/library UA, no UA at all, or any non-browser UA —\n // humans arrive with Mozilla-family UAs; everything else is automation.\n if (!userAgent || BOT_UA_PATTERN.test(userAgent) || !BROWSER_UA_PATTERN.test(userAgent)) {\n return { tier: 'anonymous-bot', evidence: { userAgent: userAgent || '(none)' } };\n }\n\n // 4b. Claims to be a browser but is missing every browser fetch-metadata\n // header — headless/spoofed. `sec-fetch-mode` is sent by all evergreen\n // browsers; its absence on a Mozilla UA is a strong bot signal.\n if (!headerValue(req, 'sec-fetch-mode') && !headerValue(req, 'accept-language')) {\n return { tier: 'anonymous-bot', evidence: { userAgent, spoofedBrowser: true } };\n }\n\n // 5. Human traffic — the gateway gets out of the way.\n return { tier: 'human' };\n}\n\n/** Exported for tests. */\nexport const _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN, SELF_UA_PATTERN };\n","/**\n * Time-budgeted event emission.\n *\n * Some edge runtimes (Lambda@Edge) have no background-work scheduler —\n * anything not awaited before the handler returns may never run. So every\n * telemetry call is awaited under an explicit budget and DROPPED on\n * timeout: latency to the customer's traffic is bounded, and a slow\n * AstraSync API costs telemetry, never page loads. Runtimes that provide\n * `waitUntil` (Cloudflare Workers, Vercel Edge, Fastly Compute) can pass\n * it via {@link EdgeCoreOptions.waitUntil} to take beacons off the latency\n * path entirely.\n */\n\nimport { reportUnregisteredAttempt } from '../verify';\nimport { buildObservedMetadata, headerValue } from './request';\nimport type { Classification, EdgeCoreOptions, NormalizedRequest } from './types';\n\n/** Await `promise` for at most `ms`; resolve `undefined` on timeout/error. */\nexport async function withBudget<T>(promise: Promise<T>, ms: number): Promise<T | undefined> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), ms);\n }),\n ]);\n } catch {\n return undefined;\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/**\n * Emit an unregistered-attempt beacon for `identified` (non-crypto depths)\n * and sampled `anonymous-bot` traffic. Unauthenticated by design; the\n * backend fingerprints the UA and find-or-provisions platform agents\n * server-side.\n */\nexport async function emitBeacon(\n options: EdgeCoreOptions,\n req: NormalizedRequest,\n classification: Classification,\n budgetMs: number\n): Promise<void> {\n const budgeted = withBudget(\n reportUnregisteredAttempt(\n { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },\n {\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: 'website',\n sourceIp: req.clientIp,\n userAgent: headerValue(req, 'user-agent'),\n requestPath: req.uri,\n requestMethod: req.method,\n // Evidence fields the backend persists into the event record.\n protocol: classification.protocol,\n evidence: classification.evidence,\n // The full sanitized header + connection capture for the\n // unregistered caller (fire-and-forget, so free).\n observedMetadata: buildObservedMetadata(req),\n }\n ),\n budgetMs\n );\n if (options.waitUntil) {\n options.waitUntil(budgeted);\n return;\n }\n await budgeted;\n}\n\n/** Deterministic-in-tests sampling gate. */\nexport function sampled(rate: number, random: () => number = Math.random): boolean {\n if (rate <= 0) return false;\n if (rate >= 1) return true;\n return random() < rate;\n}\n","/**\n * Anonymous-traffic beacon for the SDK middleware pass-through paths.\n *\n * When a request passes through UNGATED (no dashboard route matches it, or\n * the matching route is gated at `none`), no verify-access call happens and\n * the endpoint's dashboard is blind to that traffic. This module gives the\n * express/nextjs adapters the same lightweight visibility the edge adapters\n * already have: bot- and agent-shaped pass-through traffic emits a\n * fire-and-forget unregistered-attempt beacon, while human traffic and\n * static assets are never beaconed and credentialed agents are handled by\n * verify-access, not this beacon.\n *\n * Sampling is dashboard-driven: the endpoint's edge verification config\n * supplies `sampling.anonymousBeaconRate` (0 turns anonymous-bot sampling\n * off; platform-fingerprinted agents always beacon). Nothing here ever\n * waits on the request path — the beacon is never awaited, and the config\n * fetch runs in the background: until a config has arrived, no beacons are\n * sent. Merchants who must not emit any extra outbound calls can set\n * `anonymousBeacon: false` on the middleware options, which disables the\n * beacon (and its config fetch) entirely.\n */\n\nimport { _patterns } from '../edge-core/classify';\nimport { sampled } from '../edge-core/events';\nimport { getEdgeConfig, type EdgeConfig } from '../edge-config';\nimport { buildSdkObservedMetadata, sanitizeHeaders } from '../metadata-capture';\nimport { detectPlatformFingerprint } from '../platform-signatures';\nimport { extractCredentials, reportUnregisteredAttempt } from '../verify';\nimport type { GatewayConfig } from '../types';\n\n/** Raw (pre-sanitisation) header map as Node/Web adapters hold it. */\ntype RawHeaders = Record<string, string | string[] | undefined>;\n\nfunction readHeader(raw: RawHeaders, name: string): string | undefined {\n const value = raw[name];\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value[0];\n return undefined;\n}\n\n/**\n * How a pass-through request should be treated by the anonymous beacon:\n * - `never` — humans, static assets, and credentialed agents: no beacon.\n * - `platform` — a platform-fingerprinted agent (Claude/ChatGPT/Gemini/…):\n * beacon every time (unsampled) — these are exactly the\n * agents the dashboard's platform attribution exists for.\n * - `anonymous-bot` — non-browser automation with no platform signal:\n * beacon at the dashboard-configured sampling rate.\n */\nexport interface PassThroughTrafficClass {\n kind: 'never' | 'platform' | 'anonymous-bot';\n /** Detection protocol persisted with the beacon event. */\n protocol?: string;\n /** Light detection detail persisted with the beacon event. */\n evidence?: Record<string, unknown>;\n}\n\n/**\n * Classify one pass-through request for the anonymous beacon. Reuses the\n * edge classifier's heuristics (static-asset extensions, platform\n * fingerprints, browser-vs-bot UA shape) so the SDK and edge tiers agree on\n * what counts as agent traffic.\n */\nexport function classifyPassThroughTraffic(\n path: string,\n rawHeaders: RawHeaders\n): PassThroughTrafficClass {\n // Static assets: the beacon (like the gateway) gets out of the way.\n if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: 'never' };\n\n // Credentialed traffic is not anonymous — when a gated route sees these\n // credentials, verify-access records the caller; an unregistered-attempt\n // beacon would misfile it.\n const credentials = extractCredentials(rawHeaders, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { kind: 'never' };\n }\n\n const userAgent = readHeader(rawHeaders, 'user-agent') ?? '';\n\n // Platform-agent fingerprint (UA, credential key format, or a\n // platform-signal header) — a stronger, less-spoofable signal than the\n // UA alone, and it fires before the browser-shape check because several\n // platform agents present Mozilla-prefixed UAs.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);\n const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });\n if (fingerprint) {\n return {\n kind: 'platform',\n protocol: 'platform-ua',\n evidence: { vendor: fingerprint.vendor, userAgent: userAgent || '(none)' },\n };\n }\n\n // Bot-shaped: CLI/library UA, no UA at all, or any non-browser UA —\n // humans arrive with Mozilla-family UAs; everything else is automation.\n if (\n !userAgent ||\n _patterns.BOT_UA_PATTERN.test(userAgent) ||\n !_patterns.BROWSER_UA_PATTERN.test(userAgent)\n ) {\n return {\n kind: 'anonymous-bot',\n protocol: 'ua-heuristic',\n evidence: { userAgent: userAgent || '(none)' },\n };\n }\n\n // Claims to be a browser but sends none of the headers every evergreen\n // browser sends — headless/spoofed automation.\n if (!readHeader(rawHeaders, 'sec-fetch-mode') && !readHeader(rawHeaders, 'accept-language')) {\n return {\n kind: 'anonymous-bot',\n protocol: 'ua-heuristic',\n evidence: { userAgent, spoofedBrowser: true },\n };\n }\n\n // Human traffic — never beaconed, never logged.\n return { kind: 'never' };\n}\n\n/** Per-request input the middleware hands the beacon on a pass-through. */\nexport interface AnonymousBeaconInput {\n requestPath: string;\n requestMethod: string;\n /** Origin the SDK is protecting (auto-detected by the adapters). */\n counterpartyUrl?: string;\n /** Client IP as the adapter resolves it; falls back to X-Forwarded-For. */\n sourceIp?: string;\n rawHeaders: RawHeaders;\n}\n\n/** Fire-and-forget emitter — returns immediately, never throws. */\nexport type AnonymousBeaconEmitter = (input: AnonymousBeaconInput) => void;\n\n/**\n * Create the per-middleware-instance anonymous beacon.\n *\n * Requires a configured `counterpartyId` — sampling is a per-endpoint\n * dashboard setting and beacon events attribute to the endpoint; without\n * one, the returned emitter is a no-op.\n *\n * The emitter itself is synchronous: it classifies the request locally and\n * fire-and-forgets the report. The dashboard config is fetched in the\n * background (cached, stale-while-revalidate) and never awaited on the\n * request path; until the first config resolves, no beacons are emitted.\n */\nexport function createAnonymousBeacon(\n config: GatewayConfig,\n options?: {\n /** Counterparty type stamped on beacon events (adapter-specific default). */\n counterpartyType?: string;\n /** Injectable RNG for deterministic sampling in tests. */\n random?: () => number;\n }\n): AnonymousBeaconEmitter {\n const counterpartyId = config.counterpartyId;\n if (!counterpartyId) return () => {};\n\n const random = options?.random ?? Math.random;\n let edgeConfig: EdgeConfig | undefined;\n let refreshing = false;\n\n const refreshConfig = (): void => {\n if (refreshing) return;\n refreshing = true;\n getEdgeConfig(config, counterpartyId)\n .then((cfg) => {\n edgeConfig = cfg;\n })\n .catch(() => {})\n .finally(() => {\n refreshing = false;\n });\n };\n // Eager background fetch so early pass-through traffic already has a\n // sampling rate; requests arriving before it lands are simply not\n // beaconed (visibility is best-effort, latency is not negotiable).\n refreshConfig();\n\n return (input) => {\n try {\n // Keep the config fresh — getEdgeConfig serves its TTL cache and\n // revalidates in the background; this call is never awaited.\n refreshConfig();\n const cfg = edgeConfig;\n if (!cfg) return;\n\n const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);\n if (traffic.kind === 'never') return;\n if (traffic.kind === 'anonymous-bot' && !sampled(cfg.sampling.anonymousBeaconRate, random)) {\n return;\n }\n\n const userAgent = readHeader(input.rawHeaders, 'user-agent');\n const xff = input.rawHeaders['x-forwarded-for'];\n const xffStr = Array.isArray(xff) ? xff.join(', ') : xff;\n const sourceIp = input.sourceIp ?? xffStr?.split(',')[0]?.trim();\n\n reportUnregisteredAttempt(config, {\n ...(input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl }),\n counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? 'api',\n ...(sourceIp && { sourceIp }),\n ...(userAgent && { userAgent }),\n requestPath: input.requestPath,\n requestMethod: input.requestMethod,\n ...(traffic.protocol && { protocol: traffic.protocol }),\n ...(traffic.evidence && { evidence: traffic.evidence }),\n observedMetadata: buildSdkObservedMetadata(input.rawHeaders),\n }).catch(() => {});\n } catch {\n // The beacon must never break — or delay — the merchant's request.\n }\n };\n}\n","/**\n * AstraSync Universal Verification Gateway - Next.js Middleware\n *\n * Next.js middleware for verifying AI agents on web applications.\n * Serves the verification interstitial (an HTML overlay with registration\n * guidance) to unverified web-page traffic; API routes get structured JSON.\n *\n * @example\n * ```typescript\n * // middleware.ts\n * import { createMiddleware } from '@astrasyncai/verification-gateway/nextjs';\n *\n * export const middleware = createMiddleware({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * apiKey: process.env.ASTRASYNC_API_KEY,\n * counterpartyId: 'ASTRAE-...', // per-route policy is fetched from the dashboard\n * showInterstitial: true,\n * });\n *\n * export const config = {\n * matcher: ['/api/:path*', '/dashboard/:path*'],\n * };\n * ```\n */\n\nimport type { NextRequest } from 'next/server';\nimport type {\n NextJsMiddlewareOptions,\n AgentCredentials,\n VerificationResult,\n RouteAccessConfig,\n AstraSyncCredentials,\n VerificationRequest,\n StepUpOutcome,\n} from '../types';\nimport { awaitStepUpApproval } from './stepup-poll';\nimport { verify, reportCounterpartyPreCheckFailure, fetchRoutes } from '../verify';\nimport { extractHttpCredentials } from '../transport/http';\nimport { performCounterpartyPreCheck } from '../pdlss-pre-check';\nimport { buildSdkObservedMetadata } from '../metadata-capture';\nimport { createAnonymousBeacon } from './anonymous-beacon';\nimport { resolveHttpPdlss, type HttpPdlssResolution } from './http-pdlss';\nimport { requiresHumanApproval, annotateApprovalRequired } from './approval-gate';\nimport { MCP_VERIFIED_HOP_HEADER, parseVerifiedHop, isVerifiedHopValidFor } from '../verified-hop';\n\n/**\n * HTML-escape arbitrary string for safe interpolation into HTML text or\n * attribute values. Used by the interstitial HTML generator\n * to prevent reflected XSS from attacker-influenced denial messages.\n */\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Sanitize a URL for `href=`. Accepts only `http://` / `https://` schemes\n * (relative URLs allowed too); rejects `javascript:` / `data:` / `vbscript:`\n * and falls back to the supplied default on rejection. Then HTML-escapes\n * the result.\n */\nfunction sanitizeUrl(value: string | undefined, fallback: string): string {\n if (typeof value !== 'string' || value.length === 0) return escapeHtml(fallback);\n const trimmed = value.trim();\n if (/^javascript:|^data:|^vbscript:/i.test(trimmed)) return escapeHtml(fallback);\n if (/^https?:\\/\\//i.test(trimmed) || trimmed.startsWith('/')) {\n return escapeHtml(trimmed);\n }\n return escapeHtml(fallback);\n}\n\n/**\n * Extract credentials from Next.js request\n */\nfunction extractCredentialsFromNextRequest(request: NextRequest): AgentCredentials {\n const credentials: AgentCredentials = {};\n\n // Check for ASTRA-ID in headers\n const astraId = request.headers.get('x-astra-id') || request.headers.get('X-Astra-Id');\n if (astraId) {\n credentials.astraId = astraId;\n }\n\n // Check for API key\n const apiKey = request.headers.get('x-api-key') || request.headers.get('X-Api-Key');\n if (apiKey) {\n credentials.apiKey = apiKey;\n }\n\n // Check Authorization header\n const authHeader = request.headers.get('authorization');\n if (authHeader) {\n credentials.authorizationHeader = authHeader;\n if (authHeader.startsWith('Bearer ')) {\n credentials.jwt = authHeader.slice(7);\n }\n }\n\n // Check query parameters\n const url = new URL(request.url);\n const astraIdParam = url.searchParams.get('astraId');\n const apiKeyParam = url.searchParams.get('apiKey');\n\n if (astraIdParam && !credentials.astraId) {\n credentials.astraId = astraIdParam;\n }\n if (apiKeyParam && !credentials.apiKey) {\n credentials.apiKey = apiKeyParam;\n }\n\n return credentials;\n}\n\n/**\n * Match a route pattern against a path\n */\nfunction matchRoute(pattern: string, path: string): boolean {\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\//g, '\\\\/');\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(path);\n}\n\n/**\n * Find the route configuration for a request\n */\nfunction findRouteConfig(\n routes: RouteAccessConfig[],\n path: string,\n method: string\n): RouteAccessConfig | undefined {\n return routes.find((route) => {\n const methodMatches =\n route.method === '*' || route.method.toUpperCase() === method.toUpperCase();\n const pathMatches = matchRoute(route.pattern, path);\n return methodMatches && pathMatches;\n });\n}\n\n/**\n * Extract AstraSyncCredentials from Next.js request headers.\n * Returns null if no AstraSync headers are present.\n */\nfunction extractAstraSyncCredentialsFromNextRequest(\n request: NextRequest\n): AstraSyncCredentials | null {\n const headers: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return extractHttpCredentials(headers);\n}\n\n/**\n * Resolve the canonical {purpose, action} pair for a request.\n * Replaces the gen-1 method-inference (`read_data`/`write_data`) and the\n * hardwired verb action — the transport verb never travels as a PDLSS\n * action. Same resolver as the express adapter (http-pdlss.ts); nextjs has\n * no custom extractors and no query-param step (never existed here).\n */\nfunction resolveNextPdlss(\n request: NextRequest,\n routeConfig: { purpose?: string; action?: string } | null\n): HttpPdlssResolution {\n return resolveHttpPdlss({\n method: request.method,\n astraPurpose: request.headers.get('x-astra-purpose') ?? undefined,\n astraAction: request.headers.get('x-astra-action') ?? undefined,\n legacyPurpose: request.headers.get('x-purpose') ?? undefined,\n routePurpose: routeConfig?.purpose,\n routeAction: routeConfig?.action,\n });\n}\n\n/**\n * Generate the verification-interstitial HTML response served to unverified\n * web-page traffic.\n */\nfunction generateInterstitialHtml(\n result: VerificationResult,\n options: NextJsMiddlewareOptions\n): string {\n // result.guidance.message may quote attacker-controlled input from the\n // backend deny path (e.g. `Purpose \"<script>...\" is not in the allowed\n // list`). HTML-escape every interpolated value; validate URLs reject\n // non-http(s) schemes to prevent `javascript:` smuggling.\n const title = escapeHtml(options.commerceShield?.title || 'AstraSync Agent Verification');\n const message = escapeHtml(\n options.commerceShield?.message ||\n result.guidance?.message ||\n \"This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials.\"\n );\n const registrationUrl = sanitizeUrl(\n result.guidance?.registrationUrl,\n 'https://astrasync.ai/agents/register'\n );\n const docsUrl = sanitizeUrl(\n result.guidance?.documentationUrl,\n 'https://astrasync.ai/docs/agent-access'\n );\n const allowGuest = options.commerceShield?.allowGuestAccess ?? true;\n\n return `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${title}</title>\n <style>\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px;\n }\n .shield-container {\n background: rgba(255, 255, 255, 0.95);\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);\n max-width: 480px;\n width: 100%;\n padding: 40px;\n text-align: center;\n }\n .shield-icon {\n font-size: 48px;\n margin-bottom: 20px;\n }\n .shield-title {\n font-size: 24px;\n font-weight: 700;\n color: #1a1a2e;\n margin-bottom: 16px;\n }\n .shield-message {\n color: #4a5568;\n line-height: 1.6;\n margin-bottom: 24px;\n }\n .shield-steps {\n text-align: left;\n background: #f7fafc;\n border-radius: 8px;\n padding: 20px;\n margin-bottom: 24px;\n }\n .shield-steps h3 {\n font-size: 14px;\n font-weight: 600;\n color: #2d3748;\n margin-bottom: 12px;\n }\n .shield-steps ol {\n padding-left: 20px;\n color: #4a5568;\n }\n .shield-steps li {\n margin-bottom: 8px;\n }\n .shield-buttons {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n .btn {\n display: inline-block;\n padding: 14px 24px;\n border-radius: 8px;\n font-weight: 600;\n text-decoration: none;\n transition: all 0.2s;\n cursor: pointer;\n border: none;\n font-size: 16px;\n }\n .btn-primary {\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n color: white;\n }\n .btn-primary:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);\n }\n .btn-secondary {\n background: #e2e8f0;\n color: #4a5568;\n }\n .btn-secondary:hover {\n background: #cbd5e0;\n }\n .shield-footer {\n margin-top: 24px;\n font-size: 14px;\n color: #718096;\n }\n .shield-footer a {\n color: #6366f1;\n text-decoration: none;\n }\n .shield-footer a:hover {\n text-decoration: underline;\n }\n </style>\n</head>\n<body>\n <div class=\"shield-container\">\n <div class=\"shield-icon\">🛡️</div>\n <h1 class=\"shield-title\">${title}</h1>\n <p class=\"shield-message\">${message}</p>\n\n <div class=\"shield-steps\">\n <h3>To get verified access:</h3>\n <ol>\n <li>Register at <a href=\"${registrationUrl}\">astrasync.ai/agents/register</a></li>\n <li>Create and register your agent</li>\n <li>Add your ASTRA-ID to request headers</li>\n <li>Refresh this page</li>\n </ol>\n </div>\n\n <div class=\"shield-buttons\">\n <a href=\"${registrationUrl}\" class=\"btn btn-primary\">Register Now</a>\n ${allowGuest ? '<button onclick=\"window.location.reload()\" class=\"btn btn-secondary\">Continue as Guest (Limited)</button>' : ''}\n </div>\n\n <p class=\"shield-footer\">\n Learn more: <a href=\"${docsUrl}\">Agent Access Documentation</a>\n </p>\n </div>\n</body>\n</html>\n `.trim();\n}\n\nconst DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1000;\n\n/**\n * Create Next.js middleware for agent verification.\n *\n * v2.9.7 moved per-route policy out of merchant-side source code into the\n * AstraSync dashboard. The middleware fetches its routes from the backend\n * via `GET /endpoints/:counterpartyId/routes` on init and refreshes\n * periodically — see `ExpressMiddlewareOptions` for the rationale (a dual\n * config source silently conflicts with dashboard policy).\n */\nexport function createMiddleware(options: NextJsMiddlewareOptions) {\n // Guard against configs authored for pre-2.9.7 SDKs: a `routes` array in\n // merchant source is silently dead config — and dead route config means\n // the author believes paths are gated that aren't.\n if ('routes' in options) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway/Next.js] `routes` is dashboard-managed since v2.9.7; this option is ignored — ' +\n 'configure route policy in your AstraSync dashboard.'\n );\n }\n const {\n skipPaths = [],\n showInterstitial,\n showCommerceShield,\n enableRuntimeChallenge = true,\n routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,\n anonymousBeacon = true,\n trustVerifiedHop = false,\n verifiedHopMaxAgeMs,\n ...config\n } = options;\n\n // 4.1.0: `showInterstitial` supersedes the deprecated `showCommerceShield`\n // flag; the new name wins when both are set. Default remains true.\n const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;\n\n // Dashboard-driven anonymous-traffic beacon for the pass-through paths\n // (no matching route / route gated at `none`). Fire-and-forget: never\n // awaited, never delays the NextResponse. See ./anonymous-beacon.ts.\n const emitAnonymousBeacon = anonymousBeacon\n ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? 'website' })\n : undefined;\n const beaconPassThrough = emitAnonymousBeacon\n ? (request: NextRequest, pathname: string): void => {\n emitAnonymousBeacon({\n requestPath: pathname,\n requestMethod: request.method,\n counterpartyUrl: config.counterpartyUrl || request.nextUrl.origin,\n sourceIp: request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || undefined,\n rawHeaders: Object.fromEntries(request.headers.entries()),\n });\n }\n : undefined;\n\n let cachedRoutes: RouteAccessConfig[] = [];\n let lastFetchAt = 0;\n let refreshing: Promise<void> | null = null;\n let warnedNoCounterparty = false;\n\n async function refreshRoutes(): Promise<void> {\n if (!config.counterpartyId) {\n if (!warnedNoCounterparty) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway/Next.js] No counterpartyId configured — falling through (allow all). ' +\n 'Per-route policy lives in the AstraSync dashboard now; register the endpoint and ' +\n 'set counterpartyId in your middleware config to enforce policy.'\n );\n warnedNoCounterparty = true;\n }\n return;\n }\n const fetched = await fetchRoutes(config, config.counterpartyId);\n if (fetched) {\n cachedRoutes = fetched;\n lastFetchAt = Date.now();\n }\n }\n\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n\n return async function middleware(request: NextRequest) {\n // Dynamic import NextResponse to avoid build issues\n const { NextResponse } = await import('next/server');\n\n const pathname = request.nextUrl.pathname;\n\n // Check if path should be skipped\n const shouldSkip = skipPaths.some((pattern) => matchRoute(pattern, pathname));\n if (shouldSkip) {\n return NextResponse.next();\n }\n\n if (refreshing) {\n await refreshing.catch(() => {});\n }\n if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n }\n\n // Find route configuration (from remote-fetched cache)\n const routeConfig = findRouteConfig(cachedRoutes, pathname, request.method);\n\n // If no route config, allow through\n if (!routeConfig) {\n // Anonymous-traffic beacon: this request never reaches verify-access,\n // so bot/agent-shaped callers would otherwise be invisible to the\n // dashboard. Fire-and-forget — does not delay the response.\n beaconPassThrough?.(request, pathname);\n return NextResponse.next();\n }\n\n // Observe-only route: pass through unenforced.\n if (routeConfig.observe) {\n // Anonymous-traffic beacon (see the no-route-match branch above).\n beaconPassThrough?.(request, pathname);\n return NextResponse.next();\n }\n\n // Extract credentials\n const credentials = extractCredentialsFromNextRequest(request);\n\n // Inner-hop dedupe: a trusted upstream AstraSync hop (edge gateway or\n // MCP outer hop) already verified this exact ASTRA-id moments ago —\n // accept the fresh marker and skip the duplicate verify-access call.\n // Mirrors the express/MCP adapter contract. The marker must match the\n // request's own X-Astra-Id.\n if (trustVerifiedHop && credentials.astraId) {\n const marker = parseVerifiedHop(request.headers.get(MCP_VERIFIED_HOP_HEADER) ?? undefined);\n if (\n isVerifiedHopValidFor(marker, credentials.astraId, {\n ...(verifiedHopMaxAgeMs !== undefined ? { maxAgeMs: verifiedHopMaxAgeMs } : {}),\n })\n ) {\n return NextResponse.next();\n }\n }\n\n // v2.3.0: anonymous traffic no longer short-circuits client-side.\n // The server applies the endpoint's `unverifiedAgentPolicy` (deny /\n // allow_partial / allow_full) and emits the verification event +\n // blockchain record per the canonical flow. SDK forwards verbatim.\n\n // Auto-detect counterparty URL from the request if not explicitly configured.\n // Since the SDK is installed at this endpoint, we always know the origin.\n const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;\n\n // Resolve the canonical {purpose, action} pair (Bug 14, §4.6) and full\n // AstraSync credentials (includes PDLSS from X-Astra-* headers)\n const pdlssPair = resolveNextPdlss(request, routeConfig);\n const purpose = pdlssPair.purpose;\n if (config.debug) {\n // eslint-disable-next-line no-console\n console.debug('[nextjs-middleware] pdlss resolved', {\n purpose_source: pdlssPair.purposeSource,\n resolved_purpose: pdlssPair.purpose,\n action_source: pdlssPair.actionSource,\n resolved_action: pdlssPair.action,\n });\n }\n const astraCreds = extractAstraSyncCredentialsFromNextRequest(request);\n\n // Step 2: Counterparty-side PDLSS pre-check — compare agent's requested PDLSS\n // against counterparty-defined maximums on the route config.\n // Rejects immediately if outside limits, BEFORE calling verify-access.\n const preCheckFailures = performCounterpartyPreCheck(routeConfig, astraCreds, purpose);\n if (preCheckFailures.length > 0) {\n // Round-18 G4: counterparty pre-check failure — see express.ts for the\n // rationale. Neither axis verified remotely → both false.\n const preCheckResult: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: preCheckFailures.map((f) => f.message),\n guidance: {\n message: 'Request exceeds counterparty-defined PDLSS limits.',\n registrationUrl: `${config.apiBaseUrl?.replace('/api', '')}/agents/register`,\n documentationUrl: `${config.apiBaseUrl?.replace('/api', '')}/docs/pdlss`,\n },\n verifiedAt: new Date(),\n };\n\n // Fire-and-forget: notify AstraSync of the pre-check failure\n reportCounterpartyPreCheckFailure(config, {\n agentId: astraCreds?.agentId || credentials.astraId || 'unknown',\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'website',\n failures: preCheckFailures,\n requestPath: pathname,\n requestMethod: request.method,\n }).catch(() => {});\n\n // For API routes, return JSON\n if (pathname.startsWith('/api/')) {\n return NextResponse.json(\n {\n success: false,\n error: {\n code: 'PDLSS_PRE_CHECK_FAILED',\n message: preCheckResult.denialReasons?.[0] || 'PDLSS pre-check failed',\n guidance: preCheckResult.guidance,\n },\n },\n { status: 403 }\n );\n }\n\n // For web pages, show the verification interstitial\n if (interstitialEnabled) {\n return new NextResponse(generateInterstitialHtml(preCheckResult, options), {\n status: 200,\n headers: {\n 'Content-Type': 'text/html',\n 'X-AstraSync-Verification': 'commerce-shield',\n },\n });\n }\n\n return NextResponse.redirect(new URL('/unauthorized', request.url));\n }\n\n // Step 3: Call AstraSync verify-access with runtime challenge enabled\n const forwardedFor = request.headers.get('x-forwarded-for') || undefined;\n const originalClientIp = forwardedFor?.split(',')[0]?.trim();\n const verificationRequest: VerificationRequest = {\n credentials,\n purpose,\n action: pdlssPair.action,\n resource: pathname,\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'website',\n enableRuntimeChallenge,\n durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,\n callerMetadata: {\n sourceIp: originalClientIp,\n userAgent: request.headers.get('user-agent') || undefined,\n referer: request.headers.get('referer') || undefined,\n host: request.headers.get('host') || undefined,\n forwardedFor,\n agentCardUrl: request.headers.get('x-astrasync-agent-card') || undefined,\n // Workstream D — full sanitised header capture + CDN-derived\n // connection block (Web Headers → plain map).\n observedMetadata: buildSdkObservedMetadata(Object.fromEntries(request.headers.entries())),\n },\n };\n let result = await verify(config, verificationRequest);\n\n // 3.6.0 hold-and-poll (opt-in via stepUpMaxWaitMs) — see express.ts for\n // the full rationale. CAUTION on edge runtimes (~25s wall-clock budget):\n // set a small stepUpMaxWaitMs or gate in a Node route handler instead.\n // On 'approved' the same request is re-verified once, cache-bypassed, so\n // the backend redeems the single-use approval.\n let stepUpHoldOutcome: StepUpOutcome | undefined;\n if (\n config.stepUpMaxWaitMs !== undefined &&\n result.policyAllowed &&\n requiresHumanApproval(result) &&\n result.stepUpApproval?.pollUrl\n ) {\n stepUpHoldOutcome = await awaitStepUpApproval(config, result.stepUpApproval);\n if (stepUpHoldOutcome === 'approved') {\n result = await verify(config, verificationRequest, { bypassCache: true });\n } else {\n result.stepUpOutcome = stepUpHoldOutcome;\n }\n }\n\n // Round-18 G4: short-circuit on either axis failing (identity-fail or\n // policy-fail) — both encode the server-side trust-floor + PDLSS decision.\n // The access decision rests on a verified ID + runtime challenge + PDLSS\n // match + trust score; there is no access-level band (removed in SDK 5.0.0).\n // Per-route tightening is `route.minTrustScore` (below).\n // F2 direct-path fail-closed: a step-up / requires-approval outcome\n // (policyAllowed:true, allowed-but-escalate) cannot be completed\n // autonomously — deny and surface stepUpApproval polling info.\n // 4.5.0: gate on the SERVER decision only (`policyAllowed`) — anonymous\n // callers allowed by an audit/allow endpoint policy are honestly\n // identity-unverified; see express.ts for the full rationale.\n const approvalRequired = result.policyAllowed && requiresHumanApproval(result);\n if (approvalRequired) annotateApprovalRequired(result);\n\n if (!result.policyAllowed || approvalRequired) {\n // 4.0.0 BREAKING (API routes): this site's OWN key was rejected —\n // answer 503 with the dedicated code so agents don't read a merchant\n // misconfig as their own auth failure (see express.defaultOnDenied).\n // Web pages keep their existing shield/redirect flow — a human page\n // view must not turn into raw JSON because the operator rotated a key.\n if (result.misconfigured && pathname.startsWith('/api/')) {\n return NextResponse.json(\n {\n success: false,\n error: {\n code: 'MERCHANT_VERIFICATION_MISCONFIGURED',\n message:\n result.denialReasons?.[0] || \"This site's AstraSync integration is misconfigured\",\n guidance: result.guidance,\n failures: result.failures,\n correlationId: result.correlationId,\n },\n },\n { status: 503 }\n );\n }\n\n // For API routes, return JSON\n if (pathname.startsWith('/api/')) {\n return NextResponse.json(\n {\n success: false,\n error: {\n // Round-18 G4: 401 → identity missing (re-auth); 403 → identity\n // OK, policy denied (update PDLSS / step up).\n code: !result.identityVerified ? 'UNAUTHORIZED' : 'POLICY_DENIED',\n message: result.denialReasons?.[0] || 'Access denied',\n guidance: result.guidance,\n failures: result.failures,\n stepUpApproval: result.stepUpApproval,\n // 3.6.0: terminal outcome of an opt-in hold-and-poll wait.\n ...(result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }),\n },\n },\n {\n status: !result.identityVerified ? 401 : 403,\n ...(stepUpHoldOutcome && {\n headers: { 'X-Astra-Step-Up': stepUpHoldOutcome },\n }),\n }\n );\n }\n\n // For web pages, show the verification interstitial\n if (interstitialEnabled) {\n return new NextResponse(generateInterstitialHtml(result, options), {\n status: 200,\n headers: {\n 'Content-Type': 'text/html',\n 'X-AstraSync-Verification': 'commerce-shield',\n },\n });\n }\n\n // Redirect to unauthorized page\n return NextResponse.redirect(new URL('/unauthorized', request.url));\n }\n\n // All checks passed - continue with verification info in headers\n const response = NextResponse.next();\n\n // Add verification info to response headers\n // Round-18 G4: composite `verified` (identity AND policy) for legacy\n // header consumers; new headers expose each axis separately so middleware\n // chains can branch without re-running verify-access.\n response.headers.set(\n 'X-AstraSync-Verified',\n (result.identityVerified && result.policyAllowed).toString()\n );\n if (stepUpHoldOutcome) {\n response.headers.set('X-Astra-Step-Up', stepUpHoldOutcome);\n }\n response.headers.set('X-AstraSync-Identity-Verified', result.identityVerified.toString());\n response.headers.set('X-AstraSync-Policy-Allowed', result.policyAllowed.toString());\n\n if (result.agent) {\n response.headers.set('X-AstraSync-Agent-Id', result.agent.astraId);\n // 3.2.0 (post-3.1.0 feedback #2): the X-AstraSync-Trust-Score header is\n // no longer emitted — trust is a system-internal signal and this header\n // rode on the passthrough response toward the agent (gaming vector).\n }\n\n return response;\n };\n}\n\n/**\n * Helper to create matcher config\n */\nexport function createMatcherConfig(paths: string[]): { matcher: string[] } {\n return { matcher: paths };\n}\n","/**\n * AstraSync Universal Verification Gateway - SDK Adapter\n *\n * Direct SDK for verifying agents in any JavaScript/TypeScript environment.\n * Useful for agent-to-agent verification, serverless functions, or custom integrations.\n *\n * @example\n * ```typescript\n * import { createClient } from '@astrasyncai/verification-gateway/sdk';\n *\n * const gateway = createClient({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * });\n *\n * // Verify another agent before interacting\n * const result = await gateway.verify({\n * astraId: 'ASTRA-abc123',\n * purpose: 'data-exchange',\n * });\n *\n * if (result.identityVerified && result.policyAllowed) {\n * // Safe to interact with this agent\n * }\n * ```\n */\n\nimport type {\n SDKOptions,\n AgentCredentials,\n VerificationResult,\n VerificationRequest,\n GatewayConfig,\n} from '../types';\nimport { verify as coreVerify, quickVerify as coreQuickVerify, clearCache } from '../verify';\nimport { getTrustLevel } from '../trust-levels';\n\n/**\n * Verification Gateway SDK Client\n */\nexport class VerificationGatewayClient {\n private config: GatewayConfig;\n private timeout: number;\n private retryConfig: { maxRetries: number; backoffMs: number };\n\n constructor(options: SDKOptions) {\n this.config = {\n apiBaseUrl: options.apiBaseUrl,\n apiKey: options.apiKey,\n minTrustScore: options.minTrustScore,\n minTrustScoreForFull: options.minTrustScoreForFull,\n cacheTtl: options.cacheTtl,\n debug: options.debug,\n customHeaders: options.customHeaders,\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: options.counterpartyType,\n // 5.4.1 (UAT2): previously dropped here despite being a typed, documented\n // GatewayConfig field — a client-driven confirmCheckout() could never\n // identify its endpoint by ASTRAE id, so merchants with multiple\n // endpoints on one origin (or a stale row sharing the URL) resolved\n // non-deterministically by URL and could miss the first-party gate.\n counterpartyId: options.counterpartyId,\n };\n\n this.timeout = options.timeout || 10000;\n this.retryConfig = options.retry || { maxRetries: 3, backoffMs: 1000 };\n }\n\n /**\n * Full verification with all details\n */\n async verify(options: {\n astraId?: string;\n apiKey?: string;\n jwt?: string;\n purpose?: string;\n action?: string;\n resourceType?: string;\n resource?: string;\n jurisdiction?: string;\n transactionValue?: number;\n currency?: string;\n isSubAgentRequest?: boolean;\n parentAgentId?: string;\n subAgentDepth?: number;\n counterpartyUrl?: string;\n counterpartyType?: string;\n }): Promise<VerificationResult> {\n const credentials: AgentCredentials = {\n astraId: options.astraId,\n apiKey: options.apiKey,\n jwt: options.jwt,\n };\n\n return this.executeWithRetry(() =>\n coreVerify(this.config, {\n credentials,\n purpose: options.purpose,\n action: options.action,\n resourceType: options.resourceType,\n resource: options.resource,\n jurisdiction: options.jurisdiction,\n transactionValue: options.transactionValue,\n currency: options.currency,\n isSubAgentRequest: options.isSubAgentRequest,\n parentAgentId: options.parentAgentId,\n subAgentDepth: options.subAgentDepth,\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: options.counterpartyType as VerificationRequest['counterpartyType'],\n })\n );\n }\n\n /**\n * 5.4.0 (astra-pay): confirm-leg of a checkout — the ONLY call that may fire\n * first-party charge-at-redeem (server-side settlement on the owner's saved\n * instrument). This is the supported public surface for the confirm leg;\n * `verify()` deliberately does not expose the checkout fields, so settlement\n * can never fire by accident from a generic verify.\n *\n * Sends `commercePhase: 'confirm'` plus the checkout session id (per-cart\n * idempotency) and line items (order/receipt plane), and identifies the\n * merchant via `counterpartyUrl`/`counterpartyType` (required — the backend\n * only settles a merchant-mediated grant against a first-party storefront).\n * `purpose`/`action` default to the canonical shopping pair.\n *\n * Returns the full `VerificationResult`: read `.settlementOutcome` for the\n * settled/failed/requires_action/no_instrument outcome (+ `orderId`), and the\n * identity/policy/`failures` fields for a denial. On any non-`confirm`/first-\n * party path `settlementOutcome` is simply absent — no money moves.\n */\n async confirmCheckout(options: {\n astraId?: string;\n apiKey?: string;\n jwt?: string;\n purpose?: string;\n action?: string;\n transactionValue?: number;\n currency?: string;\n checkoutSessionId?: string;\n checkoutItems?: VerificationRequest['checkoutItems'];\n counterpartyUrl?: string;\n counterpartyType?: string;\n }): Promise<VerificationResult> {\n const credentials: AgentCredentials = {\n astraId: options.astraId,\n apiKey: options.apiKey,\n jwt: options.jwt,\n };\n\n return this.executeWithRetry(() =>\n coreVerify(\n this.config,\n {\n credentials,\n purpose: options.purpose ?? 'shopping',\n action: options.action ?? 'shopping.purchase',\n transactionValue: options.transactionValue,\n currency: options.currency,\n commercePhase: 'confirm',\n checkoutSessionId: options.checkoutSessionId,\n checkoutItems: options.checkoutItems,\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: options.counterpartyType as VerificationRequest['counterpartyType'],\n },\n // 5.4.1 (UAT2 Bug B): the confirm leg must always reach the backend —\n // a cached quote-leg grant carries no settlementOutcome and would\n // silently skip settlement.\n { bypassCache: true }\n )\n );\n }\n\n /**\n * Quick verification — checks credentials and policy in one call.\n *\n * The return shape mirrors `VerificationResult`'s identity/policy\n * split. Map to HTTP status the same way: `!identityVerified` → 401,\n * `identityVerified && !policyAllowed` → 403.\n */\n async quickVerify(credentials: { astraId?: string; apiKey?: string; jwt?: string }): Promise<{\n identityVerified: boolean;\n policyAllowed: boolean;\n reason?: string;\n }> {\n return this.executeWithRetry(() => coreQuickVerify(this.config, credentials));\n }\n\n /**\n * Verify a specific ASTRA-ID\n */\n async verifyAstraId(\n astraId: string,\n options?: {\n purpose?: string;\n action?: string;\n }\n ): Promise<VerificationResult> {\n return this.verify({\n astraId,\n purpose: options?.purpose,\n action: options?.action,\n });\n }\n\n /**\n * Verify using an API key\n */\n async verifyApiKey(\n apiKey: string,\n options?: {\n purpose?: string;\n action?: string;\n }\n ): Promise<VerificationResult> {\n return this.verify({\n apiKey,\n purpose: options?.purpose,\n action: options?.action,\n });\n }\n\n /**\n * Clear the verification cache\n */\n clearCache(): void {\n clearCache();\n }\n\n /**\n * Execute a function with retry logic\n */\n private async executeWithRetry<T>(fn: () => Promise<T>): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {\n try {\n // Add timeout\n const result = await Promise.race([\n fn(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Request timeout')), this.timeout)\n ),\n ]);\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on last attempt\n if (attempt < this.retryConfig.maxRetries) {\n // Exponential backoff\n const backoff = this.retryConfig.backoffMs * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, backoff));\n }\n }\n }\n\n throw lastError || new Error('Verification failed after retries');\n }\n}\n\n/**\n * Create a new SDK client\n */\nexport function createClient(options: SDKOptions): VerificationGatewayClient {\n return new VerificationGatewayClient(options);\n}\n\n/**\n * One-shot verification without creating a client\n */\nexport async function verifyOnce(\n options: SDKOptions & {\n astraId?: string;\n apiKey?: string;\n jwt?: string;\n purpose?: string;\n action?: string;\n }\n): Promise<VerificationResult> {\n const client = createClient(options);\n return client.verify(options);\n}\n\n// Re-export utilities for convenience\nexport { getTrustLevel };\n","/**\n * Cross-Protocol Transport Module\n *\n * Provides adapters for injecting/extracting AstraSync credentials\n * across HTTP, A2A, and MCP protocols.\n */\n\nimport type { AstraSyncCredentials, ProtocolTransport } from '../types';\nimport { setHttpHeaders, extractHttpCredentials } from './http';\nimport { setA2AMetadata, extractA2ACredentials } from './a2a';\nimport { setMcpMeta, extractMcpCredentials } from './mcp';\n\nexport { setHttpHeaders, extractHttpCredentials } from './http';\nexport { setA2AMetadata, extractA2ACredentials } from './a2a';\nexport { setMcpMeta, extractMcpCredentials } from './mcp';\n\n// Commerce protocol extractors + verifiers (PR 4+5)\nexport * from './purpose-mapping';\nexport * from './transaction-value';\nexport * from './rfc9421';\nexport * from './rfc9421-verify';\nexport * from './ucp';\nexport * from './acp';\nexport * from './vi';\nexport * from './stripe-webhook';\nexport * from './constraint-eval';\nexport * from './identity-binding';\nexport * from './ap2';\nexport * from './ap2-verify';\nexport * from './acp-verify';\nexport * from './mpp';\nexport * from './mpp-verify';\nexport * from './x402';\nexport * from './vi-verify';\nexport * from './commerce-pipeline';\nexport * from './extractor-registry';\nexport * from './registry/types';\nexport { createVisaRegistry } from './registry/visa';\nexport { createMastercardRegistry } from './registry/mastercard';\nexport { createWebBotAuthRegistry } from './registry/web-bot-auth';\n\n/**\n * Auto-detect protocol from request/context shape.\n */\nexport function detectProtocol(context: Record<string, unknown>): ProtocolTransport {\n // A2A: has metadata block with task-like structure\n if (context.metadata && typeof context.metadata === 'object') {\n return 'a2a';\n }\n\n // MCP: has _meta block (MCP convention)\n if (context._meta && typeof context._meta === 'object') {\n return 'mcp';\n }\n\n // Default to HTTP\n return 'http';\n}\n\n/**\n * Apply credentials to any protocol target.\n */\nexport function applyCredentials(\n protocol: ProtocolTransport,\n target: Record<string, unknown>,\n credentials: AstraSyncCredentials\n): Record<string, unknown> {\n switch (protocol) {\n case 'http':\n return setHttpHeaders(target as Record<string, string>, credentials);\n case 'a2a':\n return setA2AMetadata(target, credentials);\n case 'mcp':\n return setMcpMeta(target, credentials);\n default:\n return target;\n }\n}\n\n/**\n * Extract credentials from any protocol context.\n */\nexport function extractCredentialsFromProtocol(\n protocol: ProtocolTransport,\n context: Record<string, unknown>\n): AstraSyncCredentials | null {\n switch (protocol) {\n case 'http':\n return extractHttpCredentials(context as Record<string, string | string[] | undefined>);\n case 'a2a':\n return extractA2ACredentials(context);\n case 'mcp':\n return extractMcpCredentials(context);\n default:\n return null;\n }\n}\n","/**\n * A2A (Agent-to-Agent) Transport Adapter\n *\n * Maps AstraSync credentials to/from A2A task metadata.astrasync block.\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\ninterface A2ATask {\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface AstraSyncMetadata {\n agentId: string;\n verifyUrl?: string;\n challengeUrl?: string;\n purpose?: { category: string; action?: string };\n duration?: { maxSessionDuration?: number };\n scope?: { jurisdiction?: string };\n}\n\n/**\n * Add AstraSync credentials to an A2A task's metadata block.\n */\nexport function setA2AMetadata(\n task: A2ATask,\n credentials: AstraSyncCredentials,\n): A2ATask {\n const astrasync: AstraSyncMetadata = {\n agentId: credentials.agentId,\n };\n\n if (credentials.verifyUrl) astrasync.verifyUrl = credentials.verifyUrl;\n if (credentials.challengeUrl) astrasync.challengeUrl = credentials.challengeUrl;\n if (credentials.pdlss?.purpose) astrasync.purpose = credentials.pdlss.purpose;\n if (credentials.pdlss?.duration) astrasync.duration = credentials.pdlss.duration;\n if (credentials.pdlss?.scope) astrasync.scope = credentials.pdlss.scope;\n\n return {\n ...task,\n metadata: {\n ...task.metadata,\n astrasync,\n },\n };\n}\n\n/**\n * Extract AstraSync credentials from an A2A task's metadata block.\n */\nexport function extractA2ACredentials(task: A2ATask): AstraSyncCredentials | null {\n const meta = task.metadata?.astrasync as AstraSyncMetadata | undefined;\n if (!meta?.agentId) return null;\n\n const credentials: AstraSyncCredentials = {\n agentId: meta.agentId,\n };\n\n if (meta.verifyUrl) credentials.verifyUrl = meta.verifyUrl;\n if (meta.challengeUrl) credentials.challengeUrl = meta.challengeUrl;\n\n if (meta.purpose || meta.duration || meta.scope) {\n credentials.pdlss = {};\n if (meta.purpose) credentials.pdlss.purpose = meta.purpose;\n if (meta.duration) credentials.pdlss.duration = meta.duration;\n if (meta.scope) credentials.pdlss.scope = meta.scope;\n }\n\n return credentials;\n}\n","/**\n * MCP (Model Context Protocol) Transport Adapter\n *\n * Maps AstraSync credentials to/from MCP params._meta.astrasync block.\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\ninterface McpParams {\n _meta?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface AstraSyncMeta {\n agentId: string;\n verifyUrl?: string;\n challengeUrl?: string;\n purpose?: { category: string; action?: string };\n duration?: { maxSessionDuration?: number };\n scope?: { jurisdiction?: string };\n}\n\n/**\n * Add AstraSync credentials to MCP params' _meta block.\n */\nexport function setMcpMeta(\n params: McpParams,\n credentials: AstraSyncCredentials,\n): McpParams {\n const astrasync: AstraSyncMeta = {\n agentId: credentials.agentId,\n };\n\n if (credentials.verifyUrl) astrasync.verifyUrl = credentials.verifyUrl;\n if (credentials.challengeUrl) astrasync.challengeUrl = credentials.challengeUrl;\n if (credentials.pdlss?.purpose) astrasync.purpose = credentials.pdlss.purpose;\n if (credentials.pdlss?.duration) astrasync.duration = credentials.pdlss.duration;\n if (credentials.pdlss?.scope) astrasync.scope = credentials.pdlss.scope;\n\n return {\n ...params,\n _meta: {\n ...params._meta,\n astrasync,\n },\n };\n}\n\n/**\n * Extract AstraSync credentials from MCP params' _meta block.\n */\nexport function extractMcpCredentials(params: McpParams): AstraSyncCredentials | null {\n const meta = params._meta?.astrasync as AstraSyncMeta | undefined;\n if (!meta?.agentId) return null;\n\n const credentials: AstraSyncCredentials = {\n agentId: meta.agentId,\n };\n\n if (meta.verifyUrl) credentials.verifyUrl = meta.verifyUrl;\n if (meta.challengeUrl) credentials.challengeUrl = meta.challengeUrl;\n\n if (meta.purpose || meta.duration || meta.scope) {\n credentials.pdlss = {};\n if (meta.purpose) credentials.pdlss.purpose = meta.purpose;\n if (meta.duration) credentials.pdlss.duration = meta.duration;\n if (meta.scope) credentials.pdlss.scope = meta.scope;\n }\n\n return credentials;\n}\n","/**\n * Protocol request -> AstraSync PDLSS purpose category mapping.\n *\n * Commerce purpose mapping table, extended with MPP + x402\n * entries (April 2026 protocol landscape).\n */\n\nexport type CommercePurpose =\n | 'commerce.checkout.create'\n | 'commerce.checkout.update'\n | 'commerce.checkout.confirm'\n | 'commerce.checkout.cancel'\n | 'commerce.payment.execute'\n | 'commerce.payment.stream'\n | 'commerce.delegation.intent'\n | 'commerce.delegation.checkout'\n | 'commerce.delegation.payment'\n | 'commerce.identity_probe'\n | 'commerce.browsing';\n\nconst UCP_ROUTES: Array<{ method: string; pattern: RegExp; purpose: CommercePurpose }> = [\n { method: 'POST', pattern: /^\\/checkout[-_]sessions\\/?$/, purpose: 'commerce.checkout.create' },\n {\n method: 'PUT',\n pattern: /^\\/checkout[-_]sessions\\/[^/]+\\/?$/,\n purpose: 'commerce.checkout.update',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout[-_]sessions\\/[^/]+\\/complete\\/?$/,\n purpose: 'commerce.payment.execute',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout[-_]sessions\\/[^/]+\\/cancel\\/?$/,\n purpose: 'commerce.checkout.cancel',\n },\n];\n\nconst ACP_ROUTES: Array<{ method: string; pattern: RegExp; purpose: CommercePurpose }> = [\n { method: 'POST', pattern: /^\\/checkout_sessions\\/?$/, purpose: 'commerce.checkout.create' },\n {\n method: 'POST',\n pattern: /^\\/checkout_sessions\\/[^/]+\\/?$/,\n purpose: 'commerce.checkout.update',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout_sessions\\/[^/]+\\/complete\\/?$/,\n purpose: 'commerce.payment.execute',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout_sessions\\/[^/]+\\/cancel\\/?$/,\n purpose: 'commerce.checkout.cancel',\n },\n {\n method: 'POST',\n pattern: /^\\/agentic_commerce\\/delegate_payment\\/?$/,\n purpose: 'commerce.delegation.payment',\n },\n];\n\nexport function mapUCPRequestToPurpose(method: string, path: string): CommercePurpose | null {\n const normalizedMethod = method.toUpperCase();\n const normalizedPath = stripQuery(path);\n for (const route of UCP_ROUTES) {\n if (route.method === normalizedMethod && route.pattern.test(normalizedPath)) {\n return route.purpose;\n }\n }\n return null;\n}\n\nexport function mapACPRequestToPurpose(method: string, path: string): CommercePurpose | null {\n const normalizedMethod = method.toUpperCase();\n const normalizedPath = stripQuery(path);\n for (const route of ACP_ROUTES) {\n if (route.method === normalizedMethod && route.pattern.test(normalizedPath)) {\n return route.purpose;\n }\n }\n return null;\n}\n\nexport type AP2MandateType = 'intent_mandate' | 'cart_mandate' | 'payment_mandate';\nexport function mapAP2MandateToPurpose(mandateType: AP2MandateType): CommercePurpose {\n switch (mandateType) {\n case 'intent_mandate':\n return 'commerce.delegation.intent';\n case 'cart_mandate':\n return 'commerce.checkout.confirm';\n case 'payment_mandate':\n return 'commerce.payment.execute';\n }\n}\n\nexport type VIMandateType = 'checkout' | 'payment' | 'checkout.open' | 'payment.open';\nexport function mapVIMandateToPurpose(mandateType: VIMandateType): CommercePurpose {\n switch (mandateType) {\n case 'checkout':\n return 'commerce.checkout.confirm';\n case 'payment':\n return 'commerce.payment.execute';\n case 'checkout.open':\n return 'commerce.delegation.checkout';\n case 'payment.open':\n return 'commerce.delegation.payment';\n }\n}\n\nexport type RFC9421Tag = 'browse' | 'purchase' | undefined;\nexport function mapRFC9421TagToPurpose(tag: RFC9421Tag): CommercePurpose {\n if (tag === 'purchase') return 'commerce.payment.execute';\n return 'commerce.browsing';\n}\n\nexport type MPPIntent = 'charge' | 'session';\nexport function mapMPPRequestToPurpose(\n intent: MPPIntent | undefined,\n amount: number | undefined\n): CommercePurpose {\n if (typeof amount === 'number' && amount === 0) return 'commerce.identity_probe';\n if (intent === 'session') return 'commerce.payment.stream';\n return 'commerce.payment.execute';\n}\n\nexport function mapX402RequestToPurpose(amount: number | undefined): CommercePurpose {\n if (typeof amount === 'number' && amount === 0) return 'commerce.identity_probe';\n return 'commerce.payment.execute';\n}\n\nfunction stripQuery(path: string): string {\n const q = path.indexOf('?');\n return q === -1 ? path : path.slice(0, q);\n}\n\n/**\n * Informational Stripe webhook events surfaced as trust signals on\n * `CommerceContext.trustSignals` but NOT routed to a PDLSS purpose.\n */\nexport const STRIPE_WEBHOOK_INFORMATIONAL_EVENTS = [\n 'payment_intent.succeeded',\n 'payment_intent.payment_failed',\n 'charge.refunded',\n 'checkout.session.completed',\n 'customer.subscription.created',\n] as const;\nexport type StripeWebhookInformationalEvent = (typeof STRIPE_WEBHOOK_INFORMATIONAL_EVENTS)[number];\n\nexport function isStripeWebhookInformational(eventType: string): boolean {\n return (STRIPE_WEBHOOK_INFORMATIONAL_EVENTS as readonly string[]).includes(eventType);\n}\n","/**\n * Per-protocol transaction-value normalization.\n *\n * Each protocol encodes amount/currency differently. This module produces a\n * uniform `TransactionValueContext` with `source` recording the extraction\n * path so trace logs can show where the value came from.\n *\n * Amount unit: \"major units\" (dollars/euros/etc. for fiat; native unit for\n * tokens — we do NOT convert across currencies). UCP/ACP totals are in\n * cents, so we divide by 100. MPP/x402/VI pass through as declared.\n */\n\nexport interface TransactionValueContext {\n protocol: 'vi' | 'ap2' | 'ucp' | 'acp' | 'mpp' | 'x402' | 'agentpay' | 'tap';\n amount: number;\n currency: string;\n source: string;\n /** When true, the amount is in raw atomic/minor units and could NOT be\n * converted to major units (unknown token decimals). The limit engine\n * must fail-closed — never compare raw units against major-unit limits. */\n rawUnits?: boolean;\n}\n\nexport function extractUCPTransactionValue(input: {\n totals?: Array<{ type?: string; amount?: number; currency?: string }>;\n}): TransactionValueContext | null {\n const totals = input.totals ?? [];\n const total = totals.find((t) => t.type === 'total') ?? totals[0];\n if (!total || typeof total.amount !== 'number' || !total.currency) return null;\n return {\n protocol: 'ucp',\n amount: total.amount / 100,\n currency: total.currency,\n source: `totals[type=${total.type ?? 'unknown'}].amount`,\n };\n}\n\nexport function extractACPTransactionValue(input: {\n totals?: Array<{ type?: string; amount?: number; currency?: string }>;\n}): TransactionValueContext | null {\n const totals = input.totals ?? [];\n const total = totals.find((t) => t.type === 'total') ?? totals[0];\n if (!total || typeof total.amount !== 'number' || !total.currency) return null;\n return {\n protocol: 'acp',\n amount: total.amount / 100,\n currency: total.currency,\n source: `totals[type=${total.type ?? 'unknown'}].amount`,\n };\n}\n\nexport interface VIClaimsForValue {\n constraints?: {\n paymentAmount?: { currency?: string; min?: number; max?: number };\n };\n l3aPaymentAmount?: { currency?: string; amount?: number };\n}\n\nexport function extractVITransactionValue(\n claims: VIClaimsForValue\n): TransactionValueContext | null {\n const l3a = claims.l3aPaymentAmount;\n if (l3a && typeof l3a.amount === 'number' && l3a.currency) {\n return {\n protocol: 'vi',\n amount: l3a.amount,\n currency: l3a.currency,\n source: 'L3a.payment.amount',\n };\n }\n const bound = claims.constraints?.paymentAmount;\n if (bound && typeof bound.max === 'number' && bound.currency) {\n return {\n protocol: 'vi',\n amount: bound.max,\n currency: bound.currency,\n source: 'L2.payment.constraints.amount.max',\n };\n }\n return null;\n}\n\nexport interface AP2PaymentMandateForValue {\n payment_details_total?: { amount?: { value?: string | number; currency?: string } };\n}\n\nexport function extractAP2TransactionValue(\n mandate: AP2PaymentMandateForValue | undefined\n): TransactionValueContext | null {\n const amt = mandate?.payment_details_total?.amount;\n if (!amt || !amt.currency) return null;\n const n = typeof amt.value === 'string' ? Number(amt.value) : amt.value;\n if (typeof n !== 'number' || !Number.isFinite(n)) return null;\n return {\n protocol: 'ap2',\n amount: n,\n currency: amt.currency,\n source: 'payment_mandate.payment_details_total.amount',\n };\n}\n\nexport interface MPPChallengeForValue {\n method?: string;\n request?: { amount?: number; currency?: string } & Record<string, unknown>;\n}\n\nexport function extractMPPTransactionValue(\n challenge: MPPChallengeForValue\n): TransactionValueContext | null {\n const req = challenge.request;\n if (!req || typeof req.amount !== 'number' || !req.currency) return null;\n return {\n protocol: 'mpp',\n amount: req.amount,\n currency: req.currency,\n source: `challenge.request.amount (method=${challenge.method ?? 'unknown'})`,\n };\n}\n\nexport interface X402RequestForValue {\n maxAmountRequired?: number;\n amount?: number;\n asset?: string;\n currency?: string;\n}\n\nconst KNOWN_TOKEN_DECIMALS: Record<string, number> = {\n USDC: 6,\n USDT: 6,\n DAI: 18,\n ETH: 18,\n WETH: 18,\n};\n\nexport function extractX402TransactionValue(\n req: X402RequestForValue\n): TransactionValueContext | null {\n const rawAmount = req.maxAmountRequired ?? req.amount;\n const currency = req.currency ?? req.asset;\n if (typeof rawAmount !== 'number' || !currency) return null;\n const source = req.maxAmountRequired !== undefined ? 'maxAmountRequired' : 'amount';\n\n const decimals = KNOWN_TOKEN_DECIMALS[currency.toUpperCase()];\n if (decimals !== undefined) {\n return {\n protocol: 'x402',\n amount: rawAmount / Math.pow(10, decimals),\n currency,\n source,\n };\n }\n\n return {\n protocol: 'x402',\n amount: rawAmount,\n currency,\n source,\n rawUnits: true,\n };\n}\n","/**\n * RFC 9421 HTTP Message Signatures parser.\n *\n * Wraps `structured-headers` (transitive dep of http-message-signatures) to\n * parse the Signature-Input and Signature Dictionary headers per RFC 9421\n * Section 2.\n *\n * Produces structured metadata (kid, algorithm, covered components, tag,\n * created/expires/nonce, signature bytes) without verifying the signature —\n * verification lives in rfc9421-verify.ts.\n *\n * Shared by:\n * - Agent Pay (Mastercard) — kid resolves via Mastercard Agent Registry\n * - TAP (Visa) — kid resolves via Visa JWKS\n * - Web Bot Auth (generic transport substrate) — kid resolves via\n * /.well-known/http-message-signatures-directory\n */\n\nimport { parseDictionary } from 'structured-headers';\n\nexport interface RFC9421SignatureParams {\n /** The label identifying the signature in the Dictionary header (e.g. \"sig1\"). */\n label: string;\n /** Key ID used to look up the verifying key in the relevant registry. */\n kid: string;\n /** Algorithm declared in the Signature-Input params (e.g. \"ecdsa-p256-sha256\", \"ed25519\"). */\n alg?: string;\n /** Covered components, in order, per RFC 9421 Section 2.1. */\n covered: string[];\n /** Base64url-encoded signature bytes extracted from the paired Signature header. */\n signatureBase64: string;\n /** Unix seconds when the signature was created. */\n created?: number;\n /** Unix seconds when the signature expires. */\n expires?: number;\n /** Nonce (opaque string) for replay protection. */\n nonce?: string;\n /** Tag parameter. For Agent Pay/TAP this is \"browse\" or \"purchase\"; undefined otherwise. */\n tag?: 'browse' | 'purchase' | string;\n}\n\nexport interface ParsedRFC9421 {\n signatures: RFC9421SignatureParams[];\n}\n\n/**\n * Parse the RFC 9421 Signature-Input and Signature headers from a request or response.\n * Returns all signatures present (a single message may carry multiple labelled signatures).\n *\n * Returns null if either header is missing or malformed.\n */\nexport function parseRFC9421(\n headers: Record<string, string | string[] | undefined>\n): ParsedRFC9421 | null {\n const sigInput = readHeader(headers, 'signature-input');\n const sig = readHeader(headers, 'signature');\n if (!sigInput || !sig) return null;\n\n let inputDict;\n let sigDict;\n try {\n inputDict = parseDictionary(sigInput);\n sigDict = parseDictionary(sig);\n } catch {\n return null;\n }\n\n const signatures: RFC9421SignatureParams[] = [];\n\n for (const [label, entry] of inputDict) {\n // entry.value is the inner list of covered components; entry[1] is the params Map.\n const innerList = Array.isArray(entry)\n ? entry[0]\n : (entry as { value?: unknown; params?: unknown }).value;\n const params = Array.isArray(entry)\n ? entry[1]\n : (entry as { value?: unknown; params?: unknown }).params;\n if (!Array.isArray(innerList) || !params) continue;\n\n const covered: string[] = [];\n for (const item of innerList as Array<[unknown, Map<string, unknown>]>) {\n const [bare] = Array.isArray(item) ? item : [item];\n if (typeof bare === 'string') covered.push(bare);\n else if (bare && typeof bare === 'object' && 'toString' in bare) covered.push(String(bare));\n }\n\n const paramsMap = params as Map<string, unknown>;\n const kid = coerceString(paramsMap.get('keyid'));\n if (!kid) continue;\n\n const sigEntry = sigDict.get(label);\n if (!sigEntry) continue;\n\n const sigBare = Array.isArray(sigEntry) ? sigEntry[0] : (sigEntry as { value?: unknown }).value;\n const signatureBase64 = extractBase64(sigBare);\n if (!signatureBase64) continue;\n\n signatures.push({\n label,\n kid,\n alg: coerceString(paramsMap.get('alg')),\n covered,\n signatureBase64,\n created: coerceNumber(paramsMap.get('created')),\n expires: coerceNumber(paramsMap.get('expires')),\n nonce: coerceString(paramsMap.get('nonce')),\n tag: coerceString(paramsMap.get('tag')),\n });\n }\n\n if (signatures.length === 0) return null;\n return { signatures };\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | null {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw.join(', ');\n return null;\n }\n }\n return null;\n}\n\nfunction coerceString(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (value == null) return undefined;\n if (typeof value === 'object' && 'toString' in (value as object)) {\n const s = String(value);\n return s.length > 0 ? s : undefined;\n }\n return undefined;\n}\n\nfunction coerceNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'bigint') return Number(value);\n return undefined;\n}\n\nfunction extractBase64(value: unknown): string | null {\n if (value instanceof Uint8Array) return bufferToBase64(value);\n if (value instanceof ArrayBuffer) return bufferToBase64(new Uint8Array(value));\n if (ArrayBuffer.isView(value)) {\n const v = value as ArrayBufferView;\n return bufferToBase64(new Uint8Array(v.buffer, v.byteOffset, v.byteLength));\n }\n if (typeof value === 'string') {\n if (value.startsWith(':') && value.endsWith(':')) return value.slice(1, -1);\n return value;\n }\n return null;\n}\n\nfunction bufferToBase64(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString('base64');\n}\n","/**\n * RFC 9421 HTTP Message Signatures verification.\n *\n * Wraps http-message-signatures (dhensby) verifyMessage() with a RegistryResolver\n * hook for kid → JWK lookup. Library handles canonicalization + ES256/EdDSA/\n * HMAC/RSA verification; we supply the key-finding callback and policy around\n * clock skew.\n *\n * Shared by:\n * - Agent Pay (Mastercard) — resolver = createMastercardRegistry\n * - TAP (Visa) — resolver = createVisaRegistry\n * - Web Bot Auth (generic) — resolver = createWebBotAuthRegistry\n */\n\nimport { httpbis, type VerifierFinder, type VerifyingKey } from 'http-message-signatures';\nimport type { JWK } from 'jose';\nimport type { RegistryResolver } from './registry/types';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface RFC9421VerifyRequest {\n method: string;\n url: string;\n headers: Record<string, string | string[]>;\n body?: string;\n}\n\nexport interface RFC9421VerifyOptions {\n resolver: RegistryResolver;\n /** Seconds of tolerance around created/expires. Default 60 (tightened from 300). */\n clockSkewSec?: number;\n /** Injectable for deterministic tests. */\n now?: () => number;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface RFC9421VerifyResult {\n ok: boolean;\n kid?: string;\n registry?: RegistryResolver['name'];\n algorithm?: string;\n error?: string;\n}\n\nexport async function verifyRFC9421(\n request: RFC9421VerifyRequest,\n options: RFC9421VerifyOptions\n): Promise<RFC9421VerifyResult> {\n const { resolver } = options;\n const tolerance = options.clockSkewSec ?? 60;\n const nowSec = options.now ? options.now() : Math.floor(Date.now() / 1000);\n const nonceStore = options.nonceStore ?? defaultNonceStore;\n\n let resolvedKid: string | undefined;\n let resolvedAlg: string | undefined;\n let replayDetected = false;\n\n const keyLookup: VerifierFinder = async (parameters) => {\n const kid = typeof parameters.keyid === 'string' ? parameters.keyid : undefined;\n if (!kid) return null;\n resolvedKid = kid;\n const alg = typeof parameters.alg === 'string' ? parameters.alg : undefined;\n if (alg) resolvedAlg = alg;\n\n const origin = safeOrigin(request.url);\n const jwk = await resolver.resolve(kid, { origin, algorithm: alg });\n if (!jwk) return null;\n\n // Check clock-skew on this specific signature's created/expires.\n // SignatureParameters may carry Date, number, or ISO string per library.\n const created = toUnixSeconds(parameters.created);\n const expires = toUnixSeconds(parameters.expires);\n if (created !== undefined && Math.abs(nowSec - created) > tolerance) return null;\n if (expires !== undefined && nowSec > expires + tolerance) return null;\n\n // Audit F-A1-05: replay protection. RFC 9421 signatures include a\n // `nonce` parameter (optional but recommended for replay-sensitive\n // contexts). When present, register kid+nonce; reject duplicates\n // within the expiry window.\n const nonce = typeof parameters.nonce === 'string' ? parameters.nonce : undefined;\n if (nonce) {\n const expiresAtMs = (expires !== undefined ? expires + tolerance : nowSec + tolerance) * 1000;\n if (nonceStore.seen(`rfc9421:${kid}:${nonce}`, expiresAtMs)) {\n replayDetected = true;\n return null;\n }\n }\n\n return jwkToVerifyingKey(kid, jwk, alg);\n };\n\n try {\n const result = await httpbis.verifyMessage(\n {\n keyLookup,\n },\n normalizeRequest(request)\n );\n if (result === true) {\n return {\n ok: true,\n kid: resolvedKid,\n registry: resolver.name,\n algorithm: resolvedAlg,\n };\n }\n return {\n ok: false,\n kid: resolvedKid,\n registry: resolver.name,\n algorithm: resolvedAlg,\n error: replayDetected\n ? 'RFC9421 signature replay — already seen within tolerance window'\n : result === false\n ? 'signature invalid'\n : 'no signature found',\n };\n } catch (err) {\n return {\n ok: false,\n kid: resolvedKid,\n registry: resolver.name,\n algorithm: resolvedAlg,\n error: err instanceof Error ? err.message : 'verification error',\n };\n }\n}\n\nfunction normalizeRequest(request: RFC9421VerifyRequest): {\n method: string;\n url: string;\n headers: Record<string, string | string[]>;\n} {\n return {\n method: request.method.toUpperCase(),\n url: request.url,\n headers: request.headers,\n };\n}\n\nfunction safeOrigin(url: string): string | undefined {\n try {\n return new URL(url).origin;\n } catch {\n return undefined;\n }\n}\n\nasync function jwkToVerifyingKey(\n id: string,\n jwk: JWK,\n alg: string | undefined\n): Promise<VerifyingKey> {\n const algorithm = alg ?? inferAlgFromJwk(jwk);\n const { subtle } = await getCrypto();\n const importAlg = webCryptoImportAlgFor(algorithm);\n const verifyAlg = webCryptoAlgFor(algorithm);\n if (!importAlg || !verifyAlg) {\n return {\n id,\n algs: alg ? [alg] : undefined,\n verify: async () => false,\n };\n }\n const key = await subtle.importKey('jwk', jwk as JsonWebKey, importAlg, false, ['verify']);\n\n return {\n id,\n algs: alg ? [alg] : undefined,\n verify: async (data: Buffer, signature: Buffer): Promise<boolean> => {\n try {\n return await subtle.verify(verifyAlg, key, toArrayBuffer(signature), toArrayBuffer(data));\n } catch {\n return false;\n }\n },\n };\n}\n\nfunction inferAlgFromJwk(jwk: JWK): string {\n if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') return 'ed25519';\n if (jwk.kty === 'EC' && jwk.crv === 'P-256') return 'ecdsa-p256-sha256';\n if (jwk.kty === 'EC' && jwk.crv === 'P-384') return 'ecdsa-p384-sha384';\n if (jwk.kty === 'RSA') return 'rsa-v1_5-sha256';\n return 'ecdsa-p256-sha256';\n}\n\nfunction webCryptoAlgFor(\n rfc9421Alg: string\n): AlgorithmIdentifier | EcdsaParams | RsaPssParams | null {\n switch (rfc9421Alg) {\n case 'ed25519':\n return { name: 'Ed25519' };\n case 'ecdsa-p256-sha256':\n return { name: 'ECDSA', hash: 'SHA-256' };\n case 'ecdsa-p384-sha384':\n return { name: 'ECDSA', hash: 'SHA-384' };\n case 'rsa-v1_5-sha256':\n return { name: 'RSASSA-PKCS1-v1_5' };\n case 'rsa-pss-sha512':\n return { name: 'RSA-PSS', saltLength: 64 };\n default:\n return null;\n }\n}\n\nfunction webCryptoImportAlgFor(\n rfc9421Alg: string\n): AlgorithmIdentifier | EcKeyImportParams | RsaHashedImportParams | null {\n switch (rfc9421Alg) {\n case 'ed25519':\n return { name: 'Ed25519' };\n case 'ecdsa-p256-sha256':\n return { name: 'ECDSA', namedCurve: 'P-256' };\n case 'ecdsa-p384-sha384':\n return { name: 'ECDSA', namedCurve: 'P-384' };\n case 'rsa-v1_5-sha256':\n return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };\n case 'rsa-pss-sha512':\n return { name: 'RSA-PSS', hash: 'SHA-512' };\n default:\n return null;\n }\n}\n\nfunction toArrayBuffer(buf: Buffer): ArrayBuffer {\n const out = new ArrayBuffer(buf.byteLength);\n new Uint8Array(out).set(buf);\n return out;\n}\n\nfunction toUnixSeconds(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (v instanceof Date) return Math.floor(v.getTime() / 1000);\n if (typeof v === 'string') {\n const parsed = Date.parse(v);\n if (Number.isFinite(parsed)) return Math.floor(parsed / 1000);\n }\n return undefined;\n}\n\nasync function getCrypto(): Promise<{ subtle: SubtleCrypto }> {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n return { subtle: globalThis.crypto.subtle };\n }\n // Node fallback\n const nodeCrypto = await import('node:crypto');\n return { subtle: nodeCrypto.webcrypto.subtle as SubtleCrypto };\n}\n","/**\n * Shared nonce/signature replay-protection store for transport verifiers.\n *\n * Rationale: every transport-signature verifier (RFC9421, VI, AP2, ACP,\n * MPP) validates a created/expires window, but without a seen-nonce\n * cache any captured signed request can be replayed within the (default\n * 300s, now tightened to 60s) tolerance window.\n *\n * This module ships a bounded in-memory LRU as the default. Production\n * deployments with multi-pod horizontal scaling SHOULD pass a shared store\n * (Redis-backed) via the verifier options to make replay protection global\n * rather than per-pod.\n *\n * The store interface is intentionally minimal: a single `seen(key,\n * expiresAt)` method that returns true iff the key was already recorded\n * (i.e. caller should reject as a replay). Callers compose the key from\n * whichever identifiers are unique to the signature (kid + nonce + sig\n * digest, typically).\n */\n\nexport interface NonceStore {\n /**\n * Record `key` as seen. Returns true iff the key was ALREADY present —\n * i.e. caller should reject the request as a replay. Returns false on\n * first sighting (caller should proceed).\n *\n * `expiresAtMs` is a hint for the store to evict entries that can no\n * longer cause harm (their signature window has elapsed).\n */\n seen(key: string, expiresAtMs: number): boolean;\n}\n\n/**\n * Default in-memory LRU. Per-process, lost on restart. Suitable for\n * single-pod deploys and for development; production multi-pod deploys\n * should pass a shared store.\n *\n * Capacity-bounded: once the limit is reached, the oldest entry is dropped\n * even if it hasn't yet expired. The limit (default 10k entries) is large\n * enough that meaningful replay windows shouldn't approach it; if a\n * deployment is hitting it, that's a signal to migrate to Redis.\n *\n * Also runs a lazy sweep on each `seen` call to evict entries past their\n * `expiresAtMs` — keeps memory bounded under burst load.\n */\nexport class InMemoryNonceStore implements NonceStore {\n private readonly entries = new Map<string, number>();\n private readonly capacity: number;\n private lastSweepMs = 0;\n\n constructor(capacity = 10_000) {\n this.capacity = capacity;\n }\n\n seen(key: string, expiresAtMs: number): boolean {\n const nowMs = Date.now();\n\n // Lazy sweep: at most once per second, walk expired entries.\n if (nowMs - this.lastSweepMs > 1000) {\n for (const [k, exp] of this.entries) {\n if (exp <= nowMs) this.entries.delete(k);\n }\n this.lastSweepMs = nowMs;\n }\n\n const existing = this.entries.get(key);\n if (existing !== undefined && existing > nowMs) {\n return true; // replay\n }\n\n // First sighting (or stale entry) — record + evict oldest if over capacity.\n if (this.entries.size >= this.capacity) {\n const oldest = this.entries.keys().next().value;\n if (oldest !== undefined) this.entries.delete(oldest);\n }\n this.entries.set(key, expiresAtMs);\n return false;\n }\n}\n\n/**\n * Process-wide singleton instance for convenience. Verifiers that don't\n * receive an explicit nonceStore in their options fall back to this.\n *\n * Memory-bounded at 10k entries by default; sufficient for a single pod\n * handling thousands of requests/sec where signatures only carry value\n * within their (60s default) expiry window.\n */\nexport const defaultNonceStore = new InMemoryNonceStore();\n","/**\n * UCP (Universal Commerce Protocol) checkout session extractor.\n *\n * Google + Shopify spec (ucp.dev). Extracts checkout session context from\n * incoming HTTP requests and, at registration time, validates the\n * `/.well-known/ucp` manifest via AJV against the mirrored JSON schema.\n */\n\nimport { sdkFetch } from '../http';\nimport { mapUCPRequestToPurpose, type CommercePurpose } from './purpose-mapping';\n\nexport interface UCPTotal {\n type?: string;\n amount?: number;\n currency?: string;\n}\n\nexport interface UCPCheckoutContext {\n sessionId?: string;\n endpoint: string;\n purpose: CommercePurpose | null;\n merchantDomain?: string;\n totals?: UCPTotal[];\n paymentMethod?: string;\n manifestUrl?: string;\n}\n\nexport interface UCPRequestLike {\n method: string;\n url: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\nexport function extractUCPContext(request: UCPRequestLike): UCPCheckoutContext | null {\n const { method, url } = request;\n if (!method || !url) return null;\n\n const parsedUrl = safeParseUrl(url);\n const path = parsedUrl?.pathname ?? url.split('?')[0];\n\n const purpose = mapUCPRequestToPurpose(method, path);\n const endpoint = `${method.toUpperCase()} ${path}`;\n const sessionId = extractSessionId(path);\n\n const body = (request.body ?? {}) as Record<string, unknown>;\n const totals = Array.isArray(body.totals) ? (body.totals as UCPTotal[]) : undefined;\n const paymentMethod = coerceString(body.payment_method ?? body.paymentMethod);\n const manifestUrl = coerceString(body.manifest_url ?? body.manifestUrl);\n\n const merchantDomain = extractMerchantDomain(body, parsedUrl);\n\n return {\n sessionId,\n endpoint,\n purpose,\n merchantDomain,\n totals,\n paymentMethod,\n manifestUrl,\n };\n}\n\n/**\n * Fetch and parse a UCP manifest at registration time. Returns parsed JSON\n * on success, null on any failure (network, parse, timeout). Does NOT throw.\n *\n * Schema validation is a separate step — see `validateUCPManifest`.\n */\nexport async function fetchUCPManifest(\n manifestUrl: string,\n options: { timeoutMs?: number } = {}\n): Promise<unknown | null> {\n const timeoutMs = options.timeoutMs ?? 3000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await sdkFetch(manifestUrl, { signal: controller.signal });\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Validate a UCP manifest against the minimal shape we care about.\n *\n * The full UCP manifest schema lives upstream (ucp.dev) and is out of scope\n * to mirror here exhaustively. This function checks the structural guarantees\n * we depend on: required top-level fields (version, capabilities, endpoints).\n *\n * For full schema validation, consumers can pass their own AJV compiled\n * validator via `options.validator`.\n */\nexport interface UCPManifestValidationResult {\n ok: boolean;\n errors: string[];\n}\n\nexport function validateUCPManifest(\n manifest: unknown,\n options: { validator?: (m: unknown) => { ok: boolean; errors: string[] } } = {}\n): UCPManifestValidationResult {\n if (options.validator) return options.validator(manifest);\n\n const errors: string[] = [];\n if (!manifest || typeof manifest !== 'object') {\n return { ok: false, errors: ['manifest is not an object'] };\n }\n const m = manifest as Record<string, unknown>;\n if (typeof m.version !== 'string') errors.push('version is required and must be a string');\n if (!Array.isArray(m.capabilities)) errors.push('capabilities must be an array');\n if (!m.endpoints || typeof m.endpoints !== 'object') errors.push('endpoints must be an object');\n return { ok: errors.length === 0, errors };\n}\n\nfunction safeParseUrl(url: string): URL | null {\n try {\n return new URL(url, 'http://placeholder.invalid');\n } catch {\n return null;\n }\n}\n\nfunction extractSessionId(path: string): string | undefined {\n const match = path.match(/\\/checkout[-_]sessions\\/([^/?#]+)/);\n return match?.[1];\n}\n\nfunction extractMerchantDomain(\n body: Record<string, unknown>,\n parsedUrl: URL | null\n): string | undefined {\n const explicit = coerceString(body.merchant_domain ?? body.merchantDomain);\n if (explicit) return explicit;\n if (parsedUrl && parsedUrl.hostname !== 'placeholder.invalid') return parsedUrl.hostname;\n return undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * ACP (Agentic Commerce Protocol) request extractor.\n *\n * Co-maintained by OpenAI + Stripe. Spec at agenticcommerce.dev.\n *\n * Extracts ACP request context from HTTP requests:\n * - Multi-header parsing: Signature, Timestamp, Idempotency-Key,\n * Authorization: Bearer, API-Version\n * - Endpoint classification: Agentic Checkout (checkout_sessions.*) vs\n * Delegate Payment (agentic_commerce/delegate_payment)\n * - Payment token detection: spt_* (Stripe SharedPaymentToken),\n * vt_* (ACP vault token), unknown\n * - Totals + merchant extraction from body\n *\n * No signature verification here — see acp-verify.ts.\n */\n\nimport { mapACPRequestToPurpose, type CommercePurpose } from './purpose-mapping';\n\nexport type ACPEndpoint =\n | 'checkout_sessions.create'\n | 'checkout_sessions.update'\n | 'checkout_sessions.complete'\n | 'checkout_sessions.cancel'\n | 'delegate_payment'\n | 'unknown';\n\nexport type ACPPaymentTokenType = 'stripe-spt' | 'acp-vt' | 'other' | null;\n\nexport interface ACPTotal {\n type?: string;\n amount?: number;\n currency?: string;\n}\n\nexport interface ACPRequestContext {\n endpoint: ACPEndpoint;\n purpose: CommercePurpose | null;\n sessionId?: string;\n merchantId?: string;\n apiVersion?: string;\n bearer?: string;\n signatureHeader?: string;\n timestampHeader?: string;\n idempotencyKey?: string;\n paymentToken?: {\n raw?: string;\n type: ACPPaymentTokenType;\n provider?: string;\n };\n totals?: ACPTotal[];\n fulfillmentOption?: string;\n rawBody?: string;\n}\n\nexport interface ACPRequestLike {\n method: string;\n url: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: string;\n}\n\nexport function extractACPContext(request: ACPRequestLike): ACPRequestContext | null {\n const { method, url } = request;\n if (!method || !url) return null;\n\n const path = stripQuery(url.startsWith('http') ? new URL(url).pathname : url);\n\n const endpoint = classifyEndpoint(method, path);\n const purpose = mapACPRequestToPurpose(method, path);\n const sessionId = extractSessionId(path);\n\n const headers = request.headers ?? {};\n const signatureHeader = readHeader(headers, 'signature');\n const timestampHeader = readHeader(headers, 'timestamp');\n const idempotencyKey = readHeader(headers, 'idempotency-key');\n const apiVersion = readHeader(headers, 'api-version');\n const bearer = extractBearer(readHeader(headers, 'authorization'));\n\n const body = (request.body ?? {}) as Record<string, unknown>;\n const merchantId = coerceString(body.merchant_id ?? body.merchantId);\n const totals = Array.isArray(body.totals) ? (body.totals as ACPTotal[]) : undefined;\n const fulfillmentOption = extractFulfillmentOption(body);\n\n const paymentToken = extractPaymentToken(body);\n\n return {\n endpoint,\n purpose,\n sessionId,\n merchantId,\n apiVersion,\n bearer,\n signatureHeader,\n timestampHeader,\n idempotencyKey,\n paymentToken,\n totals,\n fulfillmentOption,\n rawBody: request.rawBody,\n };\n}\n\nfunction classifyEndpoint(method: string, path: string): ACPEndpoint {\n const m = method.toUpperCase();\n if (m !== 'POST') return 'unknown';\n if (/^\\/agentic_commerce\\/delegate_payment\\/?$/.test(path)) return 'delegate_payment';\n if (/^\\/checkout_sessions\\/?$/.test(path)) return 'checkout_sessions.create';\n if (/^\\/checkout_sessions\\/[^/]+\\/?$/.test(path)) return 'checkout_sessions.update';\n if (/^\\/checkout_sessions\\/[^/]+\\/complete\\/?$/.test(path)) return 'checkout_sessions.complete';\n if (/^\\/checkout_sessions\\/[^/]+\\/cancel\\/?$/.test(path)) return 'checkout_sessions.cancel';\n return 'unknown';\n}\n\nfunction extractSessionId(path: string): string | undefined {\n const match = path.match(/\\/checkout_sessions\\/([^/?#]+)/);\n return match?.[1];\n}\n\nfunction extractBearer(authHeader: string | undefined): string | undefined {\n if (!authHeader) return undefined;\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n return match ? match[1].trim() : undefined;\n}\n\nfunction extractPaymentToken(body: Record<string, unknown>): ACPRequestContext['paymentToken'] {\n const paymentData = body.payment_data as Record<string, unknown> | undefined;\n if (!paymentData) return undefined;\n const raw = coerceString(paymentData.token);\n const provider = coerceString(paymentData.provider);\n if (!raw) return { raw: undefined, type: null, provider };\n const type = classifyPaymentToken(raw);\n return { raw, type, provider };\n}\n\nfunction classifyPaymentToken(token: string): ACPPaymentTokenType {\n if (token.startsWith('spt_')) return 'stripe-spt';\n if (token.startsWith('vt_')) return 'acp-vt';\n return 'other';\n}\n\nfunction extractFulfillmentOption(body: Record<string, unknown>): string | undefined {\n const direct = coerceString(body.fulfillment_option ?? body.fulfillmentOption);\n if (direct) return direct;\n const options = body.fulfillment_options;\n if (Array.isArray(options) && options.length > 0) {\n const first = options[0];\n if (first && typeof first === 'object') {\n const id = coerceString((first as Record<string, unknown>).id);\n if (id) return id;\n }\n }\n return undefined;\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | undefined {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw[0];\n }\n }\n return undefined;\n}\n\nfunction stripQuery(path: string): string {\n const q = path.indexOf('?');\n return q === -1 ? path : path.slice(0, q);\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * VI (Verifiable Intent) SD-JWT extraction.\n *\n * Open-sourced 5 March 2026 by Mastercard + Google (v0.1-draft).\n * VI is a 3-layer SD-JWT chain:\n * L1 — issuer → wallet (credential provider)\n * L2 — user → agent (cnf.jwk binding to L3 agent key)\n * L3 — agent → merchant (payment or checkout mandate, split into L3a / L3b\n * cross-referenced via transaction_id)\n *\n * This module does EXTRACTION ONLY — it decodes SD-JWT structure and pulls\n * out the mandate type, kid, executionMode, 8 constraint types, checkoutHash\n * (constraint type 8), transactionId, and raw layers for later verification.\n *\n * Signature verification lives in vi-verify.ts; this module uses @sd-jwt's\n * sync decoder with a SHA-256 hasher for structural parsing only.\n */\n\nimport { splitSdJwt, decodeSdJwtSync } from '@sd-jwt/core';\nimport { createHash } from 'node:crypto';\nimport type { VIMandateType } from './purpose-mapping';\n\nexport type { VIMandateType };\nexport type VIExecutionMode = 'Immediate' | 'Autonomous' | 'Both';\n\nexport interface VIAllowedParty {\n id?: string;\n name?: string;\n website?: string;\n}\n\nexport interface VILineItem {\n id?: string;\n acceptableItems?: string[];\n quantity?: number;\n}\n\nexport interface VIPaymentAmount {\n currency?: string;\n min?: number;\n max?: number;\n}\n\nexport interface VIBudgetLimit {\n currency?: string;\n max?: number;\n}\n\nexport interface VIRecurrence {\n frequency?: string;\n startDate?: string;\n endDate?: string;\n maxOccurrences?: number;\n}\n\nexport interface VIConstraints {\n allowedMerchants?: VIAllowedParty[];\n allowedPayees?: VIAllowedParty[];\n lineItems?: VILineItem[];\n paymentAmount?: VIPaymentAmount;\n budgetLimit?: VIBudgetLimit;\n recurrence?: VIRecurrence;\n agentRecurrence?: VIRecurrence;\n}\n\nexport interface VIExtractedClaims {\n mandateType: VIMandateType;\n kid?: string;\n executionMode?: VIExecutionMode;\n credentialProvider?: string;\n constraints: VIConstraints;\n /** VI constraint type 8 — SHA-256 of the paired L2 checkout disclosure. */\n checkoutHash?: string;\n transactionId?: string;\n rawLayers: { l1?: string; l2?: string; l3?: string };\n}\n\n/**\n * Extract VI claims from a compact SD-JWT string.\n *\n * Input shape:\n * <jwt>~<disclosure1>~<disclosure2>~...~<kbJwt?>\n *\n * Returns null if parsing fails at any layer. Does not verify signatures.\n */\nexport function extractVIClaims(sdJwtCompact: string): VIExtractedClaims | null {\n if (!sdJwtCompact || typeof sdJwtCompact !== 'string') return null;\n\n let decoded;\n try {\n decoded = decodeSdJwtSync(sdJwtCompact, sha256Sync);\n } catch {\n return null;\n }\n\n const split = safeSplit(sdJwtCompact);\n\n const payload = (decoded.jwt?.payload ?? {}) as Record<string, unknown>;\n const disclosures = decoded.disclosures ?? [];\n\n // Apply disclosures onto payload to resolve _sd references.\n // Disclosure from @sd-jwt/core has { key, value, digest() } where digest is\n // a function — we only need key+value here, so narrow via a structural cast.\n const claims = applyDisclosures(\n payload,\n disclosures as unknown as Array<{ key?: string; value?: unknown }>\n );\n\n const mandateType = coerceMandateType(\n claims.mandate_type ?? claims.mandateType ?? payload.mandate_type ?? payload.mandateType\n );\n if (!mandateType) return null;\n\n const kid = coerceString(\n (decoded.jwt?.header as Record<string, unknown> | undefined)?.kid ?? claims.kid ?? payload.kid\n );\n\n const executionMode = coerceExecutionMode(claims.execution_mode ?? claims.executionMode);\n const credentialProvider = coerceString(claims.iss ?? payload.iss);\n\n const constraints = extractConstraints(\n (claims.constraints ?? claims.default_constraints ?? {}) as Record<string, unknown>\n );\n\n const transactionId = coerceString(claims.transaction_id ?? claims.transactionId);\n const checkoutHash = coerceString(\n claims.checkout_hash ??\n claims.conditional_transaction_id ??\n (claims.payment_reference as Record<string, unknown> | undefined)?.checkout_hash\n );\n\n return {\n mandateType,\n kid,\n executionMode,\n credentialProvider,\n constraints,\n checkoutHash,\n transactionId,\n rawLayers: split,\n };\n}\n\nfunction safeSplit(compact: string): { l1?: string; l2?: string; l3?: string } {\n try {\n const { jwt, kbJwt } = splitSdJwt(compact);\n // VI layering maps loosely: the outer JWT is L3 (agent mandate), KB-JWT\n // (if present) is the key-binding proof, and disclosures carry L2/L1 fragments.\n return { l3: jwt, l2: kbJwt };\n } catch {\n return {};\n }\n}\n\nfunction applyDisclosures(\n payload: Record<string, unknown>,\n disclosures: Array<{ key?: string; value?: unknown }>\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...payload };\n for (const d of disclosures) {\n if (d.key && d.value !== undefined && !(d.key in result)) {\n result[d.key] = d.value;\n }\n }\n return result;\n}\n\nfunction extractConstraints(raw: Record<string, unknown>): VIConstraints {\n return {\n allowedMerchants: toAllowedPartyArray(raw.allowed_merchants ?? raw.allowedMerchants),\n allowedPayees: toAllowedPartyArray(raw.allowed_payees ?? raw.allowedPayees),\n lineItems: toLineItemArray(raw.line_items ?? raw.lineItems),\n paymentAmount: toPaymentAmount(raw.payment_amount ?? raw.paymentAmount),\n budgetLimit: toBudgetLimit(raw.budget_limit ?? raw.budgetLimit ?? raw.budget),\n recurrence: toRecurrence(raw.recurrence),\n agentRecurrence: toRecurrence(raw.agent_recurrence ?? raw.agentRecurrence),\n };\n}\n\nfunction toAllowedPartyArray(v: unknown): VIAllowedParty[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out: VIAllowedParty[] = [];\n for (const item of v) {\n if (item && typeof item === 'object') {\n const r = item as Record<string, unknown>;\n out.push({\n id: coerceString(r.id),\n name: coerceString(r.name),\n website: coerceString(r.website),\n });\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\nfunction toLineItemArray(v: unknown): VILineItem[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out: VILineItem[] = [];\n for (const item of v) {\n if (item && typeof item === 'object') {\n const r = item as Record<string, unknown>;\n const acc = r.acceptable_items ?? r.acceptableItems;\n out.push({\n id: coerceString(r.id),\n acceptableItems: Array.isArray(acc)\n ? (acc.filter((a) => typeof a === 'string') as string[])\n : undefined,\n quantity: coerceNumber(r.quantity),\n });\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\nfunction toPaymentAmount(v: unknown): VIPaymentAmount | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n return {\n currency: coerceString(r.currency),\n min: coerceNumber(r.min),\n max: coerceNumber(r.max),\n };\n}\n\nfunction toBudgetLimit(v: unknown): VIBudgetLimit | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n return {\n currency: coerceString(r.currency),\n max: coerceNumber(r.max),\n };\n}\n\nfunction toRecurrence(v: unknown): VIRecurrence | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n return {\n frequency: coerceString(r.frequency),\n startDate: coerceString(r.start_date ?? r.startDate),\n endDate: coerceString(r.end_date ?? r.endDate),\n maxOccurrences: coerceNumber(r.max_occurrences ?? r.maxOccurrences),\n };\n}\n\nfunction coerceMandateType(v: unknown): VIMandateType | null {\n if (v === 'checkout' || v === 'payment' || v === 'checkout.open' || v === 'payment.open') {\n return v;\n }\n return null;\n}\n\nfunction coerceExecutionMode(v: unknown): VIExecutionMode | undefined {\n return v === 'Immediate' || v === 'Autonomous' || v === 'Both' ? v : undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n\nfunction coerceNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string') {\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\nfunction sha256Sync(data: string | ArrayBuffer): Uint8Array {\n const buf =\n typeof data === 'string' ? Buffer.from(data, 'utf-8') : Buffer.from(new Uint8Array(data));\n const hash = createHash('sha256').update(buf).digest();\n return new Uint8Array(hash.buffer, hash.byteOffset, hash.byteLength);\n}\n","/**\n * Stripe webhook HMAC-SHA256 verifier (inline).\n *\n * Stripe-Signature header format: \"t=TIMESTAMP,v1=HEX_SIGNATURE\"\n * - t: unix seconds when Stripe signed the webhook\n * - v1: HMAC-SHA256(webhook_secret, `${t}.${payload}`) as hex\n *\n * Multiple v1 signatures can coexist during secret rotation; any match wins.\n * Default tolerance on timestamp age: 300s (matches Stripe's own default).\n *\n * Documented at docs.stripe.com — we intentionally inline ~25 LOC rather\n * than pull in the full stripe npm package (MIT but 600KB+ with deps).\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\nexport interface VerifyStripeWebhookResult {\n ok: boolean;\n timestamp?: number;\n error?: string;\n}\n\nexport interface VerifyStripeWebhookOptions {\n toleranceSec?: number;\n /** Injectable for deterministic tests. */\n now?: () => number;\n}\n\nexport function verifyStripeWebhook(\n payload: string,\n signatureHeader: string | undefined,\n secret: string,\n options: VerifyStripeWebhookOptions = {}\n): VerifyStripeWebhookResult {\n if (!signatureHeader) return { ok: false, error: 'missing Stripe-Signature header' };\n if (!secret) return { ok: false, error: 'missing webhook secret' };\n\n const parsed = parseStripeSignature(signatureHeader);\n if (!parsed.timestamp) return { ok: false, error: 'malformed Stripe-Signature (missing t=)' };\n if (parsed.v1Signatures.length === 0) {\n return { ok: false, error: 'malformed Stripe-Signature (no v1=)' };\n }\n\n const tolerance = options.toleranceSec ?? 300;\n const now = options.now ? options.now() : Math.floor(Date.now() / 1000);\n if (Math.abs(now - parsed.timestamp) > tolerance) {\n return {\n ok: false,\n timestamp: parsed.timestamp,\n error: `timestamp outside tolerance (${tolerance}s)`,\n };\n }\n\n const signedPayload = `${parsed.timestamp}.${payload}`;\n const expected = createHmac('sha256', secret).update(signedPayload).digest();\n\n for (const candidateHex of parsed.v1Signatures) {\n const candidate = hexToBuffer(candidateHex);\n if (!candidate) continue;\n if (candidate.length !== expected.length) continue;\n if (timingSafeEqual(candidate, expected)) {\n return { ok: true, timestamp: parsed.timestamp };\n }\n }\n\n return { ok: false, timestamp: parsed.timestamp, error: 'signature mismatch' };\n}\n\ninterface ParsedStripeSignature {\n timestamp: number | null;\n v1Signatures: string[];\n}\n\nfunction parseStripeSignature(header: string): ParsedStripeSignature {\n let timestamp: number | null = null;\n const v1Signatures: string[] = [];\n for (const part of header.split(',')) {\n const [rawKey, rawValue] = part.split('=');\n if (!rawKey || !rawValue) continue;\n const key = rawKey.trim();\n const value = rawValue.trim();\n if (key === 't') {\n const n = Number(value);\n if (Number.isFinite(n)) timestamp = n;\n } else if (key === 'v1') {\n v1Signatures.push(value);\n }\n }\n return { timestamp, v1Signatures };\n}\n\nfunction hexToBuffer(hex: string): Buffer | null {\n if (!/^[0-9a-fA-F]+$/.test(hex) || hex.length % 2 !== 0) return null;\n return Buffer.from(hex, 'hex');\n}\n","/**\n * PDLSS constraint evaluation.\n *\n * Evaluates VI constraint types 1-4 (merchant/payee allowlists, line items,\n * payment amount) + MPP/x402 payment-method allowlist + spending-limit\n * against a transaction context.\n *\n * Types 5/6/7 (budget, recurrence, agent_recurrence) extract through but\n * enforcement is deferred to the cross-merchant budget service.\n * This module returns per-constraint {ok, reason} results\n * so a policy layer can decide hard-deny vs trust-signal.\n */\n\nimport type { VIConstraints, VIAllowedParty, VILineItem, VIPaymentAmount } from './vi';\n\nexport interface TransactionContext {\n amount?: number;\n currency?: string;\n merchant?: { id?: string; website?: string };\n payee?: { id?: string; website?: string };\n lineItems?: Array<{ id?: string; quantity?: number }>;\n /** For MPP / x402 payment-method enforcement. */\n paymentMethod?: string;\n}\n\nexport type ConstraintKey = 'merchant' | 'payee' | 'lineItems' | 'amount' | 'paymentMethod';\n\nexport interface ConstraintResult {\n ok: boolean;\n reason?: string;\n}\n\nexport interface ConstraintEvalResult {\n ok: boolean;\n results: Record<string, ConstraintResult>;\n reasons: string[];\n}\n\nexport interface VIConstraintEvalInput {\n constraints: VIConstraints;\n transaction: TransactionContext;\n}\n\nexport function evaluateVIConstraints(input: VIConstraintEvalInput): ConstraintEvalResult {\n const { constraints, transaction } = input;\n const results: Record<string, ConstraintResult> = {};\n\n if (constraints.allowedMerchants && constraints.allowedMerchants.length > 0) {\n results.merchant = evaluateAllowlist(\n 'merchant',\n constraints.allowedMerchants,\n transaction.merchant\n );\n }\n\n if (constraints.allowedPayees && constraints.allowedPayees.length > 0) {\n results.payee = evaluateAllowlist('payee', constraints.allowedPayees, transaction.payee);\n }\n\n if (constraints.lineItems && constraints.lineItems.length > 0) {\n results.lineItems = evaluateLineItems(constraints.lineItems, transaction.lineItems ?? []);\n }\n\n if (constraints.paymentAmount) {\n results.amount = evaluatePaymentAmount(constraints.paymentAmount, transaction);\n }\n\n const reasons: string[] = [];\n let ok = true;\n for (const [key, r] of Object.entries(results)) {\n if (!r.ok) {\n ok = false;\n reasons.push(r.reason ?? `${key} failed`);\n }\n }\n\n return { ok, results, reasons };\n}\n\nexport interface PaymentMethodAllowlistInput {\n allowedMethods?: string[];\n requestedMethod?: string;\n}\n\nexport function evaluatePaymentMethodAllowlist(\n input: PaymentMethodAllowlistInput\n): ConstraintResult {\n const allow = input.allowedMethods ?? [];\n if (allow.length === 0) return { ok: true };\n if (!input.requestedMethod) {\n return { ok: false, reason: 'no payment method in request; allowlist configured' };\n }\n const lowered = input.requestedMethod.toLowerCase();\n const allowed = allow.some((m) => m.toLowerCase() === lowered);\n if (!allowed) {\n return {\n ok: false,\n reason: `payment method \"${input.requestedMethod}\" not in allowlist [${allow.join(', ')}]`,\n };\n }\n return { ok: true };\n}\n\nexport interface SpendingLimitInput {\n limit?: { amount?: number; currency?: string };\n requested?: { amount?: number; currency?: string };\n}\n\nexport function evaluateSpendingLimit(input: SpendingLimitInput): ConstraintResult {\n const { limit, requested } = input;\n if (!limit || typeof limit.amount !== 'number') return { ok: true };\n if (!requested || typeof requested.amount !== 'number') return { ok: true };\n if (limit.currency && requested.currency && limit.currency !== requested.currency) {\n return {\n ok: false,\n reason: `currency mismatch: limit ${limit.currency} vs requested ${requested.currency}`,\n };\n }\n if (requested.amount > limit.amount) {\n return {\n ok: false,\n reason:\n `requested ${requested.amount} ${requested.currency ?? ''} exceeds limit ${limit.amount} ${limit.currency ?? ''}`.trim(),\n };\n }\n return { ok: true };\n}\n\nfunction evaluateAllowlist(\n kind: 'merchant' | 'payee',\n allowlist: VIAllowedParty[],\n actual: { id?: string; website?: string } | undefined\n): ConstraintResult {\n if (!actual || (!actual.id && !actual.website)) {\n return { ok: false, reason: `no ${kind} in transaction; allowlist configured` };\n }\n for (const entry of allowlist) {\n if (entry.id && actual.id && entry.id === actual.id) return { ok: true };\n if (entry.website && actual.website && domainsMatch(entry.website, actual.website)) {\n return { ok: true };\n }\n }\n const allowedDescriptors = allowlist.map(describeParty).join(', ');\n const actualDescriptor = describeParty(actual);\n return {\n ok: false,\n reason: `${kind} ${actualDescriptor} not in allowlist [${allowedDescriptors}]`,\n };\n}\n\nfunction evaluateLineItems(\n allowlist: VILineItem[],\n actualItems: Array<{ id?: string; quantity?: number }>\n): ConstraintResult {\n if (actualItems.length === 0) {\n return { ok: false, reason: 'no line items in transaction; allowlist configured' };\n }\n const reasons: string[] = [];\n for (const item of actualItems) {\n const match = allowlist.find(\n (a) => (a.id && a.id === item.id) || (a.acceptableItems ?? []).includes(item.id ?? '')\n );\n if (!match) {\n reasons.push(`line item \"${item.id ?? '(unnamed)'}\" not in allowlist`);\n continue;\n }\n if (\n typeof match.quantity === 'number' &&\n typeof item.quantity === 'number' &&\n item.quantity > match.quantity\n ) {\n reasons.push(\n `line item \"${item.id}\" quantity ${item.quantity} exceeds allowed ${match.quantity}`\n );\n }\n }\n return reasons.length === 0 ? { ok: true } : { ok: false, reason: reasons.join('; ') };\n}\n\nfunction evaluatePaymentAmount(\n bound: VIPaymentAmount,\n transaction: TransactionContext\n): ConstraintResult {\n if (typeof transaction.amount !== 'number') {\n return { ok: false, reason: 'no amount in transaction; paymentAmount bound configured' };\n }\n if (bound.currency && transaction.currency && bound.currency !== transaction.currency) {\n return {\n ok: false,\n reason: `currency mismatch: bound ${bound.currency} vs transaction ${transaction.currency}`,\n };\n }\n if (typeof bound.min === 'number' && transaction.amount < bound.min) {\n return {\n ok: false,\n reason: `amount ${transaction.amount} below min ${bound.min}`,\n };\n }\n if (typeof bound.max === 'number' && transaction.amount > bound.max) {\n return {\n ok: false,\n reason: `amount ${transaction.amount} above max ${bound.max}`,\n };\n }\n return { ok: true };\n}\n\nfunction domainsMatch(allow: string, actual: string): boolean {\n const a = normalizeDomain(allow);\n const b = normalizeDomain(actual);\n return a === b || b.endsWith(`.${a}`);\n}\n\nfunction normalizeDomain(value: string): string {\n try {\n const withScheme = /^https?:\\/\\//.test(value) ? value : `https://${value}`;\n return new URL(withScheme).hostname.toLowerCase();\n } catch {\n return value.toLowerCase();\n }\n}\n\nfunction describeParty(party: { id?: string; name?: string; website?: string }): string {\n if (party.id) return `id:${party.id}`;\n if (party.website) return party.website;\n if (party.name) return party.name;\n return '(unnamed)';\n}\n","/**\n * Cross-protocol agent identity binding.\n *\n * Every commerce layer claims an agent identity differently:\n * - VI L3 kid (SD-JWT header)\n * - AP2 agent_id (mandate payload)\n * - ACP Authorization: Bearer token (merchant-issued pre-shared)\n * - MPP Credential `source` field (DID or chain-native key)\n * - x402 client wallet address\n * - RFC 9421 kid (Agent Pay / TAP / Web Bot Auth)\n *\n * This module maps any such claim to a single AstraSync agent via a\n * caller-supplied resolver (typically delegates to the counterparty service),\n * then flags whether multiple claims on the same request resolve to different\n * agents (a trust signal for PDLSS).\n *\n * This is AstraSync whitespace — no vendor owns multi-protocol identity\n * unification.\n */\n\nexport interface IdentityClaim {\n /** Originating protocol label: 'vi' | 'ap2' | 'acp' | 'mpp' | 'x402' | 'agentpay' | 'tap' | 'webbotauth' */\n protocol: string;\n /** Claim field name, e.g. 'kid', 'agent_id', 'source', 'bearer'. */\n field: string;\n /** Claim value as presented on the wire. */\n value: string;\n}\n\nexport interface IdentityBindingResult {\n claims: IdentityClaim[];\n mappedAstraSyncAgentId?: string;\n /**\n * True when two or more claims resolve to different AstraSync agents.\n * Surfaced as a trust signal rather than an auto-deny — legitimate flows\n * (e.g. delegate payments) can legitimately carry multiple identities.\n */\n mismatchAcrossLayers: boolean;\n /** Per-claim resolution result for audit / debugging. */\n resolutions: Array<{ claim: IdentityClaim; agentId: string | null }>;\n}\n\nexport type IdentityResolver = (claim: IdentityClaim) => Promise<string | null>;\n\nexport async function bindIdentity(\n claims: IdentityClaim[],\n resolver: IdentityResolver\n): Promise<IdentityBindingResult> {\n const resolutions: Array<{ claim: IdentityClaim; agentId: string | null }> = [];\n for (const claim of claims) {\n if (!claim.value) {\n resolutions.push({ claim, agentId: null });\n continue;\n }\n const agentId = await resolver(claim);\n resolutions.push({ claim, agentId });\n }\n\n const resolvedIds = resolutions\n .map((r) => r.agentId)\n .filter((id): id is string => typeof id === 'string' && id.length > 0);\n\n const unique = Array.from(new Set(resolvedIds));\n const mismatchAcrossLayers = unique.length > 1;\n const mappedAstraSyncAgentId = unique.length === 1 ? unique[0] : undefined;\n\n return {\n claims,\n mappedAstraSyncAgentId,\n mismatchAcrossLayers,\n resolutions,\n };\n}\n\n/**\n * Helper constructors — keep protocol/field strings consistent across the\n * codebase and make tests readable.\n */\nexport const claim = {\n viKid: (value: string): IdentityClaim => ({ protocol: 'vi', field: 'kid', value }),\n ap2AgentId: (value: string): IdentityClaim => ({ protocol: 'ap2', field: 'agent_id', value }),\n acpBearer: (value: string): IdentityClaim => ({ protocol: 'acp', field: 'bearer', value }),\n mppSource: (value: string): IdentityClaim => ({ protocol: 'mpp', field: 'source', value }),\n x402Wallet: (value: string): IdentityClaim => ({ protocol: 'x402', field: 'wallet', value }),\n agentPayKid: (value: string): IdentityClaim => ({ protocol: 'agentpay', field: 'kid', value }),\n tapKid: (value: string): IdentityClaim => ({ protocol: 'tap', field: 'kid', value }),\n webBotAuthKid: (value: string): IdentityClaim => ({\n protocol: 'webbotauth',\n field: 'kid',\n value,\n }),\n};\n","/**\n * AP2 (Agent Payments Protocol) mandate extraction.\n *\n * Google-led, launched 3 April 2026 with 60+ partners (Mastercard, PayPal,\n * Coinbase, AmEx, Revolut, UnionPay, ...). AP2 ships three mandate types as\n * SD-JWTs in series:\n * - intent_mandate — user declares intent (amount, merchant category, etc.)\n * - cart_mandate — user approves a cart (specific items, totals)\n * - payment_mandate — authorizes the actual payment rail\n *\n * Mandates are cross-referenced via ids; each is an SD-JWT over ES256 (or\n * equivalent). We decode via @sd-jwt/core and extract the AP2-specific\n * shape — verification lives in ap2-verify.ts.\n */\n\nimport { decodeSdJwtSync } from '@sd-jwt/core';\nimport { createHash } from 'node:crypto';\nimport type { AP2MandateType } from './purpose-mapping';\n\nexport type { AP2MandateType };\n\nexport interface AP2PaymentDetailsTotal {\n amount?: { value?: string | number; currency?: string };\n label?: string;\n}\n\nexport interface AP2IntentMandateClaims {\n type: 'intent_mandate';\n agent_id?: string;\n user_id?: string;\n merchant_category?: string;\n allowedMerchantDomains?: string[];\n paymentMethods?: string[];\n expires?: string;\n payment_details_total?: AP2PaymentDetailsTotal;\n raw: Record<string, unknown>;\n}\n\nexport interface AP2CartMandateClaims {\n type: 'cart_mandate';\n agent_id?: string;\n intent_mandate_id?: string;\n merchant_id?: string;\n line_items?: Array<{\n id?: string;\n quantity?: number;\n price?: { value?: string | number; currency?: string };\n }>;\n payment_details_total?: AP2PaymentDetailsTotal;\n expires?: string;\n raw: Record<string, unknown>;\n}\n\nexport interface AP2PaymentMandateClaims {\n type: 'payment_mandate';\n agent_id?: string;\n cart_mandate_id?: string;\n payment_method?: string;\n payment_details_total?: AP2PaymentDetailsTotal;\n credential_provider?: string;\n raw: Record<string, unknown>;\n}\n\nexport type AP2MandateClaims =\n | AP2IntentMandateClaims\n | AP2CartMandateClaims\n | AP2PaymentMandateClaims;\n\nexport interface AP2MandateTriple {\n intent?: AP2IntentMandateClaims;\n cart?: AP2CartMandateClaims;\n payment?: AP2PaymentMandateClaims;\n rawLayers: { intentJwt?: string; cartJwt?: string; paymentJwt?: string };\n}\n\n/**\n * Extract a single AP2 mandate from a compact SD-JWT.\n * Returns null if the SD-JWT is malformed or lacks a recognized type field.\n */\nexport function extractAP2Mandate(sdJwtCompact: string): AP2MandateClaims | null {\n if (!sdJwtCompact || typeof sdJwtCompact !== 'string') return null;\n\n let decoded;\n try {\n decoded = decodeSdJwtSync(sdJwtCompact, sha256Sync);\n } catch {\n return null;\n }\n\n const payload = (decoded.jwt?.payload ?? {}) as Record<string, unknown>;\n const disclosures = decoded.disclosures ?? [];\n const claims = applyDisclosures(\n payload,\n disclosures as unknown as Array<{ key?: string; value?: unknown }>\n );\n\n const type = coerceMandateType(claims.type ?? claims.mandate_type ?? claims.mandateType);\n if (!type) return null;\n\n if (type === 'intent_mandate') return buildIntent(claims);\n if (type === 'cart_mandate') return buildCart(claims);\n return buildPayment(claims);\n}\n\nexport interface AP2MandateTripleInput {\n intent?: string;\n cart?: string;\n payment?: string;\n}\n\n/**\n * Extract an intent / cart / payment triple, returning whichever are present.\n * Does NOT enforce cross-reference consistency — that's ap2-verify.ts's job.\n */\nexport function extractAP2Mandates(input: AP2MandateTripleInput): AP2MandateTriple {\n const intent = input.intent\n ? (extractAP2Mandate(input.intent) as AP2IntentMandateClaims | null)\n : null;\n const cart = input.cart ? (extractAP2Mandate(input.cart) as AP2CartMandateClaims | null) : null;\n const payment = input.payment\n ? (extractAP2Mandate(input.payment) as AP2PaymentMandateClaims | null)\n : null;\n return {\n intent: intent ?? undefined,\n cart: cart ?? undefined,\n payment: payment ?? undefined,\n rawLayers: {\n intentJwt: input.intent,\n cartJwt: input.cart,\n paymentJwt: input.payment,\n },\n };\n}\n\nfunction buildIntent(claims: Record<string, unknown>): AP2IntentMandateClaims {\n return {\n type: 'intent_mandate',\n agent_id: coerceString(claims.agent_id ?? claims.agentId),\n user_id: coerceString(claims.user_id ?? claims.userId ?? claims.sub),\n merchant_category: coerceString(claims.merchant_category ?? claims.merchantCategory),\n allowedMerchantDomains: toStringArray(\n claims.allowed_merchant_domains ?? claims.allowedMerchantDomains\n ),\n paymentMethods: toStringArray(claims.payment_methods ?? claims.paymentMethods),\n expires: coerceString(claims.expires ?? claims.exp),\n payment_details_total: toPaymentDetails(claims.payment_details_total ?? claims.total),\n raw: claims,\n };\n}\n\nfunction buildCart(claims: Record<string, unknown>): AP2CartMandateClaims {\n return {\n type: 'cart_mandate',\n agent_id: coerceString(claims.agent_id ?? claims.agentId),\n intent_mandate_id: coerceString(claims.intent_mandate_id ?? claims.intentMandateId),\n merchant_id: coerceString(claims.merchant_id ?? claims.merchantId),\n line_items: toLineItems(claims.line_items ?? claims.lineItems),\n payment_details_total: toPaymentDetails(claims.payment_details_total ?? claims.total),\n expires: coerceString(claims.expires ?? claims.exp),\n raw: claims,\n };\n}\n\nfunction buildPayment(claims: Record<string, unknown>): AP2PaymentMandateClaims {\n return {\n type: 'payment_mandate',\n agent_id: coerceString(claims.agent_id ?? claims.agentId),\n cart_mandate_id: coerceString(claims.cart_mandate_id ?? claims.cartMandateId),\n payment_method: coerceString(claims.payment_method ?? claims.paymentMethod),\n payment_details_total: toPaymentDetails(claims.payment_details_total ?? claims.total),\n credential_provider: coerceString(claims.credential_provider ?? claims.credentialProvider),\n raw: claims,\n };\n}\n\nfunction toPaymentDetails(v: unknown): AP2PaymentDetailsTotal | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n const amount = r.amount as Record<string, unknown> | undefined;\n return {\n amount: amount\n ? {\n value: coerceStringOrNumber(amount.value),\n currency: coerceString(amount.currency),\n }\n : undefined,\n label: coerceString(r.label),\n };\n}\n\nfunction toLineItems(v: unknown): AP2CartMandateClaims['line_items'] {\n if (!Array.isArray(v)) return undefined;\n const items: NonNullable<AP2CartMandateClaims['line_items']> = [];\n for (const item of v) {\n if (!item || typeof item !== 'object') continue;\n const r = item as Record<string, unknown>;\n const price = r.price as Record<string, unknown> | undefined;\n items.push({\n id: coerceString(r.id),\n quantity: coerceNumber(r.quantity),\n price: price\n ? {\n value: coerceStringOrNumber(price.value),\n currency: coerceString(price.currency),\n }\n : undefined,\n });\n }\n return items.length > 0 ? items : undefined;\n}\n\nfunction toStringArray(v: unknown): string[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out = v.filter((i): i is string => typeof i === 'string' && i.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\nfunction applyDisclosures(\n payload: Record<string, unknown>,\n disclosures: Array<{ key?: string; value?: unknown }>\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...payload };\n for (const d of disclosures) {\n if (d.key && d.value !== undefined && !(d.key in result)) {\n result[d.key] = d.value;\n }\n }\n return result;\n}\n\nfunction coerceMandateType(v: unknown): AP2MandateType | null {\n if (v === 'intent_mandate' || v === 'cart_mandate' || v === 'payment_mandate') return v;\n return null;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n\nfunction coerceNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string') {\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\nfunction coerceStringOrNumber(v: unknown): string | number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && v.length > 0) return v;\n return undefined;\n}\n\nfunction sha256Sync(data: string | ArrayBuffer): Uint8Array {\n const buf =\n typeof data === 'string' ? Buffer.from(data, 'utf-8') : Buffer.from(new Uint8Array(data));\n const hash = createHash('sha256').update(buf).digest();\n return new Uint8Array(hash.buffer, hash.byteOffset, hash.byteLength);\n}\n","/**\n * AP2 mandate chain verification.\n *\n * Checks the cross-reference consistency of an intent → cart → payment\n * triple. Does NOT verify cryptographic signatures here (that's a call to\n * @sd-jwt/core which needs the agent's / CP's public key; expose via a\n * verifier callback so pipeline can plug in the right resolver).\n *\n * Rules (per AP2 spec v0.1-draft):\n * - cart.intent_mandate_id must equal the intent mandate's canonical id (if present)\n * - payment.cart_mandate_id must equal the cart mandate's canonical id (if present)\n * - agent_id must match across all three layers\n * - payment_method in payment mandate must be in intent.paymentMethods (if declared)\n * - cart totals must not exceed intent totals (if both declared in same currency)\n * - no mandate may be expired (beyond clock skew)\n */\n\nimport type { AP2MandateTriple } from './ap2';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface AP2VerifyInput {\n triple: AP2MandateTriple;\n /**\n * Clock skew tolerance in seconds for expiry checks. Default 60s\n * (tightened from the previous 300s default).\n */\n clockSkewSec?: number;\n now?: () => number;\n /**\n * Optional replay-protection store. Defaults to in-process LRU. When the\n * payment mandate carries an id, this verifier registers it as seen so\n * the same payment mandate replayed within the expiry window is rejected.\n */\n nonceStore?: NonceStore;\n}\n\nexport interface AP2ChainResult {\n ok: boolean;\n checks: {\n intentPresent: boolean;\n cartRefOk: boolean;\n paymentRefOk: boolean;\n agentIdContinuity: boolean;\n paymentMethodAllowed: boolean;\n totalsConsistent: boolean;\n expiryOk: boolean;\n };\n agentId?: string;\n errors: string[];\n}\n\nexport function verifyAP2Chain(input: AP2VerifyInput): AP2ChainResult {\n const { triple } = input;\n const errors: string[] = [];\n const toleranceSec = input.clockSkewSec ?? 60;\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n const intentPresent = triple.intent !== undefined;\n const cartRefOk = checkCartRef(triple, errors);\n const paymentRefOk = checkPaymentRef(triple, errors);\n const { ok: agentIdContinuity, agentId } = checkAgentContinuity(triple, errors);\n const paymentMethodAllowed = checkPaymentMethod(triple, errors);\n const totalsConsistent = checkTotals(triple, errors);\n const expiryOk = checkExpiries(triple, toleranceSec, input.now, errors);\n\n // Audit F-A1-05: replay protection. Register the payment mandate id (or\n // cart mandate id as fallback) so the same triple replayed within the\n // expiry window is rejected. Window matches the tolerance.\n let replayOk = true;\n const replayId = triple.payment?.raw?.id ?? triple.cart?.raw?.id;\n if (typeof replayId === 'string' && replayId.length > 0) {\n const now = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const expiresAt = (now + toleranceSec) * 1000;\n if (nonceStore.seen(`ap2:${replayId}`, expiresAt)) {\n errors.push(`AP2 chain replay — mandate ${replayId} already seen within tolerance window`);\n replayOk = false;\n }\n }\n\n const ok =\n cartRefOk &&\n paymentRefOk &&\n agentIdContinuity &&\n paymentMethodAllowed &&\n totalsConsistent &&\n expiryOk &&\n replayOk;\n\n return {\n ok,\n checks: {\n intentPresent,\n cartRefOk,\n paymentRefOk,\n agentIdContinuity,\n paymentMethodAllowed,\n totalsConsistent,\n expiryOk,\n },\n agentId,\n errors,\n };\n}\n\nfunction checkCartRef(triple: AP2MandateTriple, errors: string[]): boolean {\n const cart = triple.cart;\n if (!cart) return true;\n if (!cart.intent_mandate_id) return true;\n const intentId = triple.intent?.raw?.id as string | undefined;\n if (intentId && cart.intent_mandate_id !== intentId) {\n errors.push(\n `cart.intent_mandate_id (${cart.intent_mandate_id}) does not match intent.id (${intentId})`\n );\n return false;\n }\n return true;\n}\n\nfunction checkPaymentRef(triple: AP2MandateTriple, errors: string[]): boolean {\n const payment = triple.payment;\n if (!payment) return true;\n if (!payment.cart_mandate_id) return true;\n const cartId = triple.cart?.raw?.id as string | undefined;\n if (cartId && payment.cart_mandate_id !== cartId) {\n errors.push(\n `payment.cart_mandate_id (${payment.cart_mandate_id}) does not match cart.id (${cartId})`\n );\n return false;\n }\n return true;\n}\n\nfunction checkAgentContinuity(\n triple: AP2MandateTriple,\n errors: string[]\n): { ok: boolean; agentId?: string } {\n // Audit F-A1-03: previously returned ok: true when ids.length === 0,\n // letting agent_id-stripped triples pass. Now: at least one of the three\n // mandates must declare an agent_id. (If only some declare it, the unique\n // check still enforces consistency.)\n const ids = [triple.intent?.agent_id, triple.cart?.agent_id, triple.payment?.agent_id].filter(\n (id): id is string => typeof id === 'string' && id.length > 0\n );\n if (ids.length === 0) {\n errors.push('agent_id missing across all three mandates (intent/cart/payment)');\n return { ok: false };\n }\n const unique = new Set(ids);\n if (unique.size > 1) {\n errors.push(`agent_id mismatch across mandates: ${Array.from(unique).join(', ')}`);\n return { ok: false, agentId: undefined };\n }\n return { ok: true, agentId: ids[0] };\n}\n\nfunction checkPaymentMethod(triple: AP2MandateTriple, errors: string[]): boolean {\n const allowed = triple.intent?.paymentMethods;\n if (!allowed || allowed.length === 0) return true;\n // Audit F-A1-03: previously returned ok: true when payment_method missing,\n // letting strip-the-field attacks bypass the intent's paymentMethods\n // allowlist. Now: when payment mandate IS PRESENT, it MUST carry a\n // payment_method that the intent's allowlist authorises. Cart-only\n // flows (no payment mandate yet) are legitimate per AP2 spec — those\n // are exercised when the payment mandate is later signed; the\n // allowlist check fires at THAT point.\n if (!triple.payment) return true;\n const paymentMethod = triple.payment.payment_method;\n if (!paymentMethod) {\n errors.push(\n `payment.payment_method missing but intent declares allowlist [${allowed.join(', ')}]`\n );\n return false;\n }\n if (!allowed.includes(paymentMethod)) {\n errors.push(\n `payment_method \"${paymentMethod}\" not in intent.paymentMethods [${allowed.join(', ')}]`\n );\n return false;\n }\n return true;\n}\n\nfunction checkTotals(triple: AP2MandateTriple, errors: string[]): boolean {\n const intentTotal = toNumericAmount(triple.intent?.payment_details_total);\n const cartTotal = toNumericAmount(triple.cart?.payment_details_total);\n const paymentTotal = toNumericAmount(triple.payment?.payment_details_total);\n\n if (intentTotal && cartTotal && intentTotal.currency === cartTotal.currency) {\n if (cartTotal.value > intentTotal.value) {\n errors.push(\n `cart total ${cartTotal.value} ${cartTotal.currency} exceeds intent cap ${intentTotal.value}`\n );\n return false;\n }\n }\n if (cartTotal && paymentTotal && cartTotal.currency === paymentTotal.currency) {\n if (paymentTotal.value > cartTotal.value) {\n errors.push(\n `payment total ${paymentTotal.value} ${paymentTotal.currency} exceeds cart total ${cartTotal.value}`\n );\n return false;\n }\n }\n return true;\n}\n\nfunction checkExpiries(\n triple: AP2MandateTriple,\n toleranceSec: number,\n nowFn: (() => number) | undefined,\n errors: string[]\n): boolean {\n const now = nowFn ? nowFn() : Math.floor(Date.now() / 1000);\n let ok = true;\n\n // Audit F-A1-03: previously iterated only intent + cart; payment was\n // omitted, so expired payment mandates passed verification. Now includes\n // all three layers. AP2PaymentMandateClaims doesn't have a typed\n // `expires` field today (only intent/cart do); read from `raw.expires`\n // for payment as a defensive measure.\n const layers: Array<readonly [string, string | undefined]> = [\n ['intent', triple.intent?.expires],\n ['cart', triple.cart?.expires],\n [\n 'payment',\n typeof triple.payment?.raw?.expires === 'string'\n ? (triple.payment.raw.expires as string)\n : typeof triple.payment?.raw?.exp === 'string'\n ? (triple.payment.raw.exp as string)\n : undefined,\n ],\n ];\n\n for (const [name, expires] of layers) {\n if (!expires) continue;\n const parsed = parseExpiry(expires);\n if (parsed === null) {\n errors.push(`${name}.expires unparseable`);\n ok = false;\n continue;\n }\n if (now > parsed + toleranceSec) {\n errors.push(`${name} mandate expired at ${expires}`);\n ok = false;\n }\n }\n return ok;\n}\n\nfunction toNumericAmount(\n total: import('./ap2').AP2PaymentDetailsTotal | undefined\n): { value: number; currency: string } | null {\n if (!total?.amount?.value || !total.amount.currency) return null;\n const n =\n typeof total.amount.value === 'string' ? Number(total.amount.value) : total.amount.value;\n if (!Number.isFinite(n)) return null;\n return { value: n, currency: total.amount.currency };\n}\n\nfunction parseExpiry(value: string): number | null {\n const asInt = Number(value);\n if (Number.isFinite(asInt) && asInt > 0) {\n return asInt >= 1e12 ? Math.floor(asInt / 1000) : Math.floor(asInt);\n }\n const parsedDate = Date.parse(value);\n if (Number.isFinite(parsedDate)) return Math.floor(parsedDate / 1000);\n return null;\n}\n","/**\n * ACP detached-JSON-signature verifier.\n *\n * ACP (Agentic Commerce Protocol, OpenAI + Stripe) uses detached JSON\n * signatures over request bodies. The public signature algorithm is NOT\n * specified in open docs as of April 2026 (docs.stripe.com/agentic-commerce/*\n * is Private Preview). We implement Ed25519 and ES256 candidates against\n * whichever public key the caller supplies, and report algorithm-unsupported\n * as a trust signal rather than a hard fail so policy can weight it.\n *\n * Timestamp freshness (>300s default) IS a hard fail — prevents replay.\n *\n * Bearer-token → AstraSync agent binding is delegated to caller-supplied\n * resolver (typically the counterparty service).\n */\n\nimport type { JWK } from 'jose';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport type ACPSignatureAlgorithm = 'ed25519' | 'es256' | 'unsupported';\n\nexport interface ACPVerifyInput {\n /** Raw request body over which the signature was computed. */\n rawBody: string;\n /** Value of the Signature header. Expected to be base64 (either standard or url). */\n signatureHeader?: string;\n /** Value of the Timestamp header (unix seconds as string, or ISO 8601). */\n timestampHeader?: string;\n /** Candidate public keys to try. First matching algorithm wins. */\n candidateKeys: Array<{ jwk: JWK; alg?: ACPSignatureAlgorithm | string }>;\n /** Clock skew tolerance in seconds (default 60, tightened from 300). */\n clockSkewSec?: number;\n /** Injectable now for tests. */\n now?: () => number;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface ACPVerifyResult {\n ok: boolean;\n algorithm?: ACPSignatureAlgorithm;\n error?: string;\n /** True when timestamp is outside tolerance. */\n timestampStale?: boolean;\n}\n\nexport async function verifyACPSignature(input: ACPVerifyInput): Promise<ACPVerifyResult> {\n if (!input.signatureHeader) {\n return { ok: false, error: 'missing Signature header' };\n }\n\n const tolerance = input.clockSkewSec ?? 60;\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n const freshness = checkTimestamp(input.timestampHeader, tolerance, input.now);\n if (!freshness.ok) {\n return { ok: false, error: freshness.error, timestampStale: true };\n }\n\n // Audit F-A1-05: replay protection. Header comment claimed \"Timestamp\n // freshness IS a hard fail — prevents replay\" but implementation didn't\n // enforce it. Key on (signature header, timestamp) so the same signature\n // submitted twice within tolerance is rejected.\n const nowSec = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const expiresAtMs = (nowSec + tolerance) * 1000;\n const replayKey = `acp:${input.signatureHeader}:${input.timestampHeader ?? ''}`;\n if (nonceStore.seen(replayKey, expiresAtMs)) {\n return {\n ok: false,\n error: 'ACP signature replay — already seen within tolerance window',\n };\n }\n\n const signatureBytes = decodeBase64(input.signatureHeader);\n if (!signatureBytes) {\n return { ok: false, error: 'signature header is not valid base64' };\n }\n\n const bodyBytes = new TextEncoder().encode(input.rawBody);\n const { subtle } = await getSubtle();\n\n for (const candidate of input.candidateKeys) {\n const declaredAlg = normalizeAlgorithm(candidate.alg);\n const algsToTry: ACPSignatureAlgorithm[] =\n declaredAlg && declaredAlg !== 'unsupported' ? [declaredAlg] : ['ed25519', 'es256'];\n\n for (const alg of algsToTry) {\n try {\n const verified = await tryVerify(subtle, candidate.jwk, signatureBytes, bodyBytes, alg);\n if (verified) return { ok: true, algorithm: alg };\n } catch {\n // swallow per-candidate errors; try next algorithm/candidate\n }\n }\n }\n\n return {\n ok: false,\n algorithm: 'unsupported',\n error: 'no candidate key verified the signature under Ed25519 or ES256',\n };\n}\n\nasync function tryVerify(\n subtle: SubtleCrypto,\n jwk: JWK,\n signature: Uint8Array,\n body: Uint8Array,\n alg: ACPSignatureAlgorithm\n): Promise<boolean> {\n if (alg === 'ed25519') {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') return false;\n const key = await subtle.importKey('jwk', jwk as JsonWebKey, { name: 'Ed25519' }, false, [\n 'verify',\n ]);\n return await subtle.verify({ name: 'Ed25519' }, key, toBuf(signature), toBuf(body));\n }\n if (alg === 'es256') {\n if (jwk.kty !== 'EC' || jwk.crv !== 'P-256') return false;\n const key = await subtle.importKey(\n 'jwk',\n jwk as JsonWebKey,\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['verify']\n );\n return await subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n key,\n toBuf(signature),\n toBuf(body)\n );\n }\n return false;\n}\n\nfunction toBuf(bytes: Uint8Array): ArrayBuffer {\n const out = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(out).set(bytes);\n return out;\n}\n\nfunction checkTimestamp(\n headerValue: string | undefined,\n toleranceSec: number,\n nowFn?: () => number\n): { ok: true } | { ok: false; error: string } {\n if (!headerValue) return { ok: false, error: 'missing Timestamp header' };\n const ts = parseTimestamp(headerValue);\n if (ts === null) return { ok: false, error: 'unparseable Timestamp header' };\n const now = nowFn ? nowFn() : Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > toleranceSec) {\n return { ok: false, error: `timestamp outside ${toleranceSec}s tolerance` };\n }\n return { ok: true };\n}\n\nfunction parseTimestamp(value: string): number | null {\n const asInt = Number(value);\n if (Number.isFinite(asInt) && asInt > 0) {\n // Treat >= 1e12 as milliseconds; otherwise seconds.\n return asInt >= 1e12 ? Math.floor(asInt / 1000) : Math.floor(asInt);\n }\n const parsedDate = Date.parse(value);\n if (Number.isFinite(parsedDate)) return Math.floor(parsedDate / 1000);\n return null;\n}\n\nfunction normalizeAlgorithm(alg: string | undefined): ACPSignatureAlgorithm | undefined {\n if (!alg) return undefined;\n const lowered = alg.toLowerCase();\n if (lowered === 'ed25519' || lowered === 'eddsa') return 'ed25519';\n if (lowered === 'es256' || lowered.startsWith('ecdsa-p256')) return 'es256';\n return 'unsupported';\n}\n\nfunction decodeBase64(value: string): Uint8Array | null {\n try {\n // Accept either standard base64 or url-safe; jose and node both accept both via Buffer.\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const pad = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));\n return new Uint8Array(Buffer.from(normalized + pad, 'base64'));\n } catch {\n return null;\n }\n}\n\nasync function getSubtle(): Promise<{ subtle: SubtleCrypto }> {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n return { subtle: globalThis.crypto.subtle };\n }\n const nodeCrypto = await import('node:crypto');\n return { subtle: nodeCrypto.webcrypto.subtle as SubtleCrypto };\n}\n","/**\n * MPP (Machine Payments Protocol) extractor.\n *\n * Wraps mppx (wevm) — pinned to 0.5.13, wrapped behind this adapter so\n * upgrades localise here. MPP launched March 18 2026 (Stripe + Tempo +\n * Paradigm), IETF draft-ryan-httpauth-payment-01.\n *\n * Flow:\n * Client → GET /resource\n * Server → 402 + WWW-Authenticate: Payment id=..., realm=..., method=tempo|stripe|...\n * Client → GET /resource with Authorization: Payment <base64url-json credential>\n * Server → 200 + Payment-Receipt: <base64url-json receipt>\n *\n * What we extract:\n * - Challenge: id, realm, method, intent, request{amount,currency,...}, expires, digest\n * - Credential: challenge + source (DID/chain-key) + payload (method-specific)\n * - Receipt: challengeId, method, reference (tx hash / pi_... ID), settlement\n * - Multi-method 402 offers (may be multiple WWW-Authenticate headers)\n *\n * What we do NOT verify here (pass-through):\n * - HMAC challenge binding (requires merchant's MPP_SECRET_KEY)\n * - Payment proof cryptography (Tempo tx sig, Stripe SPT, Lightning preimage)\n * — each requires upstream connectivity\n *\n * Verification (expiry + BodyDigest + source extraction) in mpp-verify.ts.\n */\n\nimport { Challenge, Credential, Receipt } from 'mppx';\n\nexport interface MPPChallengeSummary {\n id: string;\n realm: string;\n method: string;\n intent: string;\n /** Method-specific request data (amount, currency, recipient, etc.) */\n request: Record<string, unknown>;\n expires?: string;\n digest?: string;\n description?: string;\n opaque?: Record<string, string>;\n}\n\nexport interface MPPCredentialSummary {\n challenge: MPPChallengeSummary;\n /** DID or chain-native key identifying the payer. */\n source?: string;\n /** Method-specific payment proof (Tempo tx, SPT, Lightning preimage, etc.). */\n payload: unknown;\n}\n\nexport interface MPPReceiptSummary {\n method?: string;\n reference?: string;\n externalId?: string;\n status?: string;\n timestamp?: string;\n raw: Record<string, unknown>;\n}\n\nexport type MPPKind = 'challenge' | 'credential' | 'receipt' | 'error' | 'unknown';\n\nexport interface MPPRequestContext {\n kind: MPPKind;\n /** For 402 responses: one or more challenge offers. */\n challenges?: MPPChallengeSummary[];\n /** For requests with Authorization: Payment header. */\n credential?: MPPCredentialSummary;\n /** For 200 responses with Payment-Receipt header. */\n receipt?: MPPReceiptSummary;\n /** For problem+json error responses. */\n error?: { type?: string; title?: string; detail?: string };\n /** Detected payment methods offered (for multi-method 402). */\n offeredMethods?: string[];\n /** Raw body captured for BodyDigest verification in mpp-verify.ts. */\n rawBody?: string;\n}\n\nexport interface MPPRequestLike {\n method: string;\n url: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: string;\n}\n\nexport interface MPPResponseLike {\n status: number;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: string;\n}\n\n/**\n * Extract MPP context from an agent → merchant request.\n * Looks for `Authorization: Payment <credential>` header.\n */\nexport function extractMPPFromRequest(request: MPPRequestLike): MPPRequestContext | null {\n const auth = readHeader(request.headers, 'authorization');\n if (!auth || !/^\\s*Payment\\s+/i.test(auth)) return null;\n\n try {\n const credential = Credential.deserialize(auth);\n return {\n kind: 'credential',\n credential: {\n challenge: summarizeChallenge(credential.challenge),\n source: credential.source,\n payload: credential.payload,\n },\n rawBody: request.rawBody,\n };\n } catch {\n return { kind: 'error', error: { type: 'invalid-credential-encoding' } };\n }\n}\n\n/**\n * Extract MPP context from a merchant → agent response.\n * Handles 402 (challenge offers), 200 (receipt), 4xx (problem+json errors).\n */\nexport function extractMPPFromResponse(response: MPPResponseLike): MPPRequestContext | null {\n if (response.status === 402) {\n const challenges = collectChallenges(response);\n if (challenges.length === 0) return null;\n const methods = Array.from(new Set(challenges.map((c) => c.method)));\n return {\n kind: 'challenge',\n challenges,\n offeredMethods: methods,\n };\n }\n\n const receiptHeader = readHeader(response.headers, 'payment-receipt');\n if (receiptHeader) {\n try {\n const parsed = Receipt.deserialize(receiptHeader);\n const r = parsed as unknown as Record<string, unknown>;\n return {\n kind: 'receipt',\n receipt: {\n method: coerceString(r.method),\n reference: coerceString(r.reference),\n externalId: coerceString(r.externalId ?? r.external_id),\n status: coerceString(r.status),\n timestamp: coerceString(r.timestamp),\n raw: r,\n },\n };\n } catch {\n return { kind: 'error', error: { type: 'invalid-receipt-encoding' } };\n }\n }\n\n const contentType = readHeader(response.headers, 'content-type');\n if (contentType && /application\\/problem\\+json/i.test(contentType)) {\n const body =\n typeof response.body === 'object' && response.body !== null\n ? (response.body as Record<string, unknown>)\n : {};\n return {\n kind: 'error',\n error: {\n type: coerceString(body.type),\n title: coerceString(body.title),\n detail: coerceString(body.detail),\n },\n };\n }\n\n return null;\n}\n\n/**\n * Extract from either a request OR a response, auto-detecting which has MPP\n * artifacts. Convenience for pipeline callers.\n */\nexport function extractMPPContext(\n message:\n | { request: MPPRequestLike }\n | { response: MPPResponseLike }\n | (MPPRequestLike & Partial<MPPResponseLike>)\n): MPPRequestContext | null {\n if ('request' in message) return extractMPPFromRequest(message.request);\n if ('response' in message) return extractMPPFromResponse(message.response);\n if (typeof (message as MPPResponseLike).status === 'number') {\n return extractMPPFromResponse(message as MPPResponseLike);\n }\n return extractMPPFromRequest(message as MPPRequestLike);\n}\n\nfunction collectChallenges(response: MPPResponseLike): MPPChallengeSummary[] {\n const wwwAuth = readHeader(response.headers, 'www-authenticate');\n if (!wwwAuth) return [];\n const headers = new Headers();\n headers.set('www-authenticate', wwwAuth);\n\n const out: MPPChallengeSummary[] = [];\n try {\n const list = Challenge.fromHeadersList(headers);\n for (const ch of list) {\n out.push(summarizeChallenge(ch as unknown as Challenge.Challenge));\n }\n } catch {\n // fall through with empty list\n }\n return out;\n}\n\nfunction summarizeChallenge(\n ch: Challenge.Challenge | Record<string, unknown>\n): MPPChallengeSummary {\n const raw = ch as Record<string, unknown>;\n return {\n id: coerceString(raw.id) ?? '',\n realm: coerceString(raw.realm) ?? '',\n method: coerceString(raw.method) ?? '',\n intent: coerceString(raw.intent) ?? '',\n request: (raw.request as Record<string, unknown>) ?? {},\n expires: coerceString(raw.expires),\n digest: coerceString(raw.digest),\n description: coerceString(raw.description),\n opaque: raw.opaque as Record<string, string> | undefined,\n };\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | undefined {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw.join(', ');\n }\n }\n return undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * MPP verification — expiry + optional BodyDigest + source extraction.\n *\n * We do NOT verify the challenge's HMAC binding (needs merchant's secret)\n * or the cryptographic payment proof (per-method, requires upstream\n * connectivity). Those are the merchant's / settlement layer's job.\n *\n * Our job: structural correctness, expiry policy, tamper detection via\n * optional BodyDigest, and identity extraction for PDLSS binding.\n */\n\nimport { BodyDigest } from 'mppx';\nimport type { MPPRequestContext } from './mpp';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface MPPVerifyInput {\n context: MPPRequestContext;\n /** Raw request body to validate BodyDigest against, if the challenge declares one. */\n rawBody?: string;\n /** Seconds of clock-skew tolerance on challenge.expires. Default 60. */\n clockSkewSec?: number;\n /** Injectable for deterministic tests. */\n now?: () => number;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface MPPVerifyResult {\n ok: boolean;\n expiryOk: boolean;\n bodyDigestOk: boolean | null;\n source?: string;\n method?: string;\n error?: string;\n}\n\nexport function verifyMPP(input: MPPVerifyInput): MPPVerifyResult {\n const { context } = input;\n const tolerance = input.clockSkewSec ?? 60;\n const nowSec = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n // Extract the challenge under test — for credential flow, from inside the\n // wrapped challenge; for bare challenge flow, from context.challenges[0].\n const challenge = context.credential?.challenge ?? (context.challenges && context.challenges[0]);\n const source = context.credential?.source;\n const method = challenge?.method;\n\n let expiryOk = true;\n if (challenge?.expires) {\n const parsedExpiry = Date.parse(challenge.expires);\n if (!Number.isFinite(parsedExpiry)) {\n return {\n ok: false,\n expiryOk: false,\n bodyDigestOk: null,\n source,\n method,\n error: 'unparseable challenge.expires',\n };\n }\n const expiresSec = Math.floor(parsedExpiry / 1000);\n if (nowSec > expiresSec + tolerance) {\n expiryOk = false;\n }\n }\n\n // Audit F-A1-04: previously when rawBody was present but the challenge\n // omitted `digest`, bodyDigestOk stayed `null` and was treated as OK.\n // Attacker could strip the digest field from the challenge and tamper\n // with body. Now: when rawBody is present, digest is REQUIRED.\n let bodyDigestOk: boolean | null = null;\n if (input.rawBody !== undefined) {\n if (!challenge?.digest) {\n bodyDigestOk = false;\n } else {\n try {\n if (!/^sha-256=/.test(challenge.digest)) {\n bodyDigestOk = false;\n } else {\n bodyDigestOk = BodyDigest.verify(challenge.digest as `sha-256=${string}`, input.rawBody);\n }\n } catch {\n bodyDigestOk = false;\n }\n }\n }\n\n // Audit F-A1-05: replay protection. Use challenge nonce + digest as\n // replay key when available; fall back to digest alone. Window matches\n // the expiry tolerance.\n let replayOk = true;\n if (challenge?.digest && expiryOk) {\n const replayKey = `mpp:${challenge.digest}:${(challenge as { nonce?: string }).nonce ?? ''}`;\n const expiresAt = (nowSec + tolerance) * 1000;\n if (nonceStore.seen(replayKey, expiresAt)) {\n replayOk = false;\n }\n }\n\n const ok = expiryOk && (bodyDigestOk === null || bodyDigestOk === true) && replayOk;\n const errors: string[] = [];\n if (!expiryOk) errors.push('challenge expired');\n if (bodyDigestOk === false) {\n errors.push(\n input.rawBody !== undefined && !challenge?.digest\n ? 'body digest required when rawBody present'\n : 'body digest mismatch'\n );\n }\n if (!replayOk) errors.push('MPP challenge replay — already seen within tolerance window');\n\n return {\n ok,\n expiryOk,\n bodyDigestOk,\n source,\n method,\n error: errors.length > 0 ? errors.join('; ') : undefined,\n };\n}\n","/**\n * x402 (Coinbase / Linux Foundation x402 Foundation) extractor.\n *\n * Wraps @x402/core's schema parsers. x402 Foundation launched April 2 2026\n * with v2 adding network-agnostic identifiers + multiple facilitators +\n * Bazaar discovery. MPP (Machine Payments Protocol) is the IETF-formalised\n * superset of x402; this module normalizes x402 output to MPP-shape so\n * downstream pipeline code is uniform.\n *\n * Where x402 lives on the wire:\n * - 402 response body (v2) OR `X-PAYMENT-REQUIRED` header (v1) — PaymentRequired\n * - Request body (v2) OR `X-PAYMENT` header (v1, base64) — PaymentPayload\n */\n\nimport {\n validatePaymentRequired,\n validatePaymentPayload,\n type PaymentRequired,\n type PaymentPayload,\n type PaymentRequirements,\n} from '@x402/core/schemas';\nimport { safeBase64Decode } from '@x402/core/utils';\n\nexport type X402Kind = 'required' | 'payload' | 'error' | 'unknown';\n\nexport interface X402RequirementsSummary {\n scheme: string;\n network: string;\n asset: string;\n /** Normalized to string for v1/v2 compat — v1 uses maxAmountRequired, v2 uses amount. */\n amount: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n resource?: string;\n description?: string;\n}\n\nexport interface X402RequestContext {\n kind: X402Kind;\n version: 1 | 2 | null;\n /** For 402 responses: the PaymentRequired body. */\n paymentRequired?: {\n resource: string;\n accepts: X402RequirementsSummary[];\n extensions?: Record<string, unknown>;\n error?: string;\n };\n /** For request body (v2) or X-PAYMENT header (v1 base64): the PaymentPayload. */\n paymentPayload?: {\n scheme: string;\n network: string;\n /** Free-form per-scheme payload (e.g. EIP-3009 authorization, Solana tx). */\n payload: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n };\n error?: { type: string; detail?: string };\n /** Whether this was parsed from a header (v1 back-compat) or body (v2). */\n source: 'header' | 'body' | null;\n}\n\nexport interface X402RequestLike {\n method?: string;\n url?: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\nexport interface X402ResponseLike {\n status?: number;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\n/**\n * Extract x402 PaymentPayload from an agent → merchant request.\n * Checks v2 body (if it parses as PaymentPayload) and v1 X-PAYMENT header.\n */\nexport function extractX402FromRequest(request: X402RequestLike): X402RequestContext | null {\n const headerValue = readHeader(request.headers, 'x-payment');\n\n // v2 body path first\n if (request.body && typeof request.body === 'object') {\n const parsed = tryParsePayload(request.body);\n if (parsed) return buildPayloadContext(parsed, 'body');\n }\n\n // v1 header path\n if (headerValue) {\n try {\n const decoded = safeBase64Decode(headerValue);\n if (decoded) {\n const json = JSON.parse(decoded);\n const parsed = tryParsePayload(json);\n if (parsed) return buildPayloadContext(parsed, 'header');\n }\n } catch {\n return {\n kind: 'error',\n version: 1,\n source: 'header',\n error: { type: 'invalid-x402-payload' },\n };\n }\n }\n\n return null;\n}\n\n/**\n * Extract x402 PaymentRequired from a merchant → agent 402 response.\n */\nexport function extractX402FromResponse(response: X402ResponseLike): X402RequestContext | null {\n if (response.status !== 402) return null;\n\n // v2 body path\n if (response.body && typeof response.body === 'object') {\n const parsed = tryParseRequired(response.body);\n if (parsed) return buildRequiredContext(parsed, 'body');\n }\n\n // v1 header path\n const headerValue = readHeader(response.headers, 'x-payment-required');\n if (headerValue) {\n try {\n const decoded = safeBase64Decode(headerValue);\n if (decoded) {\n const json = JSON.parse(decoded);\n const parsed = tryParseRequired(json);\n if (parsed) return buildRequiredContext(parsed, 'header');\n }\n } catch {\n return {\n kind: 'error',\n version: 1,\n source: 'header',\n error: { type: 'invalid-x402-required' },\n };\n }\n }\n\n return null;\n}\n\nexport function extractX402Context(\n message:\n | { request: X402RequestLike }\n | { response: X402ResponseLike }\n | (X402RequestLike & Partial<X402ResponseLike>)\n): X402RequestContext | null {\n if ('request' in message) return extractX402FromRequest(message.request);\n if ('response' in message) return extractX402FromResponse(message.response);\n if (typeof (message as X402ResponseLike).status === 'number') {\n return extractX402FromResponse(message as X402ResponseLike);\n }\n return extractX402FromRequest(message as X402RequestLike);\n}\n\nfunction tryParseRequired(data: unknown): PaymentRequired | null {\n try {\n return validatePaymentRequired(data);\n } catch {\n return null;\n }\n}\n\nfunction tryParsePayload(data: unknown): PaymentPayload | null {\n try {\n return validatePaymentPayload(data);\n } catch {\n return null;\n }\n}\n\nfunction buildRequiredContext(\n parsed: PaymentRequired,\n source: 'header' | 'body'\n): X402RequestContext {\n const asRecord = parsed as unknown as Record<string, unknown>;\n const version = coerceVersion(asRecord.x402Version);\n const accepts = (asRecord.accepts as PaymentRequirements[] | undefined) ?? [];\n return {\n kind: 'required',\n version,\n source,\n paymentRequired: {\n resource: resolveResource(asRecord.resource),\n accepts: accepts.map(summarizeRequirement),\n extensions: asRecord.extensions as Record<string, unknown> | undefined,\n error: typeof asRecord.error === 'string' ? asRecord.error : undefined,\n },\n };\n}\n\nfunction buildPayloadContext(\n parsed: PaymentPayload,\n source: 'header' | 'body'\n): X402RequestContext {\n const asRecord = parsed as unknown as Record<string, unknown>;\n const version = coerceVersion(asRecord.x402Version);\n const accepted = asRecord.accepted as PaymentRequirements | undefined;\n const payload = (asRecord.payload as Record<string, unknown>) ?? {};\n return {\n kind: 'payload',\n version,\n source,\n paymentPayload: {\n scheme: accepted?.scheme ?? (typeof asRecord.scheme === 'string' ? asRecord.scheme : ''),\n network: accepted?.network ?? (typeof asRecord.network === 'string' ? asRecord.network : ''),\n payload,\n extensions: asRecord.extensions as Record<string, unknown> | undefined,\n },\n };\n}\n\nfunction summarizeRequirement(req: PaymentRequirements): X402RequirementsSummary {\n const r = req as unknown as Record<string, unknown>;\n const amount = (r.amount ?? r.maxAmountRequired ?? '0') as string;\n return {\n scheme: (r.scheme as string) ?? '',\n network: (r.network as string) ?? '',\n asset: (r.asset as string) ?? '',\n amount: String(amount),\n payTo: (r.payTo as string) ?? '',\n maxTimeoutSeconds: typeof r.maxTimeoutSeconds === 'number' ? r.maxTimeoutSeconds : undefined,\n resource: typeof r.resource === 'string' ? r.resource : undefined,\n description: typeof r.description === 'string' ? r.description : undefined,\n };\n}\n\nfunction resolveResource(v: unknown): string {\n if (typeof v === 'string') return v;\n if (v && typeof v === 'object' && 'url' in v && typeof (v as { url: unknown }).url === 'string') {\n return (v as { url: string }).url;\n }\n return '';\n}\n\nfunction coerceVersion(v: unknown): 1 | 2 | null {\n if (v === 1 || v === 2) return v;\n return null;\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined> | undefined,\n name: string\n): string | undefined {\n if (!headers) return undefined;\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw[0];\n }\n }\n return undefined;\n}\n","/**\n * VI (Verifiable Intent) 3-layer SD-JWT chain verification.\n *\n * VI chains: L1 (credential provider → wallet) → L2 (user → agent) → L3\n * (agent → merchant). L3 itself can split into L3a (payment mandate) + L3b\n * (checkout mandate) cross-referenced via transaction_id, with L3b carrying\n * a checkout_hash (VI constraint type 8) that must match SHA-256 of the L2\n * checkout disclosure.\n *\n * Signature primitives are delegated to @sd-jwt/core (via our extractor);\n * cnf.jwk chain-walking + cross-references + checkout_hash binding is\n * AstraSync-specific composition logic — that's the whitespace here.\n *\n * This module does NOT re-verify selective-disclosure hashes (the extractor\n * already applied them via @sd-jwt/core). It DOES verify:\n * - cnf.jwk in L1 payload points to L2's signing key (thumbprint match)\n * - cnf.jwk in L2 payload points to L3's signing key\n * - L3a.transaction_id === L3b.transaction_id (when both present)\n * - L3b.checkout_hash === SHA-256(L2 canonical checkout disclosure) — type 8\n * - mandate-level `exp` is not in the past (beyond clock skew)\n *\n * Cryptographic signature verification on each layer uses the verifier\n * callback the caller supplies (e.g. resolves via @sd-jwt/core with the\n * right JWK from the L1 issuer's JWKS).\n */\n\nimport { createHash, webcrypto } from 'node:crypto';\nimport type { JWK } from 'jose';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface VILayer {\n /** Compact SD-JWT / JWS for this layer. */\n compact: string;\n /** Decoded JWT payload (already disclosure-merged). */\n payload: Record<string, unknown>;\n /** Decoded JWT header. */\n header: Record<string, unknown>;\n}\n\nexport interface VIVerifyInput {\n /**\n * Layers in chain order. L1 is REQUIRED by default —\n * without L1 there is no chain root and L2 can be verified against any\n * attacker-supplied key. Callers who have resolved L2's signing key by\n * a trusted out-of-band mechanism (wallet binding, prior protocol step)\n * MUST set `allowUnboundChain: true` AND supply `expectedL2Key`.\n */\n layers: {\n l1?: VILayer;\n l2: VILayer;\n l3a?: VILayer;\n l3b?: VILayer;\n };\n /**\n * Verifier callback invoked per layer. Should return true iff the layer's\n * JWS signature verifies against the resolved public key (for L2 this is\n * L1's cnf.jwk; for L3 this is L2's cnf.jwk; for L1 this is the issuer's\n * JWKS per `iss` claim).\n */\n verifySignature: (layer: VILayer, expectedKey: JWK | null) => Promise<boolean>;\n /**\n * Clock skew tolerance in seconds for expiry checks. Default 60s\n * (tightened from the previous 300s default).\n */\n clockSkewSec?: number;\n now?: () => number;\n /**\n * Explicit opt-in to verify a chain with L1 omitted.\n * Defaults to false. When true, `expectedL2Key` MUST also be supplied\n * (used as the expected signing key for L2 verification).\n */\n allowUnboundChain?: boolean;\n /** Required when allowUnboundChain === true. */\n expectedL2Key?: JWK;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface VIVerifyResult {\n ok: boolean;\n checks: {\n l1SigOk: boolean | null;\n l2SigOk: boolean;\n l3aSigOk: boolean | null;\n l3bSigOk: boolean | null;\n l1BindsL2: boolean;\n l2BindsL3: boolean;\n l3aL3bTxnIdMatch: boolean | null;\n checkoutHashOk: boolean | null;\n expiryOk: boolean;\n };\n errors: string[];\n}\n\nexport async function verifyVIChain(input: VIVerifyInput): Promise<VIVerifyResult> {\n const errors: string[] = [];\n const tolerance = input.clockSkewSec ?? 60;\n const now = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const { l1, l2, l3a, l3b } = input.layers;\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n // Audit F-A1-02: L1 is required unless caller explicitly opts into an\n // unbound chain AND supplies the expected L2 signing key. Otherwise L2\n // would be verified against null, which most verifier callbacks\n // interpret as \"use the JWK in the JWS header\" — accepting any\n // attacker-supplied key.\n if (!l1) {\n if (!input.allowUnboundChain) {\n errors.push(\n 'L1 missing — chain root unbound (set allowUnboundChain + expectedL2Key to override)'\n );\n } else if (!input.expectedL2Key) {\n errors.push('allowUnboundChain set but expectedL2Key missing');\n }\n }\n\n // Signature verification ---------------------------------\n const l1SigOk = l1 ? await input.verifySignature(l1, null) : null;\n if (l1 && !l1SigOk) errors.push('L1 signature invalid');\n\n const l1Cnf = extractCnfJwk(l1?.payload);\n // Use L1's cnf.jwk when L1 present; otherwise (opt-in unbound chain) use\n // the caller-supplied expectedL2Key. Never null — F-A1-02.\n const l2ExpectedKey: JWK | null = l1Cnf ?? input.expectedL2Key ?? null;\n const l2SigOk = await input.verifySignature(l2, l2ExpectedKey);\n if (!l2SigOk) errors.push('L2 signature invalid');\n\n // Audit F-A1-05: replay protection on L2 signature. Use the compact JWS\n // as the nonce key; the signature is unique per request. Window matches\n // tolerance (denied replays past the window are already rejected by\n // expiry check, so we don't need to retain entries longer).\n if (l2SigOk) {\n const replayKey = `vi:l2:${l2.compact}`;\n const expiresAt = now * 1000 + tolerance * 1000;\n if (nonceStore.seen(replayKey, expiresAt)) {\n errors.push('L2 signature replay — already seen within tolerance window');\n }\n }\n\n const l2Cnf = extractCnfJwk(l2.payload);\n const l3aSigOk = l3a ? await input.verifySignature(l3a, l2Cnf ?? null) : null;\n if (l3a && !l3aSigOk) errors.push('L3a signature invalid');\n const l3bSigOk = l3b ? await input.verifySignature(l3b, l2Cnf ?? null) : null;\n if (l3b && !l3bSigOk) errors.push('L3b signature invalid');\n\n // cnf.jwk binding ----------------------------------------\n let l1BindsL2 = true;\n if (l1Cnf) {\n const l2KeyFromHeader = await jwkForLayer(l2);\n l1BindsL2 = l2KeyFromHeader ? await thumbprintsMatch(l1Cnf, l2KeyFromHeader) : false;\n if (!l1BindsL2) errors.push('L1.cnf.jwk does not bind L2 signing key');\n }\n\n let l2BindsL3 = true;\n if (l2Cnf && (l3a || l3b)) {\n const l3Layer = l3a ?? l3b!;\n const l3KeyFromHeader = await jwkForLayer(l3Layer);\n l2BindsL3 = l3KeyFromHeader ? await thumbprintsMatch(l2Cnf, l3KeyFromHeader) : false;\n if (!l2BindsL3) errors.push('L2.cnf.jwk does not bind L3 signing key');\n }\n\n // L3a/L3b cross-reference --------------------------------\n let l3aL3bTxnIdMatch: boolean | null = null;\n if (l3a && l3b) {\n const a = coerceString(l3a.payload.transaction_id ?? l3a.payload.transactionId);\n const b = coerceString(l3b.payload.transaction_id ?? l3b.payload.transactionId);\n if (a && b) {\n l3aL3bTxnIdMatch = a === b;\n if (!l3aL3bTxnIdMatch) {\n errors.push(`L3a.transaction_id (${a}) does not match L3b.transaction_id (${b})`);\n }\n }\n }\n\n // checkout_hash (VI constraint type 8) -------------------\n let checkoutHashOk: boolean | null = null;\n if (l3b) {\n const declaredHash = coerceString(\n l3b.payload.checkout_hash ??\n l3b.payload.conditional_transaction_id ??\n (l3b.payload.payment_reference as Record<string, unknown> | undefined)?.checkout_hash\n );\n if (declaredHash) {\n const computed = computeCheckoutHashFromL2(l2);\n checkoutHashOk = computed ? declaredHash === computed : false;\n if (!checkoutHashOk) {\n errors.push('L3b.checkout_hash does not match SHA-256 of L2 checkout disclosure');\n }\n }\n }\n\n // Expiry policy ------------------------------------------\n const expiryOk = checkExpiryAcross([l1, l2, l3a, l3b], tolerance, now, errors);\n\n // Audit F-A1-02 + F-A1-05: ok also requires the chain-root + replay\n // checks above to have passed (errors array captures both). Previously\n // `ok` was derived purely from individual check booleans, so the L1-\n // required errors and replay-detected errors didn't gate it.\n const noUnboundChainOrReplayErrors = !errors.some(\n (e) =>\n e.startsWith('L1 missing') ||\n e.startsWith('allowUnboundChain set') ||\n e.startsWith('L2 signature replay')\n );\n\n const ok =\n l1SigOk !== false &&\n l2SigOk &&\n l3aSigOk !== false &&\n l3bSigOk !== false &&\n l1BindsL2 &&\n l2BindsL3 &&\n l3aL3bTxnIdMatch !== false &&\n checkoutHashOk !== false &&\n expiryOk &&\n noUnboundChainOrReplayErrors;\n\n return {\n ok,\n checks: {\n l1SigOk,\n l2SigOk,\n l3aSigOk,\n l3bSigOk,\n l1BindsL2,\n l2BindsL3,\n l3aL3bTxnIdMatch,\n checkoutHashOk,\n expiryOk,\n },\n errors,\n };\n}\n\nfunction extractCnfJwk(payload: Record<string, unknown> | undefined): JWK | null {\n if (!payload) return null;\n const cnf = payload.cnf as Record<string, unknown> | undefined;\n if (!cnf) return null;\n const jwk = cnf.jwk as JWK | undefined;\n return jwk ?? null;\n}\n\nasync function jwkForLayer(layer: VILayer): Promise<JWK | null> {\n // Prefer explicit cnf.jwk in the header, then payload; fallback to null.\n const fromHeader = extractCnfJwk(layer.header);\n if (fromHeader) return fromHeader;\n const fromPayload = extractCnfJwk(layer.payload);\n return fromPayload;\n}\n\nasync function thumbprintsMatch(a: JWK, b: JWK): Promise<boolean> {\n try {\n const ta = await jwkThumbprint(a);\n const tb = await jwkThumbprint(b);\n return ta === tb;\n } catch {\n return false;\n }\n}\n\n// RFC 7638 thumbprint: SHA-256 over the canonical JSON of required JWK members.\nasync function jwkThumbprint(jwk: JWK): Promise<string> {\n const canonical = canonicalJwk(jwk);\n const bytes = new TextEncoder().encode(JSON.stringify(canonical));\n const subtle = webcrypto.subtle as SubtleCrypto;\n const buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n const source = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(source).set(bytes);\n subtle.digest('SHA-256', source).then(resolve).catch(reject);\n });\n return Buffer.from(new Uint8Array(buffer)).toString('base64url').replace(/=+$/, '');\n}\n\nfunction canonicalJwk(jwk: JWK): Record<string, string> {\n // Per RFC 7638: members must appear in lexicographic order; only required\n // fields per kty are included.\n if (jwk.kty === 'EC') {\n return { crv: jwk.crv ?? '', kty: 'EC', x: jwk.x ?? '', y: jwk.y ?? '' };\n }\n if (jwk.kty === 'OKP') {\n return { crv: jwk.crv ?? '', kty: 'OKP', x: jwk.x ?? '' };\n }\n if (jwk.kty === 'RSA') {\n return { e: jwk.e ?? '', kty: 'RSA', n: jwk.n ?? '' };\n }\n return { kty: jwk.kty ?? '' };\n}\n\nfunction computeCheckoutHashFromL2(l2: VILayer): string | null {\n const checkoutDisclosure = (l2.payload.checkout ?? l2.payload.checkout_mandate) as unknown;\n if (!checkoutDisclosure) return null;\n const canonical = canonicalStringify(checkoutDisclosure);\n const hash = createHash('sha256').update(canonical).digest('base64url').replace(/=+$/, '');\n return hash;\n}\n\nfunction canonicalStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return '[' + value.map(canonicalStringify).join(',') + ']';\n const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>\n a < b ? -1 : a > b ? 1 : 0\n );\n return (\n '{' + entries.map(([k, v]) => JSON.stringify(k) + ':' + canonicalStringify(v)).join(',') + '}'\n );\n}\n\nfunction checkExpiryAcross(\n layers: Array<VILayer | undefined>,\n toleranceSec: number,\n nowSec: number,\n errors: string[]\n): boolean {\n let ok = true;\n const names = ['L1', 'L2', 'L3a', 'L3b'];\n layers.forEach((layer, idx) => {\n if (!layer) return;\n const exp = toUnixSeconds(layer.payload.exp ?? layer.payload.expires);\n if (exp === undefined) return;\n if (nowSec > exp + toleranceSec) {\n errors.push(`${names[idx]} mandate expired at ${exp}`);\n ok = false;\n }\n });\n return ok;\n}\n\nfunction toUnixSeconds(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string') {\n const asInt = Number(v);\n if (Number.isFinite(asInt) && asInt > 0) {\n return asInt >= 1e12 ? Math.floor(asInt / 1000) : Math.floor(asInt);\n }\n const parsed = Date.parse(v);\n if (Number.isFinite(parsed)) return Math.floor(parsed / 1000);\n }\n return undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * Commerce pipeline orchestrator.\n *\n * Ties together extractors + verifiers + identity binding + constraint\n * evaluation + trust signals into a single CommerceContext result.\n *\n * This is AstraSync whitespace: the orchestration over the library-backed\n * primitives. The backend verify-access service is the sole per-request\n * caller — the edge adapters forward raw artifacts to verify-access and\n * never call this module directly. The admin transport playground also\n * calls it ad-hoc.\n *\n * Policy:\n * - Hard-deny (ok=false) on bad signatures, expired mandates, constraint\n * failures, identity cannot be bound.\n * - Trust signal (ok remains policy-driven) on ACP algorithm unsupported,\n * Stripe webhook HMAC fail, payment-token type unknown, cross-layer\n * identity mismatch.\n */\n\nimport type { ACPRequestContext } from './acp';\nimport { verifyACPSignature, type ACPVerifyResult } from './acp-verify';\nimport type { AP2MandateTriple } from './ap2';\nimport { verifyAP2Chain, type AP2ChainResult } from './ap2-verify';\nimport {\n evaluateVIConstraints,\n evaluatePaymentMethodAllowlist,\n evaluateSpendingLimit,\n type ConstraintEvalResult,\n type TransactionContext,\n} from './constraint-eval';\nimport { bindIdentity, type IdentityClaim, type IdentityResolver } from './identity-binding';\nimport { verifyMPP, type MPPVerifyResult } from './mpp-verify';\nimport type { MPPRequestContext } from './mpp';\nimport {\n mapACPRequestToPurpose,\n mapMPPRequestToPurpose,\n mapRFC9421TagToPurpose,\n mapUCPRequestToPurpose,\n mapVIMandateToPurpose,\n mapX402RequestToPurpose,\n type CommercePurpose,\n} from './purpose-mapping';\nimport {\n verifyRFC9421,\n type RFC9421VerifyResult,\n type RFC9421VerifyRequest,\n} from './rfc9421-verify';\nimport { verifyStripeWebhook, type VerifyStripeWebhookResult } from './stripe-webhook';\nimport {\n extractACPTransactionValue,\n extractMPPTransactionValue,\n extractUCPTransactionValue,\n extractVITransactionValue,\n extractX402TransactionValue,\n type TransactionValueContext,\n} from './transaction-value';\nimport type { UCPCheckoutContext } from './ucp';\nimport { verifyVIChain, type VIVerifyInput, type VIVerifyResult } from './vi-verify';\nimport type { VIExtractedClaims } from './vi';\nimport type { X402RequestContext } from './x402';\n\nexport type CommerceProtocol = 'vi' | 'ap2' | 'ucp' | 'acp' | 'agentpay' | 'tap' | 'mpp' | 'x402';\n\nexport interface CommercePipelineInput {\n protocol: CommerceProtocol;\n vi?: { claims: VIExtractedClaims; verifyInput?: VIVerifyInput };\n ap2?: { triple: AP2MandateTriple };\n ucp?: UCPCheckoutContext;\n acp?: {\n context: ACPRequestContext;\n verifyInput?: Parameters<typeof verifyACPSignature>[0];\n };\n rfc9421?: {\n request: RFC9421VerifyRequest;\n tag?: 'browse' | 'purchase' | string;\n verifyOptions: Parameters<typeof verifyRFC9421>[1];\n };\n mpp?: { context: MPPRequestContext; rawBody?: string };\n x402?: X402RequestContext;\n stripeWebhook?: { payload: string; signatureHeader: string; secret: string };\n transaction?: TransactionContext;\n registeredConstraints?: {\n allowedPaymentMethods?: string[];\n spendingLimit?: { amount?: number; currency?: string };\n };\n identityResolver?: IdentityResolver;\n clockSkewSec?: number;\n now?: () => number;\n}\n\nexport interface CommerceSignatureStack {\n vi?: VIVerifyResult;\n ap2?: AP2ChainResult;\n acp?: ACPVerifyResult;\n rfc9421?: RFC9421VerifyResult;\n mpp?: MPPVerifyResult;\n stripeWebhook?: VerifyStripeWebhookResult;\n}\n\nexport interface CommerceContext {\n protocol: CommerceProtocol;\n purpose: CommercePurpose | null;\n transactionValue?: TransactionValueContext;\n signatures: CommerceSignatureStack;\n identity?: {\n claims: IdentityClaim[];\n mappedAstraSyncAgentId?: string;\n mismatchAcrossLayers: boolean;\n };\n paymentToken?: {\n present: boolean;\n type: 'stripe-spt' | 'acp-vt' | 'tempo-tx' | 'other' | null;\n };\n mppMethodsOffered?: string[];\n constraints?: ConstraintEvalResult;\n receipt?: {\n method?: string;\n reference?: string;\n status?: string;\n timestamp?: string;\n };\n trustSignals: string[];\n timings: { extractMs: number; verifyMs: number; evalMs: number };\n /** False when any hard-deny rule fires. */\n ok: boolean;\n}\n\nexport async function runCommercePipeline(input: CommercePipelineInput): Promise<CommerceContext> {\n const trustSignals: string[] = [];\n const signatures: CommerceSignatureStack = {};\n const timings = { extractMs: 0, verifyMs: 0, evalMs: 0 };\n\n const extractStart = performance.now();\n const purpose = resolvePurpose(input);\n const transactionValue = resolveTransactionValue(input);\n const identityClaims = collectIdentityClaims(input);\n const paymentToken = resolvePaymentToken(input);\n timings.extractMs = Math.round(performance.now() - extractStart);\n\n const verifyStart = performance.now();\n let hardDeny = false;\n\n if (input.vi?.verifyInput) {\n signatures.vi = await verifyVIChain(input.vi.verifyInput);\n if (!signatures.vi.ok) hardDeny = true;\n }\n\n if (input.ap2) {\n signatures.ap2 = verifyAP2Chain({\n triple: input.ap2.triple,\n clockSkewSec: input.clockSkewSec,\n now: input.now,\n });\n if (!signatures.ap2.ok) hardDeny = true;\n }\n\n if (input.acp?.verifyInput) {\n signatures.acp = await verifyACPSignature(input.acp.verifyInput);\n if (!signatures.acp.ok && signatures.acp.timestampStale) hardDeny = true;\n if (signatures.acp.algorithm === 'unsupported') {\n trustSignals.push('acp-signature-algorithm-unsupported');\n } else if (!signatures.acp.ok) {\n hardDeny = true;\n }\n }\n\n if (input.rfc9421) {\n signatures.rfc9421 = await verifyRFC9421(input.rfc9421.request, input.rfc9421.verifyOptions);\n if (!signatures.rfc9421.ok) hardDeny = true;\n }\n\n if (input.mpp) {\n signatures.mpp = verifyMPP({\n context: input.mpp.context,\n rawBody: input.mpp.rawBody,\n clockSkewSec: input.clockSkewSec,\n now: input.now,\n });\n if (!signatures.mpp.ok) hardDeny = true;\n if (input.mpp.context.credential?.source) {\n trustSignals.push(`mpp-source-${shortSource(input.mpp.context.credential.source)}`);\n }\n }\n\n if (input.stripeWebhook) {\n signatures.stripeWebhook = verifyStripeWebhook(\n input.stripeWebhook.payload,\n input.stripeWebhook.signatureHeader,\n input.stripeWebhook.secret,\n { now: input.now ? () => input.now!() : undefined }\n );\n if (!signatures.stripeWebhook.ok) {\n trustSignals.push('stripe-webhook-hmac-failed');\n }\n }\n timings.verifyMs = Math.round(performance.now() - verifyStart);\n\n let identity: CommerceContext['identity'];\n if (input.identityResolver && identityClaims.length > 0) {\n const bound = await bindIdentity(identityClaims, input.identityResolver);\n identity = {\n claims: identityClaims,\n mappedAstraSyncAgentId: bound.mappedAstraSyncAgentId,\n mismatchAcrossLayers: bound.mismatchAcrossLayers,\n };\n if (bound.mismatchAcrossLayers) trustSignals.push('identity-mismatch-across-layers');\n } else if (identityClaims.length > 0) {\n identity = {\n claims: identityClaims,\n mappedAstraSyncAgentId: undefined,\n mismatchAcrossLayers: false,\n };\n }\n\n const evalStart = performance.now();\n const constraints = runConstraintEval(input);\n if (constraints && !constraints.ok) hardDeny = true;\n timings.evalMs = Math.round(performance.now() - evalStart);\n\n if (paymentToken?.type === 'stripe-spt') trustSignals.push('stripe-spt-present');\n if (paymentToken?.type === 'acp-vt') trustSignals.push('acp-vault-token-present');\n if (paymentToken?.type === 'tempo-tx') trustSignals.push('tempo-transaction-present');\n\n const mppReceipt = input.mpp?.context.receipt;\n\n return {\n protocol: input.protocol,\n purpose,\n transactionValue,\n signatures,\n identity,\n paymentToken,\n mppMethodsOffered: input.mpp?.context.offeredMethods,\n constraints,\n receipt: mppReceipt\n ? {\n method: mppReceipt.method,\n reference: mppReceipt.reference,\n status: mppReceipt.status,\n timestamp: mppReceipt.timestamp,\n }\n : undefined,\n trustSignals,\n timings,\n ok: !hardDeny,\n };\n}\n\nfunction resolvePurpose(input: CommercePipelineInput): CommercePurpose | null {\n if (input.vi?.claims.mandateType) {\n return mapVIMandateToPurpose(input.vi.claims.mandateType);\n }\n if (input.ap2?.triple.payment) return 'commerce.payment.execute';\n if (input.ap2?.triple.cart) return 'commerce.checkout.confirm';\n if (input.ap2?.triple.intent) return 'commerce.delegation.intent';\n if (input.ucp?.endpoint) {\n const [method, path] = input.ucp.endpoint.split(' ');\n return mapUCPRequestToPurpose(method ?? 'POST', path ?? '/');\n }\n if (input.acp?.context.endpoint) {\n // Extractor classifies as 'checkout_sessions.create|update|complete|cancel'\n // or 'delegate_payment'. Route each to the correct purpose.\n switch (input.acp.context.endpoint) {\n case 'checkout_sessions.create':\n return 'commerce.checkout.create';\n case 'checkout_sessions.update':\n return 'commerce.checkout.update';\n case 'checkout_sessions.complete':\n return 'commerce.payment.execute';\n case 'checkout_sessions.cancel':\n return 'commerce.checkout.cancel';\n case 'delegate_payment':\n return 'commerce.delegation.payment';\n default:\n return mapACPRequestToPurpose('POST', '/checkout_sessions');\n }\n }\n if (input.rfc9421?.tag) {\n return mapRFC9421TagToPurpose(\n input.rfc9421.tag === 'browse' || input.rfc9421.tag === 'purchase'\n ? (input.rfc9421.tag as 'browse' | 'purchase')\n : undefined\n );\n }\n if (input.mpp?.context.credential?.challenge || input.mpp?.context.challenges?.[0]) {\n const challenge = input.mpp.context.credential?.challenge ?? input.mpp.context.challenges?.[0];\n const amount = parseFloat(String(challenge?.request?.amount ?? 'NaN'));\n return mapMPPRequestToPurpose(\n challenge?.intent === 'session' ? 'session' : 'charge',\n Number.isFinite(amount) ? amount : undefined\n );\n }\n if (input.x402?.paymentRequired) {\n const amt = input.x402.paymentRequired.accepts[0]?.amount;\n return mapX402RequestToPurpose(Number(amt));\n }\n if (input.x402?.paymentPayload) return 'commerce.payment.execute';\n return null;\n}\n\nfunction resolveTransactionValue(\n input: CommercePipelineInput\n): TransactionValueContext | undefined {\n if (input.vi?.claims) {\n const v = extractVITransactionValue({\n constraints: input.vi.claims.constraints,\n l3aPaymentAmount: (input.vi.claims.constraints.paymentAmount &&\n typeof input.vi.claims.constraints.paymentAmount.max === 'number'\n ? {\n amount: input.vi.claims.constraints.paymentAmount.max,\n currency: input.vi.claims.constraints.paymentAmount.currency,\n }\n : undefined) as { amount?: number; currency?: string } | undefined,\n });\n if (v) return v;\n }\n if (input.ucp?.totals) {\n const v = extractUCPTransactionValue({ totals: input.ucp.totals });\n if (v) return v;\n }\n if (input.acp?.context.totals) {\n const v = extractACPTransactionValue({ totals: input.acp.context.totals });\n if (v) return v;\n }\n if (input.mpp?.context.credential?.challenge) {\n const ch = input.mpp.context.credential.challenge;\n const v = extractMPPTransactionValue({ method: ch.method, request: ch.request });\n if (v) return v;\n }\n if (input.x402?.paymentRequired) {\n const first = input.x402.paymentRequired.accepts[0];\n if (first) {\n const v = extractX402TransactionValue({\n maxAmountRequired: Number(first.amount),\n asset: first.asset,\n });\n if (v) return v;\n }\n }\n return undefined;\n}\n\nfunction collectIdentityClaims(input: CommercePipelineInput): IdentityClaim[] {\n const claims: IdentityClaim[] = [];\n if (input.vi?.claims.kid)\n claims.push({ protocol: 'vi', field: 'kid', value: input.vi.claims.kid });\n if (input.ap2?.triple) {\n const agentId =\n input.ap2.triple.intent?.agent_id ??\n input.ap2.triple.cart?.agent_id ??\n input.ap2.triple.payment?.agent_id;\n if (agentId) claims.push({ protocol: 'ap2', field: 'agent_id', value: agentId });\n }\n if (input.acp?.context.bearer) {\n claims.push({ protocol: 'acp', field: 'bearer', value: input.acp.context.bearer });\n }\n if (input.mpp?.context.credential?.source) {\n claims.push({ protocol: 'mpp', field: 'source', value: input.mpp.context.credential.source });\n }\n if (input.rfc9421) {\n // For RFC 9421 the kid is recorded after verify (result.kid); not collected here.\n }\n return claims;\n}\n\nfunction resolvePaymentToken(input: CommercePipelineInput): CommerceContext['paymentToken'] {\n if (input.acp?.context.paymentToken?.type) {\n return { present: true, type: input.acp.context.paymentToken.type };\n }\n const mppMethod = input.mpp?.context.credential?.challenge?.method;\n if (mppMethod === 'tempo') return { present: true, type: 'tempo-tx' };\n if (mppMethod === 'stripe') return { present: true, type: 'stripe-spt' };\n return undefined;\n}\n\nfunction runConstraintEval(input: CommercePipelineInput): ConstraintEvalResult | undefined {\n const transaction = input.transaction ?? {};\n const results: ConstraintEvalResult['results'] = {};\n const reasons: string[] = [];\n let hasAny = false;\n\n if (input.vi?.claims) {\n const viResult = evaluateVIConstraints({\n constraints: input.vi.claims.constraints,\n transaction,\n });\n for (const [k, v] of Object.entries(viResult.results)) {\n results[k] = v;\n if (!v.ok && v.reason) reasons.push(v.reason);\n }\n if (Object.keys(viResult.results).length > 0) hasAny = true;\n }\n\n const registered = input.registeredConstraints;\n if (registered?.allowedPaymentMethods) {\n const pm = evaluatePaymentMethodAllowlist({\n allowedMethods: registered.allowedPaymentMethods,\n requestedMethod: transaction.paymentMethod,\n });\n results.paymentMethod = pm;\n if (!pm.ok && pm.reason) reasons.push(pm.reason);\n hasAny = true;\n }\n if (registered?.spendingLimit) {\n const sp = evaluateSpendingLimit({\n limit: registered.spendingLimit,\n requested: { amount: transaction.amount, currency: transaction.currency },\n });\n results.spendingLimit = sp;\n if (!sp.ok && sp.reason) reasons.push(sp.reason);\n hasAny = true;\n }\n\n if (!hasAny) return undefined;\n return { ok: reasons.length === 0, results, reasons };\n}\n\nfunction shortSource(source: string): string {\n // Take first 16 chars sans scheme for trust-signal label readability.\n return source.replace(/^did:[a-z0-9]+:/, '').slice(0, 16);\n}\n","/**\n * Pluggable extractor registry for the Trusted Agent Gateway edge\n * adapters and other callers that need a curated extractor set.\n *\n * Built-in extractors (VI, UCP, ACP, RFC 9421, MPP, x402, Stripe webhook)\n * are NOT auto-registered. A caller imports this module, picks the set\n * it wants, and calls registerTransportExtractor() for each.\n *\n * Re-registering by name replaces the prior extractor (idempotent).\n */\n\nexport interface ExtractorRequestLike {\n method?: string;\n url?: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\nexport interface TransportExtractor<T = unknown> {\n readonly name: string;\n match(request: ExtractorRequestLike): boolean;\n extract(request: ExtractorRequestLike): T | Promise<T> | null;\n}\n\nconst registry = new Map<string, TransportExtractor>();\n\nexport function registerTransportExtractor<T>(extractor: TransportExtractor<T>): void {\n if (!extractor || typeof extractor.name !== 'string' || extractor.name.length === 0) {\n throw new Error('registerTransportExtractor: extractor must have a non-empty name');\n }\n registry.set(extractor.name, extractor as TransportExtractor);\n}\n\nexport function getTransportExtractors(): ReadonlyArray<TransportExtractor> {\n return Array.from(registry.values());\n}\n\nexport function getTransportExtractor(name: string): TransportExtractor | undefined {\n return registry.get(name);\n}\n\nexport function clearTransportExtractors(): void {\n registry.clear();\n}\n\n/**\n * Helper: run all matching extractors against a request and return their\n * extracted contexts keyed by extractor name. Skips extractors whose\n * `match()` returns false.\n */\nexport async function runMatchingExtractors(\n request: ExtractorRequestLike\n): Promise<Record<string, unknown>> {\n const out: Record<string, unknown> = {};\n for (const extractor of registry.values()) {\n if (!extractor.match(request)) continue;\n const result = await extractor.extract(request);\n if (result !== null && result !== undefined) out[extractor.name] = result;\n }\n return out;\n}\n","/**\n * Visa JWKS registry resolver.\n *\n * Default endpoint: https://mcp.visa.com/.well-known/jwks (per Visa TAP spec).\n * Wraps jose.createRemoteJWKSet which handles caching + rotation natively.\n */\n\nimport { createRemoteJWKSet, type JWK } from 'jose';\nimport type { RegistryResolver, ResolveContext } from './types';\n\nconst DEFAULT_VISA_JWKS_URL = 'https://mcp.visa.com/.well-known/jwks';\n\nexport interface VisaRegistryOptions {\n jwksUrl?: string;\n cacheMaxAge?: number;\n cooldownDuration?: number;\n}\n\nexport function createVisaRegistry(options: VisaRegistryOptions = {}): RegistryResolver {\n const url = new URL(options.jwksUrl ?? DEFAULT_VISA_JWKS_URL);\n const jwks = createRemoteJWKSet(url, {\n cacheMaxAge: options.cacheMaxAge,\n cooldownDuration: options.cooldownDuration,\n });\n\n return {\n name: 'visa',\n async resolve(kid: string, context?: ResolveContext): Promise<JWK | null> {\n if (!kid) return null;\n try {\n const key = await jwks({\n kid,\n alg: context?.algorithm ?? 'ES256',\n typ: 'JWT',\n });\n return exportJwkFromKeyLike(key);\n } catch {\n return null;\n }\n },\n };\n}\n\nasync function exportJwkFromKeyLike(keyLike: unknown): Promise<JWK | null> {\n if (!keyLike) return null;\n // jose returns KeyObject or CryptoKey — both export via exportJWK at caller side.\n // Runtime shape check: if it already looks like a JWK, pass through.\n if (typeof keyLike === 'object' && 'kty' in (keyLike as object)) {\n return keyLike as JWK;\n }\n const { exportJWK } = await import('jose');\n try {\n return await exportJWK(keyLike as Parameters<typeof exportJWK>[0]);\n } catch {\n return null;\n }\n}\n","/**\n * Mastercard Agent Registry resolver — STUB.\n *\n * Mastercard Agent Pay is behind partnership (pilots Feb 2026, GA Q2 2026).\n * No public Agent Registry URL or open-source resolver exists as of April\n * 2026. This resolver accepts an optional `registryUrl` and, when absent,\n * returns null with a single one-time console.warn so callers can plumb\n * the flow end-to-end without a live registry.\n *\n * When Mastercard ships a public resolver or when a commercial relationship\n * provides a registry URL, pass it via `MastercardRegistryOptions.registryUrl`.\n * Response shape expected: { keys: JWK[] } (JWKS-style).\n */\n\nimport type { JWK } from 'jose';\nimport type { RegistryResolver } from './types';\n\nexport interface MastercardRegistryOptions {\n /** Partnership-provided registry URL. Without it, the resolver is inert. */\n registryUrl?: string;\n /** Cache TTL in seconds. Default 3600. */\n cacheTtlSec?: number;\n /** Fetch fn override for testing. */\n fetch?: typeof fetch;\n /** Silence the one-time warn (testing only). */\n silent?: boolean;\n}\n\ninterface CachedKey {\n jwk: JWK;\n expiresAt: number;\n}\n\nexport function createMastercardRegistry(\n options: MastercardRegistryOptions = {}\n): RegistryResolver {\n const cache = new Map<string, CachedKey>();\n const ttlSec = options.cacheTtlSec ?? 3600;\n const fetchFn = options.fetch ?? globalThis.fetch;\n let warned = false;\n\n return {\n name: 'mastercard',\n async resolve(kid: string): Promise<JWK | null> {\n if (!kid) return null;\n\n if (!options.registryUrl) {\n if (!warned && !options.silent) {\n warned = true;\n // eslint-disable-next-line no-console\n console.warn(\n '[mastercard-registry] registryUrl not configured — key resolution disabled. ' +\n 'Kid lookups will return null until a partnership registry is supplied.'\n );\n }\n return null;\n }\n\n const cached = cache.get(kid);\n if (cached && cached.expiresAt > Date.now()) return cached.jwk;\n\n try {\n const res = await fetchFn(options.registryUrl);\n if (!res.ok) return null;\n const body = (await res.json()) as { keys?: JWK[] };\n const keys = body.keys ?? [];\n for (const k of keys) {\n if (k.kid === kid) {\n cache.set(kid, { jwk: k, expiresAt: Date.now() + ttlSec * 1000 });\n return k;\n }\n }\n return null;\n } catch {\n return null;\n }\n },\n };\n}\n","/**\n * Web Bot Auth registry resolver.\n *\n * IETF draft-meunier-web-bot-auth-architecture-05 + draft-meunier-http-\n * message-signatures-directory-01. Shared transport substrate under TAP,\n * Agent Pay, and Cloudflare Pay Per Crawl.\n *\n * Fetches a Web Bot Auth signature directory\n * (default: `<origin>/.well-known/http-message-signatures-directory`).\n * Shape per spec is a JWKS with Ed25519 keys.\n *\n * Wraps Cloudflare's `web-bot-auth` npm package where feasible; for raw\n * directory fetch + kid matching we use fetch + JSON since web-bot-auth's\n * higher-level API assumes a full request to verify.\n */\n\nimport type { JWK } from 'jose';\nimport type { RegistryResolver, ResolveContext } from './types';\n\nconst DIRECTORY_PATH = '/.well-known/http-message-signatures-directory';\n\nexport interface WebBotAuthRegistryOptions {\n /**\n * Optional explicit directory URL. When omitted, the resolver derives one\n * from `ResolveContext.origin` (e.g. the request URL's origin at verify time).\n */\n directoryUrl?: string;\n cacheTtlSec?: number;\n fetch?: typeof fetch;\n}\n\ninterface DirectoryCache {\n keys: JWK[];\n expiresAt: number;\n}\n\nexport function createWebBotAuthRegistry(\n options: WebBotAuthRegistryOptions = {}\n): RegistryResolver {\n const cache = new Map<string, DirectoryCache>();\n const ttlSec = options.cacheTtlSec ?? 3600;\n const fetchFn = options.fetch ?? globalThis.fetch;\n\n return {\n name: 'web-bot-auth',\n async resolve(kid: string, context?: ResolveContext): Promise<JWK | null> {\n if (!kid) return null;\n\n const directoryUrl = resolveDirectoryUrl(options.directoryUrl, context?.origin);\n if (!directoryUrl) return null;\n\n const cached = cache.get(directoryUrl);\n const now = Date.now();\n if (cached && cached.expiresAt > now) {\n return findKeyByKid(cached.keys, kid);\n }\n\n try {\n const res = await fetchFn(directoryUrl);\n if (!res.ok) return null;\n const body = (await res.json()) as { keys?: JWK[] };\n const keys = body.keys ?? [];\n cache.set(directoryUrl, { keys, expiresAt: now + ttlSec * 1000 });\n return findKeyByKid(keys, kid);\n } catch {\n return null;\n }\n },\n };\n}\n\nfunction resolveDirectoryUrl(\n explicit: string | undefined,\n origin: string | undefined\n): string | null {\n if (explicit) return explicit;\n if (!origin) return null;\n try {\n const url = new URL(origin);\n return `${url.origin}${DIRECTORY_PATH}`;\n } catch {\n return null;\n }\n}\n\nfunction findKeyByKid(keys: JWK[], kid: string): JWK | null {\n for (const k of keys) {\n if (k.kid === kid) return k;\n }\n return null;\n}\n","/**\n * MCP server-side helpers — companion to `transport/mcp.ts` (which handles the\n * agent-side `_meta.astrasync` block).\n *\n * Surfaces a body-aware policy hook the existing `createMiddleware` couldn't\n * provide — MCP traffic is JSON-RPC over a single endpoint (`/mcp`), so the\n * default route-pattern gating is too coarse: every request looks the same\n * URL-wise, but `initialize` is low-risk handshake while `tools/call` of a\n * payment tool is high-risk. Cohort-3 beta merchants flagged this 🟡 in the\n * v2.9.5 round.\n *\n * What lives here:\n * - `parseMcpJsonRpc(body)` — peels JSON-RPC method + tool name + agent\n * id without committing to a particular MCP\n * server framework.\n * - `mcpToPdlss(parsed)` — canonical mapping JSON-RPC method → PDLSS\n * purpose / action / resource. Doc-stable\n * so audits can correlate.\n * - `mcpDefaultEnforced(parsed)` — whether a method is enforced by default\n * so a single MCP middleware can split\n * `initialize` / `tools/list` (pass-through)\n * from `tools/call` (enforced).\n * - `MCP_VERIFIED_HOP_HEADER` — header convention for the dedupe pattern\n * when an MCP tool calls an inner REST hop.\n * - `serialize/parseVerifiedHop` helpers.\n *\n * The Express MCP adapter is in `adapters/mcp.ts` and consumes these.\n */\n\n// X-Astra-Verified-Hop helpers live in ../verified-hop (shared with the\n// edge gateway's origin-bound emission); re-exported here so existing\n// transport-level imports keep working unchanged.\nexport {\n MCP_VERIFIED_HOP_HEADER,\n MCP_VERIFIED_HOP_MAX_AGE_MS,\n serializeVerifiedHop,\n parseVerifiedHop,\n isVerifiedHopValidFor,\n} from '../verified-hop';\nexport type { VerifiedHopMarker } from '../verified-hop';\n\n/**\n * Output of `parseMcpJsonRpc`. Self-describing so the middleware doesn't have\n * to re-introspect the body to figure out gating.\n */\nexport interface ParsedMcpRequest {\n /** JSON-RPC method (e.g. `tools/call`, `initialize`, `tools/list`). */\n method: string;\n /** Set when method === 'tools/call'; the tool name from `params.name`. */\n toolName?: string;\n /** Initialize-specific protocolVersion handshake info, when present. */\n protocolVersion?: string;\n /**\n * Agent id read from the body, in priority order:\n * 1. `params._meta.astrasync.agentId` (the canonical SDK location, see\n * `transport/mcp.ts → setMcpMeta`)\n * 2. `params.arguments.agent_id` (legacy / hand-written tool callers)\n * Header-supplied id (X-Astra-Id) is read separately by the adapter and\n * compared to this for the mismatch check.\n */\n agentIdFromBody?: string;\n /**\n * Purpose extracted from the MCP body\n * with the symmetric precedence chain. Sourced from `_meta.astrasync.purpose`\n * (canonical SDK location) OR `params.arguments.purpose` (legacy /\n * conventional callers). The discriminator is on `purposeSourceFromBody`.\n * Adapter combines this with the `X-Astra-Purpose` header (header wins)\n * before mapping; final fallback at `mcpToPdlss` is `undefined`.\n */\n purposeFromBody?: string;\n /** Which body location resolved `purposeFromBody`. */\n purposeSourceFromBody?: 'meta' | 'tool_argument';\n /**\n * Action extracted from the MCP body with the same\n * symmetric chain as purpose. Sourced from `_meta.astrasync.action`\n * (canonical) OR `params.arguments.action` (legacy). Adapter combines\n * with the `X-Astra-Action` header (header wins) before mapping; final\n * fallback at `mcpToPdlss` is the transport-layer default\n * (`tools/call:<toolname>` or just `<method>`).\n */\n actionFromBody?: string;\n /** Which body location resolved `actionFromBody`. */\n actionSourceFromBody?: 'meta' | 'tool_argument';\n /** True for handshake methods that must succeed before any tool call. */\n isInitialize: boolean;\n /** True for `tools/call`. */\n isToolCall: boolean;\n /** True for low-risk introspection (`tools/list`, `prompts/list`, etc.). */\n isIntrospection: boolean;\n}\n\n/**\n * Peel the JSON-RPC envelope. Returns `null` if the body isn't a JSON-RPC\n * request (callers can short-circuit with a 400 or treat as untyped traffic).\n *\n * Accepts both single-request and notification shapes. Batch requests are\n * NOT supported here — the verify-access contract is single-agent-per-call;\n * a batch body should be split before policy gating.\n */\nexport function parseMcpJsonRpc(body: unknown): ParsedMcpRequest | null {\n if (!body || typeof body !== 'object' || Array.isArray(body)) return null;\n const obj = body as Record<string, unknown>;\n if (obj.jsonrpc !== '2.0' && obj.jsonrpc !== '1.0') return null;\n const method = typeof obj.method === 'string' ? obj.method : null;\n if (!method) return null;\n const params = obj.params as Record<string, unknown> | undefined;\n\n // Tool-name lookup. MCP `tools/call` puts the tool under `params.name`.\n let toolName: string | undefined;\n if (method === 'tools/call' && params && typeof params.name === 'string') {\n toolName = params.name;\n }\n\n // protocolVersion only on the initialize request.\n let protocolVersion: string | undefined;\n if (method === 'initialize' && params && typeof params.protocolVersion === 'string') {\n protocolVersion = params.protocolVersion;\n }\n\n const meta = params?._meta as Record<string, unknown> | undefined;\n const astrasyncMeta = meta?.astrasync as Record<string, unknown> | undefined;\n const args = params?.arguments as Record<string, unknown> | undefined;\n\n // Agent-id lookup with documented precedence: _meta.astrasync.agentId\n // wins over params.arguments.agent_id. (The argument-shape uses\n // `agent_id` snake_case for legacy conventional callers; meta is the\n // canonical SDK location.)\n let agentIdFromBody: string | undefined;\n if (astrasyncMeta && typeof astrasyncMeta.agentId === 'string') {\n agentIdFromBody = astrasyncMeta.agentId;\n } else if (args && typeof args.agent_id === 'string') {\n agentIdFromBody = args.agent_id;\n }\n\n // Round-13 (R13-1, R13-2) — symmetric body-extraction for purpose +\n // action. Per `feedback_symmetric_fallbacks_for_symmetric_concepts.md`:\n // these two concepts are paired in the MCP middleware, so their\n // fallback chains MUST mirror each other exactly. Drift between them\n // generates the same support-ticket class repeatedly (\"I set X in\n // arguments and it didn't take\" — happened for purpose in round-12\n // post-F19, and was about to happen for action in round-13).\n //\n // Body precedence (applies to both): _meta.astrasync.<key> wins over\n // params.arguments.<key>. The discriminator is exported alongside the\n // value so the adapter can fold it into purposeSource / actionSource\n // for debug logging and adoption tracking.\n const purposeBodyResult = extractFromMcpBody(astrasyncMeta, args, 'purpose');\n const actionBodyResult = extractFromMcpBody(astrasyncMeta, args, 'action');\n\n const isInitialize = method === 'initialize';\n const isToolCall = method === 'tools/call';\n const isIntrospection =\n method === 'tools/list' ||\n method === 'prompts/list' ||\n method === 'resources/list' ||\n method === 'ping' ||\n method === 'notifications/initialized';\n\n return {\n method,\n ...(toolName ? { toolName } : {}),\n ...(protocolVersion ? { protocolVersion } : {}),\n ...(agentIdFromBody ? { agentIdFromBody } : {}),\n ...(purposeBodyResult.value ? { purposeFromBody: purposeBodyResult.value } : {}),\n ...(purposeBodyResult.source ? { purposeSourceFromBody: purposeBodyResult.source } : {}),\n ...(actionBodyResult.value ? { actionFromBody: actionBodyResult.value } : {}),\n ...(actionBodyResult.source ? { actionSourceFromBody: actionBodyResult.source } : {}),\n isInitialize,\n isToolCall,\n isIntrospection,\n };\n}\n\n/**\n * Shared body-extraction helper for the symmetric purpose + action\n * fallback chain. Returns the resolved value AND\n * the source discriminator so adapters can fold it into per-call debug\n * logs (`purpose_source` / `action_source`).\n *\n * Precedence:\n * 1. `params._meta.astrasync.<key>` — canonical SDK location, source: 'meta'\n * 2. `params.arguments.<key>` — legacy / conventional, source: 'tool_argument'\n * 3. neither present — value: undefined, source: undefined\n *\n * The HTTP-header tier (`X-Astra-<concept>`) is the adapter's job; this\n * helper only handles body sources. Adapters combine the two: header\n * wins over body. See `mcpToPdlss` for the final precedence assembly.\n */\nfunction extractFromMcpBody(\n astrasyncMeta: Record<string, unknown> | undefined,\n args: Record<string, unknown> | undefined,\n key: 'purpose' | 'action'\n): { value: string | undefined; source: 'meta' | 'tool_argument' | undefined } {\n if (astrasyncMeta && typeof astrasyncMeta[key] === 'string') {\n return { value: astrasyncMeta[key] as string, source: 'meta' };\n }\n if (args && typeof args[key] === 'string') {\n return { value: args[key] as string, source: 'tool_argument' };\n }\n return { value: undefined, source: undefined };\n}\n\n/**\n * PDLSS mapping for an MCP request. The platform's PDLSS taxonomy is\n * `purpose / action / resource`; for MCP traffic the audit-useful dimensions\n * are the JSON-RPC method and (for `tools/call`) the tool name.\n *\n * v2.5.0 rules:\n * - `resource` defaults to the HTTP request path (e.g. `/mcp`). Per-tool\n * overrides via `toolGates` config let merchants map tools to specific\n * backend resources (e.g. `/api/catalog`).\n * - `purpose` defaults to `undefined` (backend evaluator applies\n * skip-when-undefined). Per-tool overrides via `toolGates` config let\n * merchants declare the semantic purpose each tool fulfils.\n * - `action` comes only from declarations (toolGate config, header, or\n * body). For `tools/call` with none declared it is `undefined` —\n * evaluation is purpose-only, because a raw tool name is a transport\n * token, not a PDLSS action, and sending it as one guarantees an\n * action-policy mismatch. For other JSON-RPC methods the method string\n * is used.\n */\nexport interface McpPdlssMapping {\n purpose: string | undefined;\n /**\n * `undefined` when a `tools/call` request declared no action anywhere —\n * the verify-access call then evaluates purpose-only. Tool names never\n * travel as PDLSS actions.\n */\n action: string | undefined;\n resource: string;\n purposeSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | undefined;\n actionSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | 'transport_layer' | undefined;\n}\n\n/**\n * v2.5.0 — PDLSS field derivation for MCP requests.\n *\n * Purpose precedence:\n * - If `toolGate.purpose` is provided, it is authoritative (header/body ignored).\n * - Otherwise: header → body `_meta` → body `arguments` → `undefined`.\n *\n * Resource precedence:\n * - `toolGate.resource` if provided, else `requestPath`.\n *\n * Action precedence (3.1.0 — toolGate override added for\n * symmetry with purpose; 4.1.0 — the bare-tool-name fallback for\n * `tools/call` was removed):\n * - `toolGate.action` authoritative → header → body `_meta` → body\n * `arguments` → then: `undefined` for `tools/call` (purpose-only\n * evaluation — tool names are transport tokens, never PDLSS actions),\n * or the JSON-RPC method string for other methods (transport_layer).\n *\n * @param requestPath The HTTP request path (e.g. '/mcp'). Required.\n * @param toolGate Resolved per-tool config from `toolGates`, if present.\n */\nexport function mcpToPdlss(\n parsed: ParsedMcpRequest,\n requestPath: string,\n headerPurpose?: string,\n headerAction?: string,\n toolGate?: { purpose?: string; action?: string; resource?: string }\n): McpPdlssMapping {\n const resource = toolGate?.resource ?? requestPath;\n\n let purpose: string | undefined;\n let purposeSource: McpPdlssMapping['purposeSource'];\n if (toolGate?.purpose !== undefined) {\n purpose = toolGate.purpose;\n purposeSource = 'tool_gate';\n } else if (headerPurpose) {\n purpose = headerPurpose;\n purposeSource = 'header';\n } else if (parsed.purposeFromBody && parsed.purposeSourceFromBody) {\n purpose = parsed.purposeFromBody;\n purposeSource = parsed.purposeSourceFromBody;\n } else {\n purpose = undefined;\n purposeSource = undefined;\n }\n\n let action: string | undefined;\n let actionSource: McpPdlssMapping['actionSource'];\n if (toolGate?.action !== undefined) {\n action = toolGate.action;\n actionSource = 'tool_gate';\n } else if (headerAction) {\n action = headerAction;\n actionSource = 'header';\n } else if (parsed.actionFromBody && parsed.actionSourceFromBody) {\n action = parsed.actionFromBody;\n actionSource = parsed.actionSourceFromBody;\n } else if (parsed.method === 'tools/call') {\n // 4.1.0 fix: previously the bare tool name travelled as the PDLSS\n // action here, which guaranteed an action-policy deny for merchants\n // using the bare-string toolGate shorthand (tool names are transport\n // tokens, not policy vocabulary). With nothing configured or declared,\n // leave the action undeclared so evaluation is purpose-only.\n action = undefined;\n actionSource = undefined;\n } else {\n action = parsed.toolName ? `${parsed.method}:${parsed.toolName}` : parsed.method;\n actionSource = 'transport_layer';\n }\n\n return { purpose, action, resource, purposeSource, actionSource };\n}\n\n/**\n * Whether a method is enforced (calls verify-access + gates on the server\n * decision) by default. The MCP middleware uses this to split low-risk\n * handshake / introspection traffic (pass-through) from high-risk tool\n * execution (enforced). Per-tool / per-method overrides win over this default.\n *\n * - `initialize` / `notifications/initialized` → false (handshake must work for unregistered probes)\n * - `tools/list` / `prompts/list` / `resources/list` → false (introspection is public-surface)\n * - `ping` → false\n * - `resources/read` → true\n * - `tools/call` → true (default — overridable per-tool)\n * - everything else → true (least-privilege fallback)\n */\nexport function mcpDefaultEnforced(parsed: ParsedMcpRequest): boolean {\n if (parsed.isInitialize || parsed.method === 'notifications/initialized') return false;\n if (parsed.isIntrospection) return false;\n return true;\n}\n","/**\n * AstraSync Universal Verification Gateway — MCP middleware\n *\n * Express-shaped middleware tailored to the JSON-RPC body of an MCP\n * (Model Context Protocol) endpoint. Closes the cohort-3 gaps the default\n * `createMiddleware` couldn't:\n *\n * (a) **Body-aware gating**. All MCP traffic targets the same `/mcp` URL.\n * The default route-pattern matcher can't tell `initialize` (low risk)\n * from `tools/call start_checkout` (high risk). This middleware peels\n * the JSON-RPC body and applies a per-method risk tier.\n *\n * (b) **PDLSS mapping**. Derives purpose, action, and resource from\n * `toolGates` config and request context. See `transport/mcp-server.ts`\n * `mcpToPdlss()` for the exact mapping.\n *\n * (c) **Inner-hop dedupe**. Outbound responses set\n * `X-Astra-Verified-Hop` so a downstream REST endpoint that the tool\n * calls can skip a duplicate verify-access. The receiving REST\n * middleware checks `parseVerifiedHop` and skips when valid.\n *\n * (d) **Header-vs-body identity precedence**. Reads ASTRA-id from\n * `X-Astra-Id` first, body second. If both are present and disagree,\n * returns a structured 400 by default (configurable). Pre-fix,\n * integrators had to re-discover this on their own.\n *\n * Usage:\n *\n * ```typescript\n * import express from 'express';\n * import { createMcpMiddleware } from '@astrasyncai/verification-gateway/mcp';\n *\n * const app = express();\n * app.use(express.json());\n *\n * app.post(\n * '/mcp',\n * createMcpMiddleware({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * apiKey: process.env.ASTRASYNC_API_KEY,\n * // Per-tool gates — `tools/call` is enforced by default; introspection /\n * // handshake pass through. A gated tool needs a PDLSS purpose (and ideally\n * // an action). Set a tool/method to `'observe'` to pass it through\n * // unenforced (still evaluated when `evaluateAlwaysIfCredentialed`).\n * toolGates: {\n * browse_catalog: { purpose: 'shopping', action: 'shopping.search' },\n * start_checkout: { purpose: 'shopping', action: 'shopping.purchase' },\n * health_check: 'observe',\n * },\n * }),\n * yourMcpServerHandler,\n * );\n * ```\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport type {\n GatewayConfig,\n VerificationResult,\n EnhancedVerificationResult,\n VerificationRequest,\n} from '../types';\nimport { verify, extractCredentials, recordDecision } from '../verify';\nimport { buildSdkObservedMetadata } from '../metadata-capture';\nimport { requiresHumanApproval, annotateApprovalRequired } from './approval-gate';\nimport { awaitStepUpApproval } from './stepup-poll';\nimport { prefetchWellKnown, getWellKnownUrls } from '../well-known';\nimport {\n parseMcpJsonRpc,\n mcpToPdlss,\n mcpDefaultEnforced,\n serializeVerifiedHop,\n parseVerifiedHop,\n isVerifiedHopValidFor,\n MCP_VERIFIED_HOP_HEADER,\n type ParsedMcpRequest,\n} from '../transport/mcp-server';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n mcpRequest?: ParsedMcpRequest;\n // Declared here as well as in express.ts (identical type — the merged\n // interfaces are compatible) so this module typechecks standalone: the\n // grouped DTS build compiles each entry group as its own program, and\n // mcp.ts must not depend on express.ts being in the same one.\n agentVerification?: VerificationResult;\n }\n }\n}\n\n/**\n * Extended per-tool gate with optional PDLSS purpose + action + resource\n * overrides.\n *\n * When `purpose` is set, it is authoritative for that tool — the agent's\n * `X-Astra-Purpose` header is ignored. This lets the merchant declare what\n * semantic purpose each tool fulfils rather than trusting agent self-declaration.\n *\n * When `action` is set (symmetric with `purpose`), it is\n * authoritative over `X-Astra-Action` / body declarations, letting the\n * merchant pin a dotted-verb action (e.g. `shopping.search`) for a tool\n * whose callers would otherwise leave the action undeclared (purpose-only\n * evaluation — raw tool names never travel as PDLSS actions).\n *\n * When `resource` is set, it overrides the default (`req.path`) for that\n * tool's verify-access call — e.g. mapping `list_products` to `/api/catalog`.\n */\nexport interface ToolGateConfig {\n purpose?: string;\n action?: string;\n resource?: string;\n}\n\n/**\n * A tool/method gate is either a {@link ToolGateConfig} (enforced — calls\n * verify-access and gates on the server decision, using the declared PDLSS\n * purpose/action) or the literal `'observe'` (passed through unenforced;\n * still evaluated when `evaluateAlwaysIfCredentialed` is set). SDK 5.0.0\n * removed the access-level band, so a gate no longer carries a tier — its\n * only decision is enforce vs observe.\n */\nexport type ToolGate = ToolGateConfig | 'observe';\n\nexport interface McpMiddlewareOptions extends GatewayConfig {\n /**\n * Per-tool gating for `tools/call` invocations. Tools not listed are\n * enforced by default (`tools/call` calls verify-access and gates on the\n * server decision).\n *\n * A gated tool declares its PDLSS `purpose` (required: the backend rejects\n * gated calls with no resolvable purpose) and ideally a dotted-verb\n * `action`:\n * ```typescript\n * toolGates: {\n * list_products: { purpose: 'shopping',\n * action: 'shopping.search',\n * resource: '/api/catalog' },\n * start_checkout: { purpose: 'shopping',\n * action: 'shopping.purchase',\n * resource: '/api/checkout/*' },\n * health_check: 'observe', // pass through unenforced\n * }\n * ```\n *\n * Set a tool to `'observe'` to pass it through without enforcement (it is\n * still evaluated for the audit trail when `evaluateAlwaysIfCredentialed`\n * is set). A gated object form with no resolvable purpose fails fast with a\n * `PDLSS_PURPOSE_REQUIRED` 400 (the SDK never sends the raw tool name as\n * the PDLSS action).\n *\n * The action axis for non-tools/call MCP methods (`tools/list`,\n * `resources/list`, `prompts/list`, etc.) is the literal JSON-RPC method\n * name (e.g. `'tools/list'`). Merchants gating MCP traffic by action should\n * declare per-tool gates in `toolGates`, not endpoint-level `allowedActions`\n * — the latter applies to REST-style action values, not MCP method strings.\n */\n toolGates?: Record<string, ToolGate>;\n /**\n * Per-method override. By default introspection / handshake methods\n * (`tools/list`, `initialize`, `ping`, …) pass through and `tools/call` is\n * enforced; declare a method here to enforce it (object form, with a PDLSS\n * purpose) or set it to `'observe'` to pass it through. Matches by exact\n * JSON-RPC method string.\n */\n methodGates?: Record<string, ToolGate>;\n /**\n * What to do when the agent id supplied in the X-Astra-Id header\n * disagrees with the agent id in the JSON-RPC body\n * (`params._meta.astrasync.agentId` or `params.arguments.agent_id`).\n *\n * - `'reject'` (default) — return 400 `AGENT_ID_MISMATCH`. Safest.\n * - `'prefer-header'` — log + verify against the header value. Keeps\n * bodies that were authored before X-Astra-Id was the canonical\n * identity slot working.\n * - `'prefer-body'` — log + verify against the body value. Useful in\n * reverse-proxy setups that strip auth headers.\n */\n onAgentIdMismatch?: 'reject' | 'prefer-header' | 'prefer-body';\n /** Skip verification + dedupe entirely. For testing. */\n skip?: boolean;\n /** Custom denied handler. Defaults to a structured JSON-RPC error response. */\n onDenied?: (result: VerificationResult, req: Request, res: Response) => void;\n /**\n * If `true`, trust an inbound `X-Astra-Verified-Hop` header to skip\n * verify-access when it carries a recent marker for the resolved agent.\n *\n * **DEFAULT FLIPPED TO `false` in SDK 2.4.13.** The marker\n * is plaintext semicolon-delimited with no HMAC, so any client that sets\n * the header (with the right format + fresh timestamp + matching ASTRA-id)\n * skipped verify-access entirely. The per-process verify-access result\n * cache already dedupes legitimate repeat calls — this optimization\n * provided no additional savings, only a bypass surface.\n *\n * Set this to `true` ONLY if you control every upstream MCP hop that sets\n * the header AND you trust the network path between hops (mTLS, internal\n * VPC, etc.). For most installs, leave at the safe default.\n *\n * A future SDK release will either remove this option entirely OR add\n * HMAC signing to the marker.\n */\n trustVerifiedHop?: boolean;\n /** Window for accepting an upstream verified-hop marker. Default 60_000ms. */\n verifiedHopMaxAgeMs?: number;\n /**\n * Automatically record grant/deny decisions for every MCP call. Default\n * `true` — matches the express adapter.\n */\n recordDecisions?: boolean;\n /** Forward runtime challenge (default `true`). */\n enableRuntimeChallenge?: boolean;\n /**\n * Posture when the MCP middleware itself throws an internal error.\n * Default `'open'` for backward compatibility in SDK 2.4.13. Shadow logs\n * record what WOULD be denied with `failOnError: 'closed'` so merchants\n * can grep correlationId for impact analysis during the observation\n * window. Default flips to `'closed'` in a follow-up release.\n */\n failOnError?: 'open' | 'closed';\n}\n\n/**\n * Default MCP denied handler.\n *\n * Mirrors the express adapter — surfaces `failures[]`\n * and `correlationId` on the response so partners can render rich UX and\n * tie a denial to a log line. Also stamps `X-Astra-Gateway-Mode: enforced`\n * so the header reliably distinguishes gate-evaluated denials\n * from gate-skipped pass-throughs.\n */\n/**\n * Shared single-value HTTP header reader. Same shape used for\n * both `X-Astra-Purpose` and `X-Astra-Action` extraction (symmetric\n * fallback chain — see `mcpToPdlss` for the full precedence rule).\n * Returns the first value if the header repeats (Express turns repeated\n * headers into an array); returns undefined when the header is absent.\n */\nfunction readSingleHeader(value: string | string[] | undefined): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value[0];\n return undefined;\n}\n\nfunction dedupeFailures(result: VerificationResult): void {\n if (result.failures && result.failures.length > 1) {\n const seen = new Set<string>();\n result.failures = result.failures.filter((f) => {\n const key = `${f.dimension}|${f.message}|${(f as { guidance?: string }).guidance ?? ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n }\n if (result.denialReasons && result.denialReasons.length > 1) {\n result.denialReasons = [...new Set(result.denialReasons)];\n }\n}\n\nfunction defaultMcpDenied(result: VerificationResult, req: Request, res: Response): void {\n // JSON-RPC error envelope so MCP-aware clients render it correctly.\n const id = (req.body as Record<string, unknown> | undefined)?.id ?? null;\n\n // 4.0.0 BREAKING: the integration's OWN key was rejected — not the agent's\n // fault, not transient. 503 + a dedicated JSON-RPC code so MCP clients can\n // tell \"this server's verification layer is broken\" from their own denial.\n if (result.misconfigured) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.status(503).json({\n jsonrpc: '2.0',\n id,\n error: {\n // -32002 → merchant verification misconfigured (see -32000/-32001 below)\n code: -32002,\n message:\n result.denialReasons?.[0] ?? \"This server's AstraSync integration is misconfigured\",\n data: {\n guidance: result.guidance,\n failures: result.failures,\n correlationId: result.correlationId,\n },\n },\n });\n return;\n }\n\n // Round-18 G4: see express.defaultOnDenied for full rationale on the\n // identity-vs-policy split → 401/403 mapping. Same logic here so MCP\n // clients get HTTP status semantics aligned with REST adapters.\n const status = !result.identityVerified ? 401 : 403;\n\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n\n res.status(status).json({\n jsonrpc: '2.0',\n id,\n error: {\n // JSON-RPC error codes:\n // -32000 → unauthorized (no identity resolved)\n // -32001 → insufficient access (identity OK, policy denied)\n // -32002 → merchant verification misconfigured (handled above)\n code: !result.identityVerified ? -32000 : -32001,\n message: result.denialReasons?.[0] ?? 'Access denied',\n data: {\n guidance: result.guidance,\n // Round-10: aggregated per-dimension detail + correlation handle.\n failures: result.failures,\n correlationId: result.correlationId,\n stepUpApproval: result.stepUpApproval,\n // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /\n // expired / consumed / timeout). Absent when the feature is off.\n ...(result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }),\n },\n },\n });\n}\n\n/**\n * Resolve whether a parsed MCP request is enforced, and the gate config to\n * apply. SDK 5.0.0 removed the access-level band — a gate's only decision is\n * enforce vs observe.\n *\n * Precedence:\n * 1. Non-tools/call without `methodGates` entry → pass through\n * (`discovery_default`). Discovery is open — agents must list tools\n * before invoking them.\n * 2. `methodGates[method]` — per-method override (`'observe'` or a config)\n * 3. `toolGates[toolName]` — per-tool override (tools/call only)\n * 4. `mcpDefaultEnforced` — built-in default (tools/call → enforced)\n *\n * The `source` field is logged for forensics / activity-feed attribution.\n */\nfunction resolveGate(\n parsed: ParsedMcpRequest,\n opts: {\n toolGates?: Record<string, ToolGate>;\n methodGates?: Record<string, ToolGate>;\n }\n): {\n enforce: boolean;\n config?: ToolGateConfig;\n source: 'toolGate' | 'methodGate' | 'tier' | 'discovery_default';\n} {\n if (!parsed.toolName) {\n const methodGate = opts.methodGates?.[parsed.method];\n if (methodGate !== undefined) {\n return methodGate === 'observe'\n ? { enforce: false, source: 'methodGate' }\n : { enforce: true, config: methodGate, source: 'methodGate' };\n }\n // Non-tools/call methods (handshake / introspection) pass through unless a\n // methodGate opts them in — preserves open discovery for unregistered probes.\n return { enforce: false, source: 'discovery_default' };\n }\n const toolGate = opts.toolGates?.[parsed.toolName];\n if (toolGate !== undefined) {\n return toolGate === 'observe'\n ? { enforce: false, source: 'toolGate' }\n : { enforce: true, config: toolGate, source: 'toolGate' };\n }\n // tools/call with no explicit gate → enforced by default.\n return { enforce: mcpDefaultEnforced(parsed), source: 'tier' };\n}\n\n/**\n * Create the MCP middleware. Attach AFTER `express.json()` — the body must\n * already be a parsed object.\n */\nexport function createMcpMiddleware(options: McpMiddlewareOptions): RequestHandler {\n const {\n toolGates,\n methodGates,\n onAgentIdMismatch = 'reject',\n skip = false,\n onDenied = defaultMcpDenied,\n trustVerifiedHop = false,\n verifiedHopMaxAgeMs,\n recordDecisions,\n enableRuntimeChallenge = true,\n failOnError = 'open',\n ...config\n } = options;\n\n // v2.5.0: fire-and-forget pre-fetch of well-known URLs\n if (config.apiBaseUrl) {\n prefetchWellKnown(config.apiBaseUrl).catch(() => {});\n }\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n try {\n if (skip) return next();\n\n const parsed = parseMcpJsonRpc(req.body);\n if (!parsed) {\n // Not a JSON-RPC body. Either the route is misconfigured or the\n // client sent a non-MCP payload. We don't 400 here — let the actual\n // MCP server handler render its own error so the middleware doesn't\n // pre-empt valid framework error shapes.\n if (config.setPassThroughHeader) {\n // Round-10 (#49, O10): `unenforced` describes the GATE state, not\n // the downstream response. Renamed from the ambiguous\n // `pass-through` (which partners read as \"request succeeded\").\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader('X-Astra-Gateway-Reason', 'non-jsonrpc-body');\n }\n return next();\n }\n req.mcpRequest = parsed;\n\n // ── Identity reconciliation (defect d) ─────────────────────────────\n // Header value is the SDK-canonical slot; body slot exists for legacy\n // hand-written tool callers and the MCP `_meta.astrasync.agentId`\n // convention.\n const headerRaw = req.headers['x-astra-id'] ?? req.headers['x-astra-agentid'];\n const headerAstraId =\n typeof headerRaw === 'string'\n ? headerRaw\n : Array.isArray(headerRaw)\n ? headerRaw[0]\n : undefined;\n const bodyAstraId = parsed.agentIdFromBody;\n\n let effectiveAstraId: string | undefined;\n if (headerAstraId && bodyAstraId && headerAstraId !== bodyAstraId) {\n if (onAgentIdMismatch === 'reject') {\n const id = (req.body as Record<string, unknown>)?.id ?? null;\n res.status(400).json({\n jsonrpc: '2.0',\n id,\n error: {\n code: -32602,\n message: 'AGENT_ID_MISMATCH',\n data: {\n detail:\n 'The agent id in the X-Astra-Id header disagrees with params._meta.astrasync.agentId / params.arguments.agent_id. Reconcile before calling the tool — see https://astrasync.ai/docs/mcp-integration#identity-reconciliation.',\n headerAstraId,\n bodyAstraId,\n },\n },\n });\n return;\n }\n effectiveAstraId = onAgentIdMismatch === 'prefer-header' ? headerAstraId : bodyAstraId;\n } else {\n effectiveAstraId = headerAstraId ?? bodyAstraId;\n }\n\n // ── Inner-hop dedupe (defect c) ────────────────────────────────────\n // If a trusted upstream MCP hop already verified this exact ASTRA-id\n // a few ms ago, we accept the marker and skip a redundant verify-access\n // call. Only valid when the header is fresh AND matches the agent id\n // we resolved above.\n if (trustVerifiedHop && effectiveAstraId) {\n const hopRaw = req.headers[MCP_VERIFIED_HOP_HEADER.toLowerCase()];\n const hopValue =\n typeof hopRaw === 'string' ? hopRaw : Array.isArray(hopRaw) ? hopRaw[0] : undefined;\n const marker = parseVerifiedHop(hopValue);\n if (\n isVerifiedHopValidFor(marker, effectiveAstraId, {\n ...(verifiedHopMaxAgeMs !== undefined ? { maxAgeMs: verifiedHopMaxAgeMs } : {}),\n })\n ) {\n // Skip verify-access — pass straight through. Don't re-emit the\n // header since the MCP framework will issue the response (the\n // outer hop already tagged it for any further inner hops).\n return next();\n }\n }\n\n // ── Resolve gating ─────────────────────────────────────────────────\n const gateDecision = resolveGate(parsed, {\n toolGates,\n methodGates,\n });\n\n // ── Build verify-access request ────────────────────────────────────\n // Round-13 (R13-5) — credentials extraction hoisted above the\n // mcp-tier-none short-circuit (mirrors round-12 F9 express adapter\n // restructure). The `evaluateAlwaysIfCredentialed` flag lets the\n // caller turn unenforced tier-none calls into evaluated-not-enforced\n // calls when credentials are present, so the agent verification\n // result populates `req.agentVerification` for tier-aware handler\n // rendering (e.g. anonymous vs verified MCP tool listings).\n const credentials = extractCredentials(\n req.headers as Record<string, string | string[] | undefined>,\n req.query as Record<string, string | undefined>\n );\n // Override the SDK's default credential extraction with the resolved\n // ASTRA-id so the verify-access call sees the post-precedence value\n // (defect d). When neither header nor body supplied an id, the SDK's\n // anonymous-canonical-flow handles it.\n if (effectiveAstraId) credentials.astraId = effectiveAstraId;\n\n // Pass-through short-circuit. Default behaviour: skip verify-access for\n // observe / handshake / introspection (must work for unregistered\n // probes). With `evaluateAlwaysIfCredentialed: true` AND credentials\n // present, fall through to verify-access for the audit trail; the\n // post-verify gate-skipping branch below handles the rendering side.\n // Round-12 F9 parity (closes the round-12 deferral).\n const shouldEnforce = gateDecision.enforce;\n if (!shouldEnforce && (!config.evaluateAlwaysIfCredentialed || !credentials.astraId)) {\n if (config.setPassThroughHeader) {\n // Round-10 (#49, O10): `unenforced` describes the GATE state, not\n // the downstream response.\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader('X-Astra-Gateway-Reason', 'mcp-observe');\n }\n return next();\n }\n\n // Per-tool gate config (purpose + action + resource overrides).\n const gate = gateDecision.config;\n\n const headerPurpose = readSingleHeader(req.headers['x-astra-purpose']);\n const headerAction = readSingleHeader(req.headers['x-astra-action']);\n const pdlss = mcpToPdlss(\n parsed,\n req.path,\n headerPurpose,\n headerAction,\n gate ? { purpose: gate.purpose, action: gate.action, resource: gate.resource } : undefined\n );\n\n // Telemetry: debug log per resolution. Adoption tracking, support\n // triage, and the `default_*` / `transport_layer` decay signals\n // all read this. Both purpose and action emit their source so we\n // can spot which integration path each partner is using.\n if (config.debug) {\n // eslint-disable-next-line no-console\n console.debug('[mcp-middleware] pdlss resolved', {\n purpose_source: pdlss.purposeSource,\n resolved_purpose: pdlss.purpose,\n action_source: pdlss.actionSource,\n resolved_action: pdlss.action,\n });\n }\n\n // 3.2.0 — clear \"purpose required\" error. We only reach here on the\n // ENFORCED path (the `!shouldEnforce` early-return is above). A gated\n // tool call with no resolvable PDLSS purpose (none on the toolGate, no\n // X-Astra-Purpose header, none in the body) would otherwise hit\n // verify-access's generic \"Invalid request data\" → surface to the agent\n // as an opaque `verify_access.api_error`. Fail fast with an actionable\n // message instead (purpose is required post-vocabulary-unification).\n if (!pdlss.purpose) {\n const id = (req.body as Record<string, unknown>)?.id ?? null;\n res.status(400).json({\n jsonrpc: '2.0',\n id,\n error: {\n code: -32602,\n message: 'PDLSS_PURPOSE_REQUIRED',\n data: {\n dimension: 'pdlss.purpose',\n detail:\n 'This tool is access-gated but the call declared no PDLSS purpose. Supply a bare-category purpose via the X-Astra-Purpose header or params._meta.astrasync.purpose, or have the merchant set the tool’s purpose in its toolGate config.',\n resolvedAction: pdlss.action,\n },\n },\n });\n return;\n }\n\n const counterpartyUrl =\n config.counterpartyUrl || `${req.protocol}://${req.get('host')}${req.path}`;\n const shouldRecordDecisions = recordDecisions !== false;\n\n const verificationRequest: VerificationRequest = {\n credentials,\n purpose: pdlss.purpose,\n action: pdlss.action,\n resource: pdlss.resource,\n // Round-12 (F19): mark transport protocol separately from intent.\n // The MCP middleware always sets this to 'mcp'; non-MCP callers\n // leave it unset (server-side default is 'rest').\n invocationProtocol: 'mcp',\n createSession: shouldRecordDecisions,\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'mcp_server',\n enableRuntimeChallenge,\n callerMetadata: {\n sourceIp: req.ip,\n userAgent: req.headers['user-agent'] as string | undefined,\n host: req.headers.host as string | undefined,\n // Capture EVERY inbound header (parity with the express adapter —\n // MCP-only merchants have no edge to do it upstream) plus the\n // CDN-derived connection block. Local string work, secrets\n // stripped; out of the verify cache key so it doesn't defeat\n // caching.\n observedMetadata: buildSdkObservedMetadata(req.headers),\n },\n };\n let result = await verify(config, verificationRequest);\n\n req.agentVerification = result;\n let sessionId = (result as EnhancedVerificationResult).sessionId;\n\n // 3.6.0 hold-and-poll (opt-in via stepUpMaxWaitMs) — see express.ts for\n // the full rationale. On 'approved' the same request is re-verified\n // once, cache-bypassed, so the backend redeems the single-use approval.\n if (\n config.stepUpMaxWaitMs !== undefined &&\n result.policyAllowed &&\n requiresHumanApproval(result) &&\n result.stepUpApproval?.pollUrl\n ) {\n const outcome = await awaitStepUpApproval(config, result.stepUpApproval);\n res.setHeader('X-Astra-Step-Up', outcome);\n if (outcome === 'approved') {\n result = await verify(config, verificationRequest, { bypassCache: true });\n req.agentVerification = result;\n sessionId = (result as EnhancedVerificationResult).sessionId;\n } else {\n result.stepUpOutcome = outcome;\n }\n }\n\n // v2.3.9 (defect #30): denied verifications short-circuit BEFORE the\n // gate-level comparison. See express.ts for the full rationale —\n // mirroring it here so the MCP path inherits the same belt-and-braces\n // protection against access-level/help-payload conflation.\n // 4.5.0: gate on the SERVER decision only (`policyAllowed`) — anonymous\n // callers allowed by an audit/allow endpoint policy are honestly\n // identity-unverified; see express.ts.\n if (!result.policyAllowed) {\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // F2 direct-path fail-closed: a step-up / requires-approval outcome\n // (policyAllowed:true, allowed-but-escalate) cannot be completed\n // autonomously — deny and surface stepUpApproval polling info.\n if (requiresHumanApproval(result)) {\n annotateApprovalRequired(result);\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // Round-13 (R13-5): evaluation-without-enforcement parity with the\n // express F9 adapter. When the route is `none` but we ran\n // verify-access because `evaluateAlwaysIfCredentialed: true` AND\n // credentials were present, skip the gates and call next() — the\n // result is on `req.agentVerification` for the MCP handler to\n // render tier-aware responses (e.g. anonymous vs verified\n // tool-listing on the same `/mcp` endpoint).\n if (!shouldEnforce) {\n if (config.setPassThroughHeader) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.setHeader('X-Astra-Gateway-Reason', 'evaluated-not-enforced');\n }\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n return next();\n }\n\n // The access decision is the server's (identityVerified / policyAllowed,\n // denied above) — resting on a verified ID + runtime challenge + PDLSS\n // match + trust score. The per-tool gate only decides WHETHER a tool is\n // enforced at all (`shouldEnforce`, above); there is no client-side tier\n // veto (the access-level band was removed in SDK 5.0.0).\n\n // ── Tag the outbound response with X-Astra-Verified-Hop ────────────\n // Inner-hop REST endpoints called by this tool can read the header\n // and skip a duplicate verify-access. We set it on the response so\n // downstream proxies see it; tools that perform fetch() to an inner\n // hop should also forward it themselves (the MCP server framework\n // controls outbound calls — out of scope here).\n if (effectiveAstraId) {\n res.setHeader(\n MCP_VERIFIED_HOP_HEADER,\n serializeVerifiedHop({\n astraId: effectiveAstraId,\n ...(sessionId ? { sessionId } : {}),\n checkedAt: Date.now(),\n })\n );\n }\n\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n // v2.3.8 (defect #26): relay X-Astra-Unverified-Warning when the\n // server returned an audit-mode advisory.\n const enhancedResult = result as EnhancedVerificationResult;\n if (enhancedResult.warningHeader) {\n res.setHeader(enhancedResult.warningHeader.name, enhancedResult.warningHeader.value);\n }\n next();\n } catch (error) {\n // Audit F-A1-06: shadow-mode logging for fail-closed default migration.\n // Mirror of the express adapter pattern. Default 'open' for backward\n // compat in SDK 2.4.13; shadow logs let merchants grep correlationId\n // for impact analysis before the default flips in a follow-up release.\n const errorClass = error instanceof Error ? error.constructor.name : typeof error;\n const correlationId =\n (req.headers['x-request-id'] as string | undefined) ||\n (req.headers['x-correlation-id'] as string | undefined) ||\n `gen-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n // eslint-disable-next-line no-console\n console.error('[VerificationGateway/MCP] Middleware error:', error);\n // eslint-disable-next-line no-console\n console.warn(\n `[SHADOW] would-have-denied: errorClass=${errorClass} route=${req.method}:${req.path} merchantId=${config.counterpartyId ?? 'unknown'} correlationId=${correlationId}`\n );\n\n if (failOnError === 'closed') {\n const result: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: [`MCP middleware internal error: ${errorClass}`],\n failures: [\n {\n dimension: 'middleware.internal_error',\n message: `Middleware threw ${errorClass} — failing closed`,\n },\n ],\n verifiedAt: new Date(),\n correlationId,\n };\n const catchUrls = config.apiBaseUrl\n ? await getWellKnownUrls(config.apiBaseUrl).catch(() => undefined)\n : undefined;\n if (catchUrls) {\n result.guidance = {\n message: `Middleware threw ${errorClass} — failing closed`,\n registrationUrl: catchUrls.registrationUrl,\n documentationUrl: catchUrls.documentationUrl,\n };\n }\n dedupeFailures(result);\n return onDenied(result, req, res);\n }\n\n next();\n }\n };\n}\n\n// Re-export the helpers so consumers can mix-and-match (e.g. read the\n// verified-hop header themselves on a custom inner-hop handler).\nexport {\n parseMcpJsonRpc,\n mcpToPdlss,\n mcpDefaultEnforced,\n serializeVerifiedHop,\n parseVerifiedHop,\n isVerifiedHopValidFor,\n MCP_VERIFIED_HOP_HEADER,\n};\nexport type { ParsedMcpRequest } from '../transport/mcp-server';\n","import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the owner denies the\n * pending registration request. The `reason` field, when present, mirrors the\n * deny note the owner left in the dashboard.\n */\nexport class RegistrationDeniedError extends AstraSyncError {\n public readonly requestId: string;\n public readonly reason?: string;\n\n constructor(requestId: string, reason?: string) {\n super(\n `Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ''}`,\n 403,\n 'REGISTRATION_DENIED'\n );\n this.name = 'RegistrationDeniedError';\n this.requestId = requestId;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the pending request\n * passes its 14-day TTL with no owner decision. The agent must re-submit.\n */\nexport class RegistrationExpiredError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,\n 410,\n 'REGISTRATION_EXPIRED'\n );\n this.name = 'RegistrationExpiredError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the caller's local\n * `timeoutMs` elapses before the owner makes a decision. The request is still\n * live server-side — poll `pollRegistration(requestId)` to resume waiting, or\n * call `waitForApproval` again with a longer timeout.\n */\nexport class RegistrationTimeoutError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,\n 408,\n 'REGISTRATION_TIMEOUT'\n );\n this.name = 'RegistrationTimeoutError';\n this.requestId = requestId;\n }\n}\n","import { sdkFetch } from '../http';\nimport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n AgentRecord,\n} from './types';\nimport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n let raw = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n // Round-10 (O2): tolerate the verify-side convention. `GatewayConfig.apiBaseUrl`\n // is documented as `https://astrasync.ai/api` (with /api), but\n // `AstraSyncConfig.baseUrl` is documented as the bare origin. Partners\n // passing the verify-style URL to the registration client hit a 404\n // because we'd then append `/api/agents/register` → double /api. Strip\n // a trailing `/api` and warn once so the partner can fix the source.\n if (raw.toLowerCase().endsWith('/api')) {\n raw = raw.slice(0, -'/api'.length);\n if (config.baseUrl && !config.silent) {\n // eslint-disable-next-line no-console\n console.warn(\n `[AstraSync] baseUrl '${config.baseUrl}' had a trailing /api — stripped to '${raw}'. ` +\n `Pass the bare origin (e.g. 'https://astrasync.ai' or 'https://staging.astrasync.ai') ` +\n `to AstraSync(). The /api suffix is the verify-gateway (GatewayConfig.apiBaseUrl) convention.`\n );\n }\n }\n this.baseUrl = raw;\n\n // Env fallback is opt-OUT: server-side wrappers (MCP tool handlers,\n // gateway adapters) pass `disableEnvFallback: true` so a no-credentials\n // call from a user-facing flow cannot silently authenticate as the host\n // process's platform-attribution key. CLIs / scripts that legitimately\n // rely on ASTRASYNC_API_KEY keep working under the default.\n this.apiKey = config.disableEnvFallback\n ? config.apiKey\n : config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n // Defense-in-depth: warn when env fallback actually fires under the\n // default (non-strict) config. Surfaces the \"I'm running as platform\"\n // foot-gun before it becomes a security bug. Gated by !silent.\n if (\n !config.apiKey &&\n !config.disableEnvFallback &&\n process.env.ASTRASYNC_API_KEY &&\n !config.silent\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n '[AstraSync] No apiKey passed to constructor; using process.env.ASTRASYNC_API_KEY. ' +\n 'If this code wraps user-facing flows (e.g. MCP tool handlers), pass ' +\n 'disableEnvFallback: true to prevent ambient credentials from impersonating callers. ' +\n 'See https://astrasync.ai/docs/agent-access#disableenvfallback for details.'\n );\n }\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n *\n * The backend response depends on auth context:\n * - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,\n * returns `{ status: 'active', agent }`.\n * - **API-key only** (no signature): 202 pending, returns\n * `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The\n * owner is notified by email and a dashboard alert is emitted; the agent\n * becomes active only after the owner approves.\n *\n * Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the\n * request until it resolves, then return the live agent record. The promise\n * rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or\n * `RegistrationTimeoutError` on the corresponding terminal states.\n *\n * @example Non-blocking (default — best for serverless / scheduled agents):\n * ```typescript\n * const result = await sdk.register({ name, pdlss });\n * if (result.status === 'pending_approval') {\n * storeRequestId(result.requestId);\n * return; // function exits; resume later via pollRegistration()\n * }\n * ```\n *\n * @example Blocking (best for long-running services + CLI):\n * ```typescript\n * const agent = await sdk.register({\n * name, pdlss, waitForApproval: true, timeoutMs: 600_000,\n * onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),\n * });\n * ```\n */\n async register(\n options: RegisterOptions & WaitForApprovalOptions\n ): Promise<RegisterResult | AgentRecord> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n const { status, body: raw } = await this.requestWithStatus<\n RegistrationResponse | PendingRegistrationResponse\n >('POST', '/api/agents/register', body);\n\n if (status === 201) {\n const activeBody = raw as RegistrationResponse;\n const active: RegisterResult = {\n status: 'active',\n agent: activeBody.data.agent,\n // Round-12 (F16): pass backend advisories through verbatim.\n // Pre-fix the SDK whitelisted five fields and silently dropped\n // `warnings`, which left partners with no signal that\n // `no_callback_endpoint` (or future advisories) had fired.\n ...(activeBody.warnings && { warnings: activeBody.warnings }),\n };\n return active;\n }\n\n // 202 Accepted — owner approval required.\n const pendingBody = raw as PendingRegistrationResponse;\n const pending: RegisterResult = {\n status: 'pending_approval',\n requestId: pendingBody.requestId,\n expiresAt: pendingBody.expiresAt,\n pollUrl: pendingBody.pollUrl,\n message: pendingBody.message,\n // Round-12 (F16): same pass-through on the pending path.\n ...(pendingBody.warnings && { warnings: pendingBody.warnings }),\n };\n\n if (!options.waitForApproval) return pending;\n\n return this.waitForApproval(pendingBody.requestId, options);\n }\n\n /**\n * Poll the current state of a pending-approval registration request.\n *\n * Useful for caller-driven polling when `waitForApproval: false` (the\n * default). The endpoint is unauthenticated — pass the `requestId` that\n * was returned from the 202 response.\n *\n * @returns `state: 'pending'` while awaiting; `'approved'` carries the\n * minted agent in `agent`; `'denied'` may carry the owner's\n * `reason`; `'expired'` is terminal after 14 days.\n */\n async pollRegistration(requestId: string): Promise<PollRegistrationResult> {\n const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;\n const res = await sdkFetch(url, { headers: { Accept: 'application/json' } });\n if (!res.ok) {\n const errBody = (await res.json().catch(() => ({}))) as ApiErrorResponse;\n throw new AstraSyncError(\n errBody.error || `pollRegistration failed: ${res.status}`,\n res.status,\n errBody.code\n );\n }\n return (await res.json()) as PollRegistrationResult;\n }\n\n /**\n * Block until a pending registration request resolves to a terminal state.\n * Resolves to the live `AgentRecord` on approval; rejects with the matching\n * Registration*Error on deny/expire/timeout. Usually called via\n * `register({ waitForApproval: true })`, but exposed for callers that want\n * to fire-and-forget the initial register call and resume waiting later\n * (e.g. after restoring a stored `requestId` on cold start).\n */\n async waitForApproval(\n requestId: string,\n options: WaitForApprovalOptions = {}\n ): Promise<AgentRecord> {\n const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;\n const pollIntervalMs = options.pollIntervalMs ?? 5_000;\n const start = Date.now();\n const deadline = start + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await this.pollRegistration(requestId);\n const ageMs = Date.now() - start;\n options.onPending?.({ requestId, ageMs });\n\n if (result.state === 'approved') {\n if (!result.agent) {\n throw new AstraSyncError(\n `Registration ${requestId} reported approved but no agent payload returned.`,\n 500\n );\n }\n return result.agent;\n }\n if (result.state === 'denied') {\n throw new RegistrationDeniedError(requestId, result.reason);\n }\n if (result.state === 'expired') {\n throw new RegistrationExpiredError(requestId);\n }\n await sleep(pollIntervalMs);\n }\n throw new RegistrationTimeoutError(requestId);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await sdkFetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const { body: parsed } = await this.requestWithStatus<T>(method, endpoint, body);\n return parsed;\n }\n\n /**\n * Variant of {@link request} that also returns the HTTP status code, so\n * callers can branch on 201 vs 202 (or other success codes) without losing\n * type information about the response body.\n */\n private async requestWithStatus<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await sdkFetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return { status: res.status, body: (await res.json()) as T };\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await sdkFetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n","/**\n * Guidance envelope for credentials-required cases.\n *\n * A single shared source of truth so partners writing their own wrappers\n * (custom MCP servers, Express middleware around registration, gateway\n * adapters) consume a single source of truth instead of re-implementing the\n * five-step boilerplate.\n *\n * The envelope is what an agent (or wrapping MCP client) sees when it calls\n * `register_agent` with no AstraSync credentials. It tells the calling agent\n * (a) what failed (`status: 'credentials_required'`), (b) the keyless\n * registration ACTION endpoint (`registrationUrl` — POST-able, not the human\n * dashboard), (c) where the relevant docs are (`documentationUrl`), and (d) the\n * ordered next-actions (`steps`).\n */\n\nexport interface GuidanceEnvelope {\n /**\n * Single-literal today. Expand to a union (e.g.\n * `'credentials_required' | 'kyd_required' | …`) when a second guidance\n * status emerges. Don't pre-emptively widen — the literal pins the shape.\n */\n status: 'credentials_required';\n message: string;\n guidance: {\n message: string;\n registrationUrl: string;\n documentationUrl: string;\n steps: string[];\n };\n}\n\nexport interface BuildGuidanceParams {\n /**\n * Bare origin of the AstraSync deployment the caller should register at,\n * e.g. `https://astrasync.ai` or `https://staging.astrasync.ai`. No\n * trailing slash, no `/api` suffix — registrationUrl and documentationUrl\n * are templated relative to this origin.\n */\n origin: string;\n /**\n * Overrides the top-level `message` (the short summary the agent sees).\n * Defaults to the error message from the SDK's `AuthenticationError`\n * when present, else a generic \"credentials required\" line.\n */\n message?: string;\n /**\n * Overrides the documentation path. Defaults to `/docs/agent-access`.\n */\n documentationPath?: string;\n}\n\n/**\n * Build the credentials-required guidance envelope.\n *\n * This is the canonical builder — MCP wrappers (`agent-registration.ts`),\n * Express middleware in custom integrations, and any other partner-side\n * wrapper that needs to surface \"you need to register\" should call this\n * rather than reconstructing the shape inline. Inline reconstruction\n * historically led to drift between wrappers; this consolidates it.\n *\n * @example\n * ```ts\n * import { buildGuidance } from '@astrasyncai/verification-gateway';\n *\n * try {\n * const sdk = new AstraSync({ apiKey: callerApiKey, disableEnvFallback: true });\n * // ...\n * } catch (err) {\n * if (err instanceof AuthenticationError) {\n * return buildGuidance({ origin: 'https://astrasync.ai', message: err.message });\n * }\n * throw err;\n * }\n * ```\n */\nexport function buildGuidance(params: BuildGuidanceParams): GuidanceEnvelope {\n const origin = params.origin.replace(/\\/+$/, '');\n const docsPath = params.documentationPath ?? '/docs/agent-access';\n const message = params.message ?? 'AstraSync registration requires credentials.';\n\n return {\n status: 'credentials_required',\n message,\n guidance: {\n message:\n \"Register either with an agent-scoped API key (the recommended credentialed path) OR, if you hold no credentials, via the owner's email using request_registration. Never send a password or private key over the wire.\",\n // 3.0.0: registrationUrl is the agent-actionable KEYLESS endpoint, not the\n // human dashboard `/agents/register` (an auth-walled page an agent can't\n // use). documentationUrl carries the machine-readable contract.\n registrationUrl: `${origin}/api/agents/request-registration`,\n documentationUrl: `${origin}${docsPath.startsWith('/') ? docsPath : `/${docsPath}`}`,\n steps: [\n 'Credentialed path (recommended): have your human mint an agent-scoped API key at Settings → API Keys, then re-call register_agent with apiKey set. An agent holding its own scoped kya_ key is fine and intended.',\n \"No-credentials path: call request_registration({ name, ownerEmail, ... }) with the human owner's email — the only bootstrap credential. No API key is involved.\",\n 'Include as much metadata as you can in the registration — especially model ({ modelName, modelProvider }) and framework ({ frameworkName, frameworkVersion }). Declared platform/model metadata directly improves your trust score and attributes your traffic correctly.',\n 'The owner approves via an emailed link (first time, they create an account and complete a quick verification).',\n 'Use poll_registration({ requestId }) once the owner confirms approval to retrieve the astraId.',\n 'Never transmit a password or private key over the MCP wire — those are never required.',\n ],\n },\n };\n}\n","/**\n * Agent-Side SDK Module\n *\n * Tools for AI agents to present credentials, handle challenges,\n * and interact with the AstraSync verification protocol.\n */\n\nexport { AgentClient } from './client';\nexport { ChallengeHandler } from './challenge-handler';\nexport { formatPDLSSForTransport, parsePDLSSFromTransport } from './pdlss-formatter';\nexport type { PDLSSConfig, TransportPDLSS } from './pdlss-formatter';\nexport { recordDecision } from './decision-client';\nexport { AstraSyncSdkError, OwnershipMismatchError } from './errors';\n","/**\n * Agent-side SDK errors.\n */\n\nexport class AstraSyncSdkError extends Error {\n readonly code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'AstraSyncSdkError';\n this.code = code;\n }\n}\n\n/**\n * Thrown when the API key used to initialise AgentClient is not owned by\n * the same account that registered the configured ASTRA-id. Blocks the\n * client from doing anything under a mismatched identity.\n */\nexport class OwnershipMismatchError extends AstraSyncSdkError {\n readonly astraId: string;\n\n constructor(astraId: string) {\n super(\n 'ownership_mismatch',\n `The configured API key does not own agent ${astraId}. Refusing to initialise.`\n );\n this.name = 'OwnershipMismatchError';\n this.astraId = astraId;\n }\n}\n","/**\n * AgentClient — Credential Presentation\n *\n * Agent-side SDK for automatically injecting AstraSync credentials\n * into outgoing requests across all supported protocols.\n */\n\nimport { sdkFetch } from '../http';\nimport type { AstraSyncCredentials, ProtocolTransport } from '../types';\nimport { setHttpHeaders } from '../transport/http';\nimport { setA2AMetadata } from '../transport/a2a';\nimport { setMcpMeta } from '../transport/mcp';\nimport { applyCredentials } from '../transport';\nimport { OwnershipMismatchError } from './errors';\n\ninterface AgentClientConfig {\n agentId: string;\n verifyUrl?: string;\n challengeUrl?: string;\n pdlss?: AstraSyncCredentials['pdlss'];\n /** Base URL for AstraSync API (used for ownership check). Defaults to https://astrasync.ai/api */\n apiBaseUrl?: string;\n /** API key used to authenticate ownership check + other authenticated calls. */\n apiKey?: string;\n}\n\ninterface FetchOptions extends RequestInit {\n purpose?: string;\n action?: string;\n}\n\nexport class AgentClient {\n private credentials: AstraSyncCredentials;\n private apiBaseUrl: string;\n private apiKey: string | undefined;\n\n constructor(config: AgentClientConfig) {\n this.credentials = {\n agentId: config.agentId,\n verifyUrl: config.verifyUrl ?? 'https://astrasync.ai/api/agents/verify-access',\n challengeUrl: config.challengeUrl,\n pdlss: config.pdlss,\n };\n this.apiBaseUrl = config.apiBaseUrl ?? 'https://astrasync.ai/api';\n this.apiKey = config.apiKey;\n }\n\n /**\n * Async factory that validates the API key's account owns the configured\n * ASTRA-id before returning a usable client. Refuses to initialise on\n * mismatch so a stolen ASTRA-id cannot be paired with a valid (different)\n * API key.\n *\n * Set env `ASTRASYNC_SKIP_OWNERSHIP_CHECK=true` to bypass — intended for\n * test environments only.\n */\n static async create(config: AgentClientConfig): Promise<AgentClient> {\n const client = new AgentClient(config);\n\n const skip =\n typeof process !== 'undefined' && process.env?.ASTRASYNC_SKIP_OWNERSHIP_CHECK === 'true';\n if (skip) return client;\n\n if (!config.apiKey) {\n // Without an API key we cannot bind ownership. Surface this as the\n // same refusal so misconfigured clients fail loudly.\n throw new OwnershipMismatchError(config.agentId);\n }\n\n const owned = await client.verifyOwnership();\n if (!owned) throw new OwnershipMismatchError(config.agentId);\n return client;\n }\n\n /**\n * Calls GET /api/agents/:astraId/ownership with the configured API key.\n * Returns true only when the backend confirms this API key's account\n * owns the configured agent.\n */\n private async verifyOwnership(): Promise<boolean> {\n if (!this.apiKey) return false;\n const url = `${this.apiBaseUrl.replace(/\\/+$/, '')}/api/agents/${encodeURIComponent(\n this.credentials.agentId\n )}/ownership`;\n const resp = await sdkFetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n });\n if (!resp.ok) return false;\n const body = (await resp.json().catch(() => null)) as {\n success?: boolean;\n data?: { owned?: boolean };\n } | null;\n return Boolean(body?.data?.owned);\n }\n\n /**\n * Make an HTTP request with AstraSync headers automatically injected.\n */\n async fetch(url: string, options?: FetchOptions): Promise<Response> {\n const { purpose, action, ...fetchOptions } = options ?? {};\n\n // Build credentials with optional overrides\n const creds: AstraSyncCredentials = { ...this.credentials };\n if (purpose) {\n creds.pdlss = {\n ...creds.pdlss,\n purpose: { category: purpose, action },\n };\n }\n\n // Inject AstraSync headers\n const existingHeaders: Record<string, string> = {};\n if (fetchOptions.headers) {\n if (fetchOptions.headers instanceof Headers) {\n fetchOptions.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n } else if (Array.isArray(fetchOptions.headers)) {\n for (const [key, value] of fetchOptions.headers) {\n existingHeaders[key] = value;\n }\n } else {\n Object.assign(existingHeaders, fetchOptions.headers);\n }\n }\n\n const enrichedHeaders = setHttpHeaders(existingHeaders, creds);\n\n return sdkFetch(url, {\n ...fetchOptions,\n headers: enrichedHeaders,\n });\n }\n\n /**\n * Prepare A2A task metadata with AstraSync credentials.\n */\n prepareA2AMetadata(\n task: Record<string, unknown>,\n overrides?: { purpose?: string; action?: string }\n ): Record<string, unknown> {\n const creds = this.buildCredentials(overrides);\n return setA2AMetadata(task, creds);\n }\n\n /**\n * Prepare MCP params with AstraSync _meta.\n */\n prepareMcpMeta(\n params: Record<string, unknown>,\n overrides?: { purpose?: string; action?: string }\n ): Record<string, unknown> {\n const creds = this.buildCredentials(overrides);\n return setMcpMeta(params, creds);\n }\n\n /**\n * Generic: apply credentials to any protocol.\n */\n applyCredentials(\n protocol: ProtocolTransport,\n target: Record<string, unknown>,\n overrides?: { purpose?: string; action?: string }\n ): Record<string, unknown> {\n const creds = this.buildCredentials(overrides);\n return applyCredentials(protocol, target, creds);\n }\n\n private buildCredentials(overrides?: {\n purpose?: string;\n action?: string;\n }): AstraSyncCredentials {\n if (!overrides?.purpose) return this.credentials;\n\n return {\n ...this.credentials,\n pdlss: {\n ...this.credentials.pdlss,\n purpose: { category: overrides.purpose, action: overrides.action },\n },\n };\n }\n}\n","/**\n * ChallengeHandler — Agent-Side Runtime Challenge Responder\n *\n * Handles incoming runtime challenges from AstraSync's verification service.\n * Agents register pending counterparties before initiating contact,\n * then this handler validates and responds to challenges.\n */\n\ninterface ChallengePayload {\n challengeId: string;\n type: string;\n counterpartyId?: string | null;\n counterpartyUrl?: string | null;\n question?: string;\n issuedAt: string;\n expiresAt: string;\n}\n\ninterface ChallengeResponse {\n status: number;\n body: {\n challengeId: string;\n acknowledged: boolean;\n pendingCounterparties: string[];\n respondedAt: string;\n error?: string;\n };\n}\n\ninterface ChallengeHandlerConfig {\n agentId: string;\n}\n\nexport class ChallengeHandler {\n private agentId: string;\n private pendingCounterparties: Set<string> = new Set();\n\n constructor(config: ChallengeHandlerConfig) {\n this.agentId = config.agentId;\n }\n\n /**\n * Register a counterparty as pending (before initiating contact).\n */\n registerPending(counterpartyId: string): void {\n this.pendingCounterparties.add(counterpartyId);\n }\n\n /**\n * Remove a counterparty from pending list (after interaction complete).\n */\n removePending(counterpartyId: string): void {\n this.pendingCounterparties.delete(counterpartyId);\n }\n\n /**\n * Get current pending counterparties list.\n */\n getPendingList(): string[] {\n return [...this.pendingCounterparties];\n }\n\n /**\n * Express middleware for the challenge endpoint.\n * Mount at: app.post('/astrasync/challenge', handler.expressMiddleware())\n */\n expressMiddleware(): (\n req: { body: unknown },\n res: { status: (code: number) => { json: (body: unknown) => void } }\n ) => void {\n return (req, res) => {\n const result = this.handleChallenge(req.body);\n res.status(result.status).json(result.body);\n };\n }\n\n /**\n * Generic handler (framework-agnostic).\n * Returns { status, body } for the caller to send.\n */\n handleChallenge(body: unknown): ChallengeResponse {\n // Validate payload shape\n if (!body || typeof body !== 'object') {\n return {\n status: 400,\n body: {\n challengeId: '',\n acknowledged: false,\n pendingCounterparties: [],\n respondedAt: new Date().toISOString(),\n error: 'Invalid challenge payload',\n },\n };\n }\n\n const payload = body as ChallengePayload;\n\n if (!payload.challengeId || !payload.issuedAt || !payload.expiresAt) {\n return {\n status: 400,\n body: {\n challengeId: payload.challengeId ?? '',\n acknowledged: false,\n pendingCounterparties: [],\n respondedAt: new Date().toISOString(),\n error: 'Missing required challenge fields',\n },\n };\n }\n\n // Check if challenge has expired\n const now = new Date();\n const expiresAt = new Date(payload.expiresAt);\n if (now > expiresAt) {\n return {\n status: 410,\n body: {\n challengeId: payload.challengeId,\n acknowledged: false,\n pendingCounterparties: [],\n respondedAt: now.toISOString(),\n error: 'Challenge has expired',\n },\n };\n }\n\n // Build the pending counterparties list. When the agent has pre-registered\n // counterparties via registerPending(), use that whitelist. Otherwise,\n // auto-include the incoming counterpartyId/counterpartyUrl from the\n // challenge payload so the default behaviour is correct without requiring\n // agents to call registerPending() before every interaction.\n const explicitList = this.getPendingList();\n const pendingCounterparties =\n explicitList.length > 0\n ? explicitList\n : [payload.counterpartyId, payload.counterpartyUrl].filter(\n (v): v is string => typeof v === 'string' && v.length > 0\n );\n\n return {\n status: 200,\n body: {\n challengeId: payload.challengeId,\n acknowledged: true,\n pendingCounterparties,\n respondedAt: now.toISOString(),\n },\n };\n }\n}\n","/**\n * PDLSS Formatter — Transport Format Conversion\n *\n * Converts between full PDLSS boundaries and compact transport format\n * used in HTTP headers, A2A metadata, and MCP _meta blocks.\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\n/**\n * Full PDLSS configuration (as returned by the backend).\n */\nexport interface PDLSSConfig {\n purpose?: {\n categories?: string[];\n allowedActions?: string[];\n deniedActions?: string[];\n };\n duration?: {\n maxSessionDuration?: number;\n ttl?: number;\n allowedDays?: number[];\n allowedHours?: { start: number; end: number };\n };\n limits?: {\n autonomousThreshold?: number;\n approvalThreshold?: number;\n currency?: string;\n };\n scope?: {\n jurisdictions?: string[];\n resources?: string[];\n resourceTypes?: string[];\n };\n selfInstantiation?: {\n allowed: boolean;\n maxDepth?: number;\n maxSubAgents?: number;\n };\n}\n\n/**\n * Compact transport format (embedded in headers/metadata).\n */\nexport type TransportPDLSS = NonNullable<AstraSyncCredentials['pdlss']>;\n\n/**\n * Convert full PDLSS boundaries into compact transport format.\n * Used by AgentClient when building credential headers/metadata.\n */\nexport function formatPDLSSForTransport(pdlss: PDLSSConfig): TransportPDLSS {\n const transport: TransportPDLSS = {};\n\n // Purpose: pick the primary category and first allowed action\n if (pdlss.purpose?.categories?.length) {\n transport.purpose = {\n category: pdlss.purpose.categories[0],\n action: pdlss.purpose.allowedActions?.[0],\n };\n }\n\n // Duration: use the shorter of maxSessionDuration and ttl\n if (pdlss.duration) {\n const candidates: number[] = [];\n if (pdlss.duration.maxSessionDuration) candidates.push(pdlss.duration.maxSessionDuration);\n if (pdlss.duration.ttl) candidates.push(pdlss.duration.ttl);\n if (candidates.length > 0) {\n transport.duration = { maxSessionDuration: Math.min(...candidates) };\n }\n }\n\n // Scope: use the primary jurisdiction\n if (pdlss.scope?.jurisdictions?.length) {\n transport.scope = { jurisdiction: pdlss.scope.jurisdictions[0] };\n }\n\n return transport;\n}\n\n/**\n * Parse transport format back into full PDLSS config.\n * Used by counterparty-side when receiving credentials.\n */\nexport function parsePDLSSFromTransport(transport: TransportPDLSS): PDLSSConfig {\n const pdlss: PDLSSConfig = {};\n\n if (transport.purpose) {\n pdlss.purpose = {\n categories: [transport.purpose.category],\n allowedActions: transport.purpose.action ? [transport.purpose.action] : undefined,\n };\n }\n\n if (transport.duration) {\n pdlss.duration = {\n maxSessionDuration: transport.duration.maxSessionDuration,\n };\n }\n\n if (transport.scope) {\n pdlss.scope = {\n jurisdictions: transport.scope.jurisdiction ? [transport.scope.jurisdiction] : undefined,\n };\n }\n\n return pdlss;\n}\n","/**\n * Decision Client — Counterparty-Side Decision Recording\n *\n * Helper for counterparties to record their grant/deny decisions\n * back to AstraSync after receiving a verification result.\n */\n\nimport { sdkFetch } from '../http';\nimport type { GatewayConfig } from '../types';\n\ninterface RecordDecisionParams {\n sessionId: string;\n decision: 'granted' | 'denied';\n reason?: string;\n tokenIssued?: boolean;\n auditId?: string;\n}\n\ninterface RecordDecisionResult {\n recorded: boolean;\n blockchainTxHash?: string;\n}\n\n/**\n * Record a counterparty's grant/deny decision for a verification session.\n * POST to /agents/verify-access/:sessionId/decision\n */\nexport async function recordDecision(\n config: GatewayConfig,\n params: RecordDecisionParams\n): Promise<RecordDecisionResult> {\n const { sessionId, ...body } = params;\n const baseUrl = config.apiBaseUrl.replace(/\\/$/, '');\n const url = `${baseUrl}/agents/verify-access/${encodeURIComponent(sessionId)}/decision`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n }\n\n if (config.customHeaders) {\n Object.assign(headers, config.customHeaders);\n }\n\n const response = await sdkFetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(\n `Failed to record decision for session ${sessionId}: ${response.status} ${errorText}`\n );\n }\n\n const result = await response.json();\n\n return {\n recorded: result.recorded ?? true,\n blockchainTxHash: result.blockchainTxHash,\n };\n}\n","/**\n * HTTP-client RUNTIME signatures — a display-only vocabulary, disjoint from\n * the platform-agent vendor vocabulary in `platform-signatures.ts`.\n *\n * A UA of `node` or `python-requests` identifies the HTTP STACK, never the\n * operator: OpenAI Codex, Claude Code, Perplexity's tooling, and our own SDK\n * all fetch through Node — labeling any of them a vendor from the runtime\n * alone would be fabrication. What we CAN say honestly is \"undeclared\n * automation on the Node.js runtime\", which beats \"unknown\" in every surface.\n *\n * HARD RULE: this module must NEVER be consulted by `edge-core/classify.ts`,\n * `detectPlatformFingerprint`, or any tiering / orphan-provisioning path.\n * Runtime matches carry no identity: promoting them to the `identified` tier\n * would flip anonymous-bot traffic to 1:1 beacons and auto-provision orphan\n * agents literally named \"node\". Display and clustering layers only.\n */\n\nexport interface RuntimeSignature {\n /** Stable runtime key — namespace disjoint from `PlatformAgentVendor`. */\n runtime: string;\n /** Human-readable label, e.g. \"Node.js runtime\". */\n displayName: string;\n uaPatterns: RegExp[];\n}\n\n/** First match wins — order more-specific tokens before generic ones. */\nexport const RUNTIME_SIGNATURES: ReadonlyArray<RuntimeSignature> = [\n {\n runtime: 'browser-automation',\n displayName: 'Browser automation',\n uaPatterns: [/headless/i, /phantomjs/i, /selenium/i, /playwright/i, /puppeteer/i],\n },\n {\n runtime: 'nodejs',\n displayName: 'Node.js runtime',\n // `node` exactly is the global-fetch default UA; the token forms cover\n // the common Node HTTP libraries.\n uaPatterns: [/^node$/i, /^undici/i, /node-fetch/i, /^axios/i, /^got\\b/i, /needle/i],\n },\n {\n runtime: 'python',\n displayName: 'Python runtime',\n uaPatterns: [/python-requests/i, /python-urllib/i, /^python\\b/i, /httpx/i, /aiohttp/i],\n },\n { runtime: 'go', displayName: 'Go runtime', uaPatterns: [/go-http-client/i] },\n {\n runtime: 'java',\n displayName: 'Java runtime',\n uaPatterns: [/^java\\//i, /okhttp/i, /apache-httpclient/i],\n },\n { runtime: 'curl', displayName: 'curl', uaPatterns: [/^curl\\//i] },\n { runtime: 'wget', displayName: 'wget', uaPatterns: [/^wget\\//i] },\n { runtime: 'ruby', displayName: 'Ruby runtime', uaPatterns: [/^ruby\\b/i, /faraday/i] },\n {\n runtime: 'php',\n displayName: 'PHP runtime',\n uaPatterns: [/^php\\b/i, /guzzlehttp/i, /^symfony/i],\n },\n { runtime: 'dotnet', displayName: '.NET runtime', uaPatterns: [/^dotnet/i, /httpclient/i] },\n { runtime: 'dart', displayName: 'Dart runtime', uaPatterns: [/^dart/i] },\n];\n\n/**\n * Detect the HTTP-client runtime from a User-Agent. Returns the displayName\n * (e.g. \"Node.js runtime\") or undefined when the UA doesn't look like a bare\n * runtime/library client.\n */\nexport function detectRuntime(userAgent: string | undefined | null): string | undefined {\n if (!userAgent) return undefined;\n const ua = userAgent.trim();\n for (const sig of RUNTIME_SIGNATURES) {\n if (sig.uaPatterns.some((p) => p.test(ua))) return sig.displayName;\n }\n return undefined;\n}\n"],"mappings":"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","names":["has","result","cache","inflight","headerValue","result","createMiddleware","matchRoute","findRouteConfig","DEFAULT_ROUTES_REFRESH_MS","createMiddleware","readHeader","coerceString","stripQuery","extractSessionId","readHeader","coerceString","coerceString","coerceNumber","claim","decodeSdJwtSync","createHash","sha256Sync","applyDisclosures","coerceMandateType","coerceString","coerceNumber","headerValue","readHeader","coerceString","headerValue","readHeader","createHash","coerceString","createHash","toUnixSeconds","cache","cache","dedupeFailures","sleep","recordDecision","recordDecision"]}
|
|
1
|
+
{"version":3,"sources":["../src/trust-levels.ts","../src/version.ts","../src/http.ts","../src/well-known.ts","../src/verify.ts","../src/adapters/stepup-poll.ts","../src/adapters/approval-gate.ts","../src/settlement.ts","../src/adapters/express.ts","../src/transport/http.ts","../src/verified-hop.ts","../src/adapters/http-pdlss.ts","../src/pdlss-pre-check.ts","../src/metadata-capture.ts","../src/edge-config.ts","../src/platform-signatures.ts","../src/edge-core/classify.ts","../src/edge-core/events.ts","../src/adapters/anonymous-beacon.ts","../src/adapters/nextjs.ts","../src/adapters/sdk.ts","../src/transport/index.ts","../src/transport/a2a.ts","../src/transport/mcp.ts","../src/transport/purpose-mapping.ts","../src/transport/transaction-value.ts","../src/transport/rfc9421.ts","../src/transport/rfc9421-verify.ts","../src/transport/nonce-store.ts","../src/transport/ucp.ts","../src/transport/acp.ts","../src/transport/vi.ts","../src/transport/stripe-webhook.ts","../src/transport/constraint-eval.ts","../src/transport/identity-binding.ts","../src/transport/ap2.ts","../src/transport/ap2-verify.ts","../src/transport/acp-verify.ts","../src/transport/mpp.ts","../src/transport/mpp-verify.ts","../src/transport/x402.ts","../src/transport/vi-verify.ts","../src/transport/commerce-pipeline.ts","../src/transport/extractor-registry.ts","../src/transport/registry/visa.ts","../src/transport/registry/mastercard.ts","../src/transport/registry/web-bot-auth.ts","../src/transport/mcp-server.ts","../src/adapters/mcp.ts","../src/registration/errors.ts","../src/registration/api.ts","../src/registration/guidance.ts","../src/agent/index.ts","../src/agent/errors.ts","../src/agent/client.ts","../src/agent/challenge-handler.ts","../src/agent/pdlss-formatter.ts","../src/agent/decision-client.ts","../src/runtime-signatures.ts"],"sourcesContent":["/**\n * AstraSync Universal Verification Gateway — Trust Level helpers.\n *\n * SDK 5.0.0: the `accessLevel` band (`none`/`restricted`/`read-only`/`standard`/\n * `full`/`internal`) was removed entirely — it never gated the access decision\n * (the server does, from a verified ID + runtime challenge + PDLSS match + trust\n * score). What remains here is the coarse trust-level badge derived from the\n * numeric trust score, used only for display.\n */\n\nimport type { TrustLevel } from './types';\n\n/**\n * Trust level score ranges\n */\nexport const TRUST_LEVEL_RANGES: Record<TrustLevel, { min: number; max: number }> = {\n BRONZE: { min: 0, max: 39 },\n SILVER: { min: 40, max: 59 },\n GOLD: { min: 60, max: 79 },\n PLATINUM: { min: 80, max: 100 },\n};\n\n/**\n * Determine trust level from score\n */\nexport function getTrustLevel(score: number): TrustLevel {\n if (score >= 80) return 'PLATINUM';\n if (score >= 60) return 'GOLD';\n if (score >= 40) return 'SILVER';\n return 'BRONZE';\n}\n","/**\n * Single source-of-truth for the SDK's\n * package version emitted on verify-access bodies (and any future\n * telemetry). Bumped alongside `package.json#version` on every release.\n *\n * Why a constant rather than `import pkg from '../package.json'`:\n * - `tsconfig.json` sets `rootDir: ./src`; importing the sibling\n * package.json fails the build with \"outside rootDir\".\n * - Build-time string replacement (tsup `define`, esbuild banner, etc.)\n * adds toolchain coupling for a trivial gain.\n * - Embedded readonly constant works in every environment (Node, browser,\n * bundlers, Deno) without runtime fs / network access.\n *\n * Release discipline: a CI lint can grep `package.json#version` against\n * this constant if the two ever diverge in the wild. A manual bump\n * is fine — bumping both in the release-ceremony commit keeps them\n * lockstep.\n */\nexport const SDK_VERSION = '5.5.0';\n","/**\n * Shared outbound-HTTP wrapper — every request the SDK makes to the\n * AstraSync backend (or anywhere else) goes through `sdkFetch` so it\n * carries an identifying User-Agent.\n *\n * Why: Node's global fetch defaults to `user-agent: node`, which is\n * indistinguishable from every other Node client on the wire. Visit\n * Intelligence observed our own SDK/beacon traffic as anonymous \"node\"\n * visits. Self-identification is the platform's own medicine.\n *\n * Browser note: some browsers filter the User-Agent request header\n * silently (never throwing), so this is a no-op there — which is correct:\n * in a browser the page's real UA is the honest identity.\n */\n\nimport { SDK_VERSION } from './version';\n\nexport const SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;\n\n/**\n * Add the SDK User-Agent without changing the SHAPE of the caller's headers\n * (plain records stay plain records) — interceptors, adapters, and tests\n * read `init.headers` as a record, and `Headers` would also lowercase names.\n */\nfunction withUserAgent(initHeaders: HeadersInit | undefined): HeadersInit {\n if (!initHeaders) return { 'user-agent': SDK_USER_AGENT };\n if (initHeaders instanceof Headers) {\n const copy = new Headers(initHeaders);\n if (!copy.has('user-agent')) copy.set('user-agent', SDK_USER_AGENT);\n return copy;\n }\n if (Array.isArray(initHeaders)) {\n const has = initHeaders.some(([name]) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : [...initHeaders, ['user-agent', SDK_USER_AGENT]];\n }\n const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : { 'user-agent': SDK_USER_AGENT, ...initHeaders };\n}\n\nexport const sdkFetch: typeof fetch = (input, init) =>\n fetch(input, { ...init, headers: withUserAgent(init?.headers) });\n","import { sdkFetch } from './http';\n/**\n * SDK-side discovery of canonical platform URLs via `/.well-known/agentic-commerce`.\n *\n * Fire-and-forget pre-fetch at middleware creation; first verify() awaits\n * the in-flight promise if it hasn't resolved. 60-minute TTL with\n * stale-while-revalidate background refresh.\n */\n\nexport interface WellKnownAgenticCommerce {\n registrationUrl: string;\n documentationUrl: string;\n verifyAccessUrl: string;\n /** 5.1.0: hosted AstraSync MCP bridge endpoint (absent on self-hosted backends). */\n mcpEndpoint?: string;\n /** 5.1.0: bridge connector-discovery doc (absent on self-hosted backends). */\n mcpDiscoveryUrl?: string;\n}\n\ninterface CacheEntry {\n data: WellKnownAgenticCommerce;\n fetchedAt: number;\n}\n\nconst CACHE_TTL_MS = 60 * 60 * 1000; // 60 minutes\n\nconst cache = new Map<string, CacheEntry>();\nconst inflight = new Map<string, Promise<WellKnownAgenticCommerce>>();\n\nfunction wellKnownUrl(apiBaseUrl: string): string {\n // apiBaseUrl is typically 'https://astrasync.ai/api' — strip the /api suffix\n // to get the platform root, then append /.well-known/agentic-commerce.\n const base = apiBaseUrl.replace(/\\/api\\/?$/, '');\n return `${base}/.well-known/agentic-commerce`;\n}\n\nasync function fetchWellKnown(apiBaseUrl: string): Promise<WellKnownAgenticCommerce> {\n const url = wellKnownUrl(apiBaseUrl);\n const response = await sdkFetch(url, {\n method: 'GET',\n headers: { Accept: 'application/json' },\n signal: AbortSignal.timeout(5000),\n });\n if (!response.ok) {\n throw new Error(\n `AstraSync platform must expose /.well-known/agentic-commerce; ` +\n `got ${response.status} from ${url}. SDK cannot initialise without it.`\n );\n }\n const data = (await response.json()) as Record<string, unknown>;\n if (!data.registrationUrl || !data.documentationUrl || !data.verifyAccessUrl) {\n throw new Error(\n `/.well-known/agentic-commerce response missing required fields ` +\n `(registrationUrl, documentationUrl, verifyAccessUrl).`\n );\n }\n return data as unknown as WellKnownAgenticCommerce;\n}\n\n/**\n * Start a background fetch. Returns the promise for callers that need\n * to await it (first verify() call).\n */\nexport function prefetchWellKnown(apiBaseUrl: string): Promise<WellKnownAgenticCommerce> {\n const existing = inflight.get(apiBaseUrl);\n if (existing) return existing;\n\n const promise = fetchWellKnown(apiBaseUrl)\n .then((data) => {\n cache.set(apiBaseUrl, { data, fetchedAt: Date.now() });\n inflight.delete(apiBaseUrl);\n return data;\n })\n .catch((err) => {\n inflight.delete(apiBaseUrl);\n throw err;\n });\n\n inflight.set(apiBaseUrl, promise);\n return promise;\n}\n\n/**\n * Get cached well-known URLs. If stale, triggers a background refresh\n * and returns stale data (stale-while-revalidate). If no cache exists,\n * awaits the in-flight fetch or starts a new one.\n */\nexport async function getWellKnownUrls(apiBaseUrl: string): Promise<WellKnownAgenticCommerce> {\n const entry = cache.get(apiBaseUrl);\n\n if (entry) {\n if (Date.now() - entry.fetchedAt > CACHE_TTL_MS) {\n // Stale — trigger background refresh, return stale data\n prefetchWellKnown(apiBaseUrl).catch(() => {\n // Background refresh failed — stale data remains until next request\n });\n }\n return entry.data;\n }\n\n // No cache — must await\n const pending = inflight.get(apiBaseUrl);\n if (pending) return pending;\n\n return prefetchWellKnown(apiBaseUrl);\n}\n\n/**\n * Synchronous cache read — returns cached URLs or undefined.\n * Never triggers a fetch. Used by verify() to avoid extra HTTP calls\n * in the hot path; adapters are responsible for prefetching.\n */\nexport function getCachedWellKnownUrls(apiBaseUrl: string): WellKnownAgenticCommerce | undefined {\n return cache.get(apiBaseUrl)?.data;\n}\n\n/** Reset cache — for testing only. */\nexport function _resetWellKnownCache(): void {\n cache.clear();\n inflight.clear();\n}\n","/**\n * AstraSync Universal Verification Gateway - Core Verification Logic\n *\n * This module handles the core verification logic, calling the AstraSync API\n * and processing the response into a standardized VerificationResult.\n */\n\nimport { sdkFetch } from './http';\nimport type {\n GatewayConfig,\n AgentCredentials,\n VerificationRequest,\n VerificationResult,\n VerifiedAgent,\n VerifiedDeveloper,\n VerifiedOrganization,\n GuidanceInfo,\n EnhancedVerificationResult,\n TokenGuidance,\n RuntimeChallengeResult,\n StepUpApprovalInfo,\n SettlementOutcomeInfo,\n MerchantSettlementToken,\n SettlementArtifact,\n AttemptReport,\n} from './types';\nimport { getTrustLevel } from './trust-levels';\nimport type { ObservedMetadata } from './metadata-capture';\nimport { SDK_VERSION } from './version';\nimport { getCachedWellKnownUrls, type WellKnownAgenticCommerce } from './well-known';\n\n/**\n * Default configuration values\n *\n * apiBaseUrl matches the OpenAPI authoritative server (https://astrasync.ai/api\n * for prod, https://staging.astrasync.ai/api for staging). Always include the\n * /api path prefix when overriding — registration / docs URLs are derived by\n * stripping it.\n */\nconst DEFAULT_CONFIG: Partial<GatewayConfig> = {\n apiBaseUrl: 'https://astrasync.ai/api',\n // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.\n // cacheTtl deliberately unset. When undefined, cacheResult applies the 60s\n // default; the caller's explicit value is honoured for cacheable results.\n // Denials and step-up escalations are NEVER cached (3.6.0) regardless of\n // cacheTtl. Set cacheTtl: 0 to disable caching entirely.\n debug: false,\n};\n\n/**\n * Init self-test state. Fires once per process on first verify() call to warn\n * if apiBaseUrl is pointing at the wrong host (e.g. a marketing site that\n * 200s with text/html instead of the API).\n */\nlet initCheckPerformed = false;\n\n/** Test-only: re-arm the one-time init self-check. */\nexport function _resetInitCheck(): void {\n initCheckPerformed = false;\n}\n\n/** One-shot guard for v2.3.0 deprecation warning. */\nlet deprecationWarningShown = false;\n\nasync function performInitCheck(\n apiBaseUrl: string,\n debug?: boolean,\n strictInit?: boolean,\n apiKey?: string\n): Promise<void> {\n initCheckPerformed = true;\n try {\n const probeUrl = `${apiBaseUrl}/agents/verify-access`;\n // HEAD mirrors GET semantics (running the full request pipeline without a\n // body) so the response carries the same content-type the marketing 404\n // would return. OPTIONS often gets short-circuited by CORS-preflight\n // handlers and returns no content-type, defeating the check.\n const response = await sdkFetch(probeUrl, { method: 'HEAD' });\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.startsWith('text/html')) {\n const message =\n `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). ` +\n `This usually means apiBaseUrl is pointing at a marketing site instead of the API. ` +\n `Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;\n // Audit F-A6-33: when strictInit is set, throw on misconfig instead\n // of warning + continuing. Recurring footgun per\n // `[[feedback_astrasync_api_url_canonical]]` — silent warn lets\n // misconfigured prod deploys ship with all verify-access calls\n // silently failing.\n if (strictInit) {\n throw new Error(`${message} (strictInit=true)`);\n }\n console.warn(`${message} Set disableInitChecks: true on GatewayConfig to silence.`);\n } else if (debug) {\n console.log(\n `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`\n );\n }\n\n // 4.0.0: key liveness probe. A dead API key otherwise surfaces only\n // per-request as inbound agents get turned away — the operator should\n // learn at deploy time. 404 = older backend without self-check: silent.\n if (apiKey) {\n const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n });\n if (selfCheck.status === 401) {\n const body = (await selfCheck.json().catch(() => ({}))) as {\n code?: string;\n message?: string;\n remediation?: { manageUrl?: string };\n };\n const message =\n `[VerificationGateway] the configured AstraSync API key was REJECTED at startup ` +\n `(${body.code ?? 'api_key_invalid'}: ${body.message ?? 'invalid key'}). Every inbound agent ` +\n `will be turned away until the key is rotated` +\n (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : '') +\n `.`;\n if (strictInit) {\n throw new Error(`${message} (strictInit=true)`);\n }\n console.error(message);\n } else if (selfCheck.ok) {\n const body = (await selfCheck.json().catch(() => ({}))) as {\n daysToExpiry?: number | null;\n };\n if (typeof body.daysToExpiry === 'number' && body.daysToExpiry <= 7) {\n console.warn(\n `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) — ` +\n `rotate it at Settings → Developer Tools before integrations start failing.`\n );\n } else if (debug) {\n console.log('[VerificationGateway] API key self-check passed');\n }\n }\n }\n } catch (err) {\n if (strictInit) {\n // strict mode propagates init failures so callers get a clear,\n // synchronous \"your config is broken\" signal at startup.\n throw err;\n }\n if (debug) {\n console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);\n }\n }\n}\n\n/**\n * Simple in-memory cache for verification results\n */\nconst verificationCache = new Map<string, { result: VerificationResult; expiresAt: number }>();\n\n/**\n * Generate cache key from the full request shape.\n *\n * Historically the key was credentials-only (`astraId-apiKey-jwt`),\n * which silently returned the cached result of a prior call even when the\n * subsequent call's purpose/action/counterparty/etc. differed. That was a\n * security gap — a warm cache could serve an allow verdict for a purpose the\n * agent hadn't actually been authorised for. Key now includes every field\n * that affects the backend verdict.\n *\n * MAINTAIN: when adding a field to VerificationRequest that affects the\n * backend verdict, add it to this key. Fields that don't affect verdict\n * (e.g. requestId, timestamps, sdkVersion) don't belong here — including\n * them would needlessly thrash the cache for repeated identical requests.\n *\n * 3.12.0 (Trust Record): `attemptId` and `considerationSet` are\n * deliberately EXCLUDED — like `callerMetadata.observedMetadata` they are\n * observational pass-through that never affects the verdict, and keying on\n * a per-attempt id would defeat verdict caching entirely. Cache hits get\n * their attemptId rewritten in verify() instead (never leak a prior\n * attempt's id from a cached result).\n */\nfunction getCacheKey(request: VerificationRequest, counterpartyId?: string): string {\n const c = request.credentials;\n return [\n c.astraId || '',\n c.apiKey || '',\n c.jwt || '',\n request.purpose || '',\n request.action || '',\n request.resourceType || '',\n request.resource || '',\n request.jurisdiction || '',\n request.transactionValue ?? '',\n request.currency || '',\n // SECURITY (cross-merchant cache leak): the merchant identity is sent via\n // `config.counterpartyId`, NOT on the request, so it was previously absent\n // from the key — two verifies for the SAME agent/purpose/action/value but\n // DIFFERENT merchants collided, and a grant at a permissive merchant (low\n // trust floor) was served for a stricter one. Same bug class as the\n // duration omission (F-A1-07). counterpartyId affects the backend verdict\n // (trust floor / per-route policy), so it MUST key the cache.\n counterpartyId || '',\n request.counterpartyUrl || '',\n request.counterpartyType || '',\n request.isSubAgentRequest ? '1' : '0',\n request.parentAgentId || '',\n request.subAgentDepth ?? '',\n // Audit F-A1-07: previously-missing dimensions that DO affect the\n // backend verdict. Without these, two requests with different\n // durations (e.g. 60s vs 86400s) collided on the same cache key and\n // the shorter-duration allow served the longer-duration request.\n request.durationRequired ?? '',\n request.invocationProtocol || '',\n request.enableRuntimeChallenge ? '1' : '0',\n // callerMetadata fields contribute to risk model; include the ones\n // backend reads. sourceIp/userAgent/forwardedFor change per-request\n // so their inclusion effectively forces a re-check for any varying\n // client (the right behavior — IP-driven anomaly scoring shouldn't\n // be cached across IPs).\n request.callerMetadata?.sourceIp || '',\n request.callerMetadata?.userAgent || '',\n request.callerMetadata?.forwardedFor || '',\n request.callerMetadata?.agentCardUrl || '',\n // UAT2 Bug B (5.4.1): the commerce phase and cart identity DO affect the\n // backend verdict — the confirm leg is the ONLY leg that may execute\n // first-party settlement. Without these, a confirm within the cache TTL of\n // its start_checkout quote was served the cached quote-leg grant (no\n // settlementOutcome) and never reached the backend. Same F-A1-07 bug class.\n request.commercePhase || '',\n request.checkoutSessionId || '',\n ].join('|');\n}\n\n/**\n * Check if cached result is still valid\n */\nfunction getCachedResult(\n request: VerificationRequest,\n counterpartyId?: string\n): VerificationResult | null {\n const key = getCacheKey(request, counterpartyId);\n const cached = verificationCache.get(key);\n\n if (cached && cached.expiresAt > Date.now()) {\n return cached.result;\n }\n\n if (cached) {\n verificationCache.delete(key);\n }\n\n return null;\n}\n\n/**\n * Cache a verification result.\n *\n * 3.6.0: uniform 60s default. The earlier step-up TTL split (300s for\n * step-up verdicts) is gone — step-up verdicts are no longer cached AT ALL\n * (see the write predicate in verify()): a cached step_up_required result\n * carries a pollUrl that goes stale (consumed/expired) and, worse, keeps\n * denying retries that the owner has already approved. When `configuredTtl`\n * is set (truthy positive number), it's honoured for cacheable results.\n */\nconst DEFAULT_CACHE_TTL_SECONDS = 60;\n\nfunction cacheResult(\n request: VerificationRequest,\n result: VerificationResult,\n configuredTtl: number | undefined,\n counterpartyId?: string\n): void {\n const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : DEFAULT_CACHE_TTL_SECONDS;\n const key = getCacheKey(request, counterpartyId);\n verificationCache.set(key, {\n result,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n}\n\n/**\n * Clear the verification cache\n */\nexport function clearCache(): void {\n verificationCache.clear();\n}\n\n/**\n * Extract agent credentials from various sources\n */\nexport function extractCredentials(\n headers: Record<string, string | string[] | undefined>,\n query?: Record<string, string | undefined>\n): AgentCredentials {\n const credentials: AgentCredentials = {};\n\n // Audit F-A1-12: ASTRA-ID shape validation. Accept only the canonical\n // pattern (ASTRA-/ASTRAE- prefix + 1-64 url-safe chars) to prevent CRLF\n // header injection or downstream interpolation surprises. Reject otherwise.\n const ASTRA_ID_PATTERN = /^ASTRAE?-[A-Za-z0-9_-]{1,64}$/;\n\n // Check for ASTRA-ID in headers (case-insensitive). Accepts the historical\n // X-Astra-Id name plus the X-Astra-AgentId / x-astra-agent-id alias the\n // partner asked for in #9a — both surface the same field.\n const astraIdHeader =\n headers['x-astra-id'] ||\n headers['X-Astra-Id'] ||\n headers['X-ASTRA-ID'] ||\n headers['x-astra-agentid'] ||\n headers['X-Astra-AgentId'] ||\n headers['x-astra-agent-id'] ||\n headers['X-Astra-Agent-Id'] ||\n headers['X-ASTRA-AGENT-ID'];\n if (astraIdHeader) {\n // Audit F-A1-11: guard array-confusion. If multiple X-Astra-Id headers\n // were sent (Express collapses to comma-joined string on most paths),\n // take only the first canonical-shaped one.\n const raw = Array.isArray(astraIdHeader)\n ? astraIdHeader[0]\n : typeof astraIdHeader === 'string'\n ? astraIdHeader\n : undefined;\n if (typeof raw === 'string' && ASTRA_ID_PATTERN.test(raw)) {\n credentials.astraId = raw;\n }\n }\n\n // Check for API key in headers\n const apiKeyHeader = headers['x-api-key'] || headers['X-Api-Key'] || headers['X-API-KEY'];\n if (apiKeyHeader) {\n credentials.apiKey = Array.isArray(apiKeyHeader) ? apiKeyHeader[0] : apiKeyHeader;\n }\n\n // Check Authorization header for Bearer token.\n // Audit F-A1-11: defensive type guard — Array.isArray gives a non-string,\n // and Express path quirks can produce undefined despite the truthy check.\n const authHeader = headers['authorization'] || headers['Authorization'];\n if (authHeader) {\n const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;\n if (typeof authValue === 'string') {\n credentials.authorizationHeader = authValue;\n if (authValue.startsWith('Bearer ')) {\n credentials.jwt = authValue.slice(7);\n }\n }\n }\n\n // Check query parameters as fallback\n if (query) {\n if (query.astraId && !credentials.astraId) {\n credentials.astraId = query.astraId;\n }\n if (query.apiKey && !credentials.apiKey) {\n credentials.apiKey = query.apiKey;\n }\n }\n\n return credentials;\n}\n\n/**\n * Check if credentials are present\n */\nexport function hasCredentials(credentials: AgentCredentials): boolean {\n return !!(credentials.astraId || credentials.apiKey || credentials.jwt);\n}\n\n/**\n * Source of a synthesised guidance response. The sources are split — the\n * `'no_credentials'` shape is the original (caller has no AstraSync\n * credentials, suggest registration). The `'api_error'` shape is for when\n * the verify-access HTTP call itself failed (5xx, network, etc.) — DON'T\n * tell a verified-but-currently-blocked partner to \"register your agent\".\n *\n * 4.0.0 adds `'merchant_misconfig'`: the backend rejected THIS INTEGRATION'S\n * own API key (401 api_key_revoked/expired/invalid). Neither the agent's\n * fault nor a platform outage — retrying won't help, and the inbound agent\n * deserves to know the site operator's integration is broken (the\n * gadget-emporium failure mode: a rotated key silently 401ing every\n * credentialed agent for days).\n */\ntype GuidanceSource = 'no_credentials' | 'api_error' | 'merchant_misconfig';\n\n/**\n * MCP-connector steering (5.1.0). Present only when the backend's well-known\n * doc advertises a hosted bridge. The copy must directly counter the observed\n * model refusal (\"go register manually on the dashboard\"): registration via\n * the connector is the agent's own next action, with the human approval built\n * into the flow.\n */\nfunction mcpGuidance(urls?: WellKnownAgenticCommerce): GuidanceInfo['mcp'] {\n if (!urls?.mcpEndpoint) return undefined;\n return {\n endpoint: urls.mcpEndpoint,\n discoveryUrl: urls.mcpDiscoveryUrl,\n message:\n 'If you are operating inside an MCP-capable host (Claude, ChatGPT, Cursor, or any MCP client), ' +\n 'add the AstraSync MCP connector instead of integrating these URLs by hand: registration through ' +\n 'the connector is KEYLESS and HUMAN-APPROVED — your human approves in an in-chat card, and you ' +\n 'never see, hold, or transmit an API key, password, or private key.',\n };\n}\n\n/**\n * Create guidance response for unverified agents or for API-error fallback.\n *\n * The source is split so the `register your agent` template\n * doesn't fire on transient backend failures. Also threads `correlationId`\n * through so adapter `onDenied` handlers can surface it on the merchant's\n * response body for log correlation.\n */\nfunction createGuidanceResponse(\n _config: GatewayConfig,\n reason?: string,\n options: {\n source?: GuidanceSource;\n correlationId?: string;\n /** 3.12.0 (Trust Record): server-echoed attempt handle, threaded like correlationId. */\n attemptId?: string;\n urls?: WellKnownAgenticCommerce;\n /** 4.0.0: backend-provided remediation URLs for the merchant (misconfig source). */\n remediation?: { docsUrl?: string; manageUrl?: string };\n } = {}\n): VerificationResult {\n const source = options.source ?? 'no_credentials';\n const isApiError = source === 'api_error';\n const isMisconfig = source === 'merchant_misconfig';\n const urls = options.urls;\n\n const guidance: GuidanceInfo = isMisconfig\n ? {\n message:\n \"This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). \" +\n 'Your identity and the AstraSync platform are fine — contact the site operator. Retrying will not help.',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? '',\n steps: [\n 'Report the failure to the site operator — their AstraSync API key needs rotating',\n 'Do not retry: the failure is deterministic until the operator updates their key',\n ],\n }\n : isApiError\n ? {\n message:\n 'Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n steps: [\n 'Retry the request with exponential backoff',\n 'If failures persist, share the correlationId with support',\n ],\n }\n : {\n message:\n 'This service verifies AI agents before granting access. Please register your agent with AstraSync.',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n steps: [\n // MCP steering leads when the hosted bridge is advertised — the\n // connector is the agent-actionable path (keyless, human-approved).\n ...(urls?.mcpEndpoint\n ? [\n `Fastest path (inside an MCP host): add the AstraSync MCP connector at ${urls.mcpEndpoint} — keyless, human-approved registration`,\n ]\n : []),\n 'Register for an AstraSync account',\n 'Create and register your agent',\n 'Add your ASTRA-ID to request headers',\n 'Retry your request',\n ],\n ...(mcpGuidance(urls) && { mcp: mcpGuidance(urls) }),\n };\n\n return {\n // Round-18 G4: createGuidanceResponse fires for unverified-agent path or\n // API-error fallback. Identity is not verified (no agent resolved);\n // policy is not evaluated (we never reached the gate).\n identityVerified: false,\n policyAllowed: false,\n guidance,\n denialReasons: reason ? [reason] : ['No valid agent credentials provided'],\n // Round-10 (#47, O5): on API-error fallback, surface a typed failure so\n // partners (and their custom onDenied handlers) can branch on\n // dimension. Without this, the synthesised stub was indistinguishable\n // from a real policy deny.\n failures: isMisconfig\n ? [\n {\n dimension: 'verify_access.merchant_misconfigured',\n message: reason ?? 'The integration API key was rejected by AstraSync',\n guidance: guidance.message,\n },\n ]\n : isApiError\n ? [\n {\n dimension: 'verify_access.api_error',\n message: reason ?? 'Verification temporarily unavailable',\n guidance: guidance.message,\n },\n ]\n : undefined,\n // 4.0.0: typed marker so adapters render the misconfig envelope (503 +\n // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.\n ...(isMisconfig && { misconfigured: true }),\n // 4.6.0: a transient api_error is retryable — mark it so consumers surface\n // \"temporarily unavailable, retry\" (recommendation 'error') instead of\n // coercing the absent recommendation to a policy 'deny'. Misconfig is\n // deterministic and intentionally NOT marked retryable.\n ...(isApiError && { retryable: true }),\n correlationId: options.correlationId,\n attemptId: options.attemptId,\n verifiedAt: new Date(),\n };\n}\n\n/**\n * Call the AstraSync verify-access API\n */\nasync function callVerifyAccessAPI(\n config: GatewayConfig,\n request: VerificationRequest\n): Promise<{\n success: boolean;\n access?: {\n allowed: boolean;\n reason?: string;\n /**\n * Aggregated denial failures (v2.9.8+). Empty / absent when allowed.\n * Each entry is `{ dimension, message, guidance? }` — see\n * `AccessFailure` for the contract.\n */\n failures?: Array<{ dimension: string; message: string; guidance?: string }>;\n requiresStepUp?: boolean;\n requiresApproval?: boolean;\n appliedPolicy?: {\n boundaryName: string;\n policyVersion: string;\n };\n counterparty?: {\n id: string;\n name: string;\n trustScoreRequirement: number;\n };\n };\n agent?: {\n kyaAgentId: string;\n astraId: string;\n name: string;\n trustScore: number;\n trustLevel: string;\n agentStatus: string;\n blockchainStatus: string;\n };\n developer?: {\n kyaOwnerId: string;\n fullName: string;\n email: string;\n identityVerified: boolean;\n trustScore: number;\n };\n organization?: {\n name: string;\n verified: boolean;\n trustScore: number;\n };\n /**\n * Structured explanation of the verification decision. Tells the merchant\n * WHY (id verified? challenge passed? request within PDLSS? trust score?)\n * without exposing thresholds, scope lists, or other-tenant counterparty\n * membership. Empty `attestations` unless the endpoint's access policy\n * declared `required_attestations`.\n */\n verificationContext?: {\n idVerified: boolean;\n runtimeChallenge: {\n status: 'passed' | 'skipped' | 'failed' | 'timeout' | 'not_supported';\n checkedAt: string | null;\n };\n pdlssCheck: {\n result: 'within' | 'exceeded' | 'denied' | 'not_evaluated';\n purpose: 'approved' | 'denied';\n scope: 'approved' | 'denied';\n };\n dynamicTrustScore: number;\n attestations: Array<{\n type: string;\n status: 'passed' | 'failed';\n /** LMAX-POC C1: underlying check timestamp for merchant freshness gates. */\n checkedAt: string;\n validUntil?: string;\n proofType: 'reference' | 'zkp';\n proof: string;\n }>;\n };\n error?: string;\n /**\n * 4.0.0: the backend 401'd this integration's OWN API key (revoked /\n * expired / invalid) — deterministic merchant-side misconfig, not a\n * transient failure. `misconfigCode` carries the backend's api_key_* code\n * and `remediation` its operator-facing URLs when present.\n */\n misconfig?: boolean;\n misconfigCode?: string;\n remediation?: { docsUrl?: string; manageUrl?: string };\n /**\n * When the verify-access server response carries a\n * correlationId on an error envelope, propagate it so the SDK can thread\n * it through createGuidanceResponse → adapter onDenied → merchant body.\n */\n correlationId?: string;\n /**\n * 3.12.0 (Trust Record): the server echoes the attempt-chain\n * handle top-level on every response branch (error envelopes included).\n */\n attemptId?: string;\n}> {\n const { credentials, ...requestData } = request;\n\n // Build the request body. agentId is omitted when not provided so the\n // server treats it as an anonymous canonical-flow call (Branch A/B/C).\n const body: Record<string, unknown> = {\n ...(credentials.astraId && { agentId: credentials.astraId }),\n ...(requestData.purpose && { purpose: requestData.purpose }),\n };\n\n // Add optional fields\n if (requestData.action) body.action = requestData.action;\n if (requestData.resourceType) body.resourceType = requestData.resourceType;\n if (requestData.resource) body.resource = requestData.resource;\n if (requestData.jurisdiction) body.jurisdiction = requestData.jurisdiction;\n if (requestData.transactionValue) body.transactionValue = requestData.transactionValue;\n if (requestData.currency) body.currency = requestData.currency;\n if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;\n if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;\n if (requestData.subAgentDepth !== undefined) body.subAgentDepth = requestData.subAgentDepth;\n // Handshake Protocol v10 additions\n if (requestData.enableRuntimeChallenge)\n body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;\n if (requestData.createSession) body.createSession = requestData.createSession;\n if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;\n if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;\n if (requestData.counterpartyUrl) body.counterpartyUrl = requestData.counterpartyUrl;\n if (config.counterpartyId) body.counterpartyId = config.counterpartyId;\n if (requestData.runtimeChallengeOptions)\n body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;\n // Round-12 (F19): transport-vs-intent separation. MCP middleware sets\n // this to 'mcp'; non-MCP callers leave it unset.\n if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;\n // 5.3.0 (astra-pay): checkout-leg discriminator — first-party settlement\n // fires only on 'confirm'; absent keeps pre-phase server behavior.\n if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;\n // Per-cart idempotency key (checkout session id) forwarded on the confirm\n // leg so concurrent confirms for one cart charge at most once.\n if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;\n // Order-plane cart lines (receipts + fulfillment email) — informational.\n if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;\n // 3.9.0 (§33.5 #1): raw commerce artifacts forwarded verbatim — the\n // backend's Step 0.5 pipeline does the cryptographic verification\n // server-side (adapters forward, never verify locally).\n if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;\n // 3.12.0 (Trust Record, §33.5 #3): attempt-chain handle + consideration set,\n // forwarded skip-when-undefined (observedMetadata precedent) — pure\n // observational pass-through; the server echoes attemptId on every branch.\n if (requestData.attemptId) body.attemptId = requestData.attemptId;\n if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;\n\n // Round-13 (F14 closure / R13-7): emit the SDK package version on every\n // verify-access body so the backend can auto-populate `kya_counterparty.\n // sdk_version` for the calling endpoint. Body field (not User-Agent\n // header) is the canonical channel — works in Node, browser, behind\n // Cloudflare, and across SDK bundlers without environment-specific\n // header gymnastics. Backend's `validation.ts:verifyAccessSchema`\n // accepts the semver regex; the auto-pop logic is forward-only.\n body.sdkVersion = SDK_VERSION;\n\n // Forward caller metadata when present. Merges the legacy top-level\n // clientIp/userAgent into the nested block for backward compatibility.\n if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {\n const meta = {\n ...(requestData.clientIp && { sourceIp: requestData.clientIp }),\n ...(requestData.userAgent && { userAgent: requestData.userAgent }),\n ...requestData.callerMetadata,\n };\n if (Object.keys(meta).length > 0) body.callerMetadata = meta;\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...config.customHeaders,\n };\n\n // verify-access requires authentication. Use ONLY the merchant's\n // configured apiKey for outbound auth. Previously the caller's inbound\n // Authorization header took priority, which pivoted the verify-access\n // call to the caller's identity — letting an attacker who supplied\n // their own Authorization header trigger verify-access calls under\n // THEIR account and observe the resulting verdicts for arbitrary\n // lookups they triggered via the merchant. Audit F-A1-10.\n //\n // The caller-supplied JWT (if any) is already extracted to\n // credentials.jwt and travels in the verify-access request body so\n // backend can evaluate it as the agent's identity claim — separate from\n // the merchant-attribution auth on the outbound HTTPS call.\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n // Legacy header kept for compatibility with any middleware that reads it directly.\n headers['X-API-Key'] = config.apiKey;\n }\n\n try {\n // 4.0.0: hard timeout — without one, a backend that accepts the\n // connection but never answers hangs the merchant's middleware and every\n // inbound agent request behind it (observed live on a partner property).\n // Timeouts land on the catch path below → api_error (fail-closed),\n // NOT misconfig. The edge adapter races its own tighter withBudget.\n const response = await sdkFetch(`${config.apiBaseUrl}/agents/verify-access`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 10_000),\n });\n\n const data = await response.json();\n\n // v2.3.8 (defect #29): treat 410 Gone as a deterministic deactivated-endpoint\n // signal. Older SDKs may treat any non-2xx as transient and retry; v2.3.8+\n // surfaces it as a structured denial with `reason: 'endpoint_deactivated'`\n // so callers can distinguish \"endpoint gone\" from \"endpoint denied this\".\n if (response.status === 410) {\n return {\n success: true,\n // 3.12.0 (Trust Record): keep the server-echoed attempt handle even on\n // the synthesised 410 deny shape (echoed on every branch).\n attemptId: typeof data?.attemptId === 'string' ? data.attemptId : undefined,\n access: {\n allowed: false,\n reason: 'endpoint_deactivated',\n failures: [\n {\n dimension: 'endpoint.deactivated',\n message:\n typeof data?.message === 'string' ? data.message : 'Endpoint has been deactivated',\n guidance:\n typeof data?.guidance === 'string'\n ? data.guidance\n : 'Reactivate via POST /api/endpoints/{id}/reactivate, or update the URL on the calling agent.',\n },\n ],\n },\n };\n }\n\n if (!response.ok) {\n // 4.0.0: a 401 from verify-access can ONLY mean the backend rejected\n // THIS INTEGRATION'S own API key — agent denials come back as 200 with\n // access.allowed=false. Surface it as merchant-misconfig, not a\n // transient api_error: it is deterministic until the operator rotates\n // the key, and the \"retry with backoff\" template actively misleads.\n // Backends ≥ this round also send code: api_key_* + remediation URLs.\n if (response.status === 401) {\n return {\n success: false,\n error: data.message || data.error || 'Integration API key rejected',\n misconfig: true,\n misconfigCode: typeof data?.code === 'string' ? data.code : undefined,\n remediation:\n data?.remediation && typeof data.remediation === 'object'\n ? (data.remediation as { docsUrl?: string; manageUrl?: string })\n : undefined,\n correlationId: typeof data?.correlationId === 'string' ? data.correlationId : undefined,\n attemptId: typeof data?.attemptId === 'string' ? data.attemptId : undefined,\n };\n }\n // Round-10 (#47, O5): propagate correlationId on the error path too if\n // the server happened to include one (some 5xx error envelopes carry\n // it). Lets the SDK pass it through to the adapter onDenied handler.\n return {\n success: false,\n error: data.message || data.error || `API returned ${response.status}`,\n correlationId: typeof data?.correlationId === 'string' ? data.correlationId : undefined,\n attemptId: typeof data?.attemptId === 'string' ? data.attemptId : undefined,\n };\n }\n\n return data;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n success: false,\n error: `Failed to call verify-access API: ${message}`,\n };\n }\n}\n\n/**\n * Options for a single verify() call (as opposed to GatewayConfig, which is\n * per-gateway). Mirrors the Java SDK's `verify(request, bypassCache)`.\n */\nexport interface VerifyOptions {\n /**\n * Skip the cache READ for this call so the request is guaranteed to reach\n * the backend (the result is still written to the cache if cacheable).\n * Used by the step-up hold-and-poll retry: the re-verify after an approval\n * must hit the server to redeem the single-use approval.\n */\n bypassCache?: boolean;\n}\n\n/**\n * Main verification function\n */\nexport async function verify(\n config: GatewayConfig,\n request: VerificationRequest,\n options?: VerifyOptions\n): Promise<VerificationResult> {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n // v2.5.0: read well-known URLs from cache (prefetched by adapter at middleware creation).\n // Synchronous — never triggers a fetch. If cache is empty, guidance URLs are empty strings.\n const urls = mergedConfig.apiBaseUrl\n ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl)\n : undefined;\n\n // One-time init self-test — fire-and-forget by default, never blocks verify().\n // Audit F-A6-33: when GatewayConfig.strictInit is set, the init promise is\n // awaited and any failure throws synchronously so callers learn about\n // misconfigured apiBaseUrl on the first verify() call rather than silently\n // running with broken auth.\n if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {\n if (mergedConfig.strictInit) {\n await performInitCheck(\n mergedConfig.apiBaseUrl,\n mergedConfig.debug,\n true,\n mergedConfig.apiKey\n );\n } else {\n void performInitCheck(\n mergedConfig.apiBaseUrl,\n mergedConfig.debug,\n false,\n mergedConfig.apiKey\n );\n }\n }\n\n // Deprecation warning for v2.3.0 removed config fields. Fires once per process.\n if (\n !deprecationWarningShown &&\n (config.minTrustScore !== undefined || config.minTrustScoreForFull !== undefined)\n ) {\n deprecationWarningShown = true;\n console.warn(\n '[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 ' +\n 'and have no effect. Server is now the single source of truth for access decisions ' +\n '(verified ID + runtime challenge + PDLSS + trust score). To gate access ' +\n \"to an endpoint, configure the endpoint's trust_score_requirement server-side.\"\n );\n }\n\n // v2.3.0: anonymous traffic no longer short-circuits here. We forward the\n // request to the server with no agentId; the server applies the endpoint's\n // unverifiedAgentPolicy and returns advisory. createGuidanceResponse remains\n // as the offline fallback if the API itself fails (handled below).\n\n // Check cache first. Caching on unless caller explicitly sets cacheTtl: 0\n // to disable. Undefined falls through to the 60s default at cacheResult\n // write time. options.bypassCache skips the read only (hold-and-poll retry\n // must reach the backend to redeem its approval).\n if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {\n const cached = getCachedResult(request, mergedConfig.counterpartyId);\n if (cached) {\n if (mergedConfig.debug) {\n console.log('[VerificationGateway] Returning cached result');\n }\n // 3.12.0 (Trust Record, §33.5 #3): attemptId is excluded from the cache\n // key, so the stored result may carry a PRIOR attempt's id. Overwrite it\n // with this request's own attemptId — or drop it when this request has\n // none — a cached verdict must never leak another attempt's handle.\n // Shallow clone: never mutate the stored entry (a concurrent holder of\n // the same cached object may still be reading it).\n const hit: VerificationResult = { ...cached };\n if (request.attemptId) {\n hit.attemptId = request.attemptId;\n } else {\n delete hit.attemptId;\n }\n return hit;\n }\n }\n\n // Inject counterparty info from config if not already set in request\n const enrichedRequest = { ...request };\n if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {\n enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;\n }\n if (!enrichedRequest.counterpartyType && mergedConfig.counterpartyType) {\n enrichedRequest.counterpartyType = mergedConfig.counterpartyType;\n }\n\n // Call the API\n if (mergedConfig.debug) {\n console.log('[VerificationGateway] Calling verify-access API');\n }\n\n const apiResponse = await callVerifyAccessAPI(mergedConfig, enrichedRequest);\n\n // 3.6.0: the server emits a top-level denialReasons array on every deny\n // path (same strings as the failure messages). Non-empty → authoritative;\n // absent/empty → fall back to the client-side reconstructions below.\n const rawServerDenialReasons = (apiResponse as Record<string, unknown>).denialReasons;\n const serverDenialReasons =\n Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0\n ? (rawServerDenialReasons as string[])\n : undefined;\n\n // Handle API errors\n if (!apiResponse.success) {\n // Round-10 (#47, O5): distinguish API errors from missing-credentials.\n // The previous default tagged any failure with the \"register your\n // agent\" template, which is misleading to a verified partner whose\n // verify-access call hit a 500. The `api_error` source surfaces a\n // typed `verify_access.api_error` failure entry instead.\n // 4.0.0: a rejected merchant key gets its own source — deterministic\n // misconfig must not wear the \"temporarily unavailable, retry\" template.\n return createGuidanceResponse(mergedConfig, apiResponse.error, {\n source: apiResponse.misconfig ? 'merchant_misconfig' : 'api_error',\n correlationId: (apiResponse as { correlationId?: string }).correlationId,\n attemptId: (apiResponse as { attemptId?: string }).attemptId,\n remediation: apiResponse.remediation,\n urls,\n });\n }\n\n // Check access result\n if (!apiResponse.access?.allowed) {\n // v2.9.8 (defect M1): aggregated failures across every gate that\n // denied. Surface them on the result so the integrator can see every\n // blocker in one go instead of the previous fail-fast cascade.\n const aggregatedFailures = (apiResponse.access as Record<string, unknown> | undefined)\n ?.failures as Array<{ dimension: string; message: string; guidance?: string }> | undefined;\n // Round-18 G4: backend denied access (PDLSS or other gate); identity status\n // depends on whether the backend resolved the caller. Read from\n // verificationContext.idVerified; default false if absent (anonymous or\n // identity-fail paths land here too). policyAllowed is false by definition\n // in this branch (apiResponse.access.allowed === false).\n const idVerifiedFromBackend =\n (apiResponse.verificationContext as { idVerified?: boolean } | undefined)?.idVerified ===\n true;\n const result: EnhancedVerificationResult = {\n identityVerified: idVerifiedFromBackend,\n policyAllowed: false,\n // 3.6.0: the server now emits top-level denialReasons on every deny\n // path — prefer it verbatim; the failure-message reconstruction remains\n // as the fallback for older backends.\n denialReasons:\n serverDenialReasons ??\n (aggregatedFailures && aggregatedFailures.length > 0\n ? aggregatedFailures.map((f) => f.message)\n : apiResponse.access?.reason\n ? [apiResponse.access.reason]\n : ['Access denied']),\n failures: aggregatedFailures,\n requiresStepUp: apiResponse.access?.requiresStepUp,\n requiresApproval: apiResponse.access?.requiresApproval,\n guidance: {\n message: apiResponse.access?.reason || 'Access denied by PDLSS policy',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n // 5.1.0: anonymous callers land on this branch — steer MCP-hosted\n // agents to the connector (this is what the edge deny body surfaces).\n ...(mcpGuidance(urls) && { mcp: mcpGuidance(urls) }),\n },\n verifiedAt: new Date(),\n // Extract sessionId so decisions can be recorded for denials too\n sessionId: (apiResponse as Record<string, unknown>).sessionId as string | undefined,\n // Anonymous traffic has no session → correlationId is the per-attempt\n // linking key (the sessionId-equivalent for anonymous callers).\n correlationId: (apiResponse as Record<string, unknown>).correlationId as string | undefined,\n // 3.12.0 (Trust Record): server echoes the attempt-chain handle on\n // every branch — denials included (the funnel outlives one deny).\n attemptId: (apiResponse as Record<string, unknown>).attemptId as string | undefined,\n recommendation: (apiResponse as Record<string, unknown>)\n .recommendation as EnhancedVerificationResult['recommendation'],\n recommendationReasons: (apiResponse as Record<string, unknown>).recommendationReasons as\n | string[]\n | undefined,\n stepUpApproval: (apiResponse as Record<string, unknown>).stepUpApproval as\n | StepUpApprovalInfo\n | undefined,\n settlement: (apiResponse as Record<string, unknown>).settlement as\n | SettlementArtifact\n | undefined,\n settlementOutcome: (apiResponse as Record<string, unknown>).settlementOutcome as\n | SettlementOutcomeInfo\n | undefined,\n // 5.5.0 self-settlement: merchant-only material — passes through to the\n // MERCHANT caller only (bridge callers strip it before the agent plane).\n settlementToken: (apiResponse as Record<string, unknown>).settlementToken as\n | MerchantSettlementToken\n | undefined,\n };\n\n return result;\n }\n\n // Build successful result\n const agent: VerifiedAgent | undefined = apiResponse.agent\n ? {\n astraId: apiResponse.agent.astraId,\n name: apiResponse.agent.name,\n trustScore: apiResponse.agent.trustScore,\n trustLevel: getTrustLevel(apiResponse.agent.trustScore),\n blockchainVerified: apiResponse.agent.blockchainStatus === 'verified',\n status: apiResponse.agent.agentStatus as VerifiedAgent['status'],\n }\n : undefined;\n\n const developer: VerifiedDeveloper | undefined = apiResponse.developer\n ? {\n astradId: apiResponse.developer.kyaOwnerId,\n name: apiResponse.developer.fullName,\n trustScore: apiResponse.developer.trustScore || 0,\n verified: apiResponse.developer.identityVerified,\n }\n : undefined;\n\n const organization: VerifiedOrganization | undefined = apiResponse.organization\n ? {\n name: apiResponse.organization.name,\n verified: apiResponse.organization.verified,\n trustScore: apiResponse.organization.trustScore,\n }\n : undefined;\n\n // Verification context — structured \"why\" the merchant gets in v2.2.4+.\n // Carries appliedPolicy (no UUIDs), pdlssCheck summary, dynamic trust score,\n // and policy-driven attestations. Replaces the old over-sharing `pdlss` block.\n const verificationContext = apiResponse.verificationContext;\n\n const result: EnhancedVerificationResult = {\n // 4.5.0 (probe F1): read idVerified from verificationContext with the\n // SAME absent⇒false default as the deny branch. The previous `!== false`\n // default manufactured `identityVerified: true` for anonymous\n // allow_full/allow_partial/audit responses (which allow access but omit\n // verificationContext entirely) — the \"anonymous caller labelled\n // verified\" defect. Every authenticated success response has carried\n // `verificationContext.idVerified: true` since v2.2.4, so a truth claim\n // this load-bearing must never be defaulted on.\n identityVerified:\n (apiResponse.verificationContext as { idVerified?: boolean } | undefined)?.idVerified ===\n true,\n policyAllowed: true,\n agent,\n developer,\n organization,\n appliedPolicy: apiResponse.access?.appliedPolicy,\n verificationContext,\n requiresStepUp: apiResponse.access?.requiresStepUp,\n requiresApproval: apiResponse.access?.requiresApproval,\n verifiedAt: new Date(),\n cacheTtl: mergedConfig.cacheTtl,\n // Handshake Protocol v10 enhanced fields (present when backend returns them)\n sessionId: (apiResponse as Record<string, unknown>).sessionId as string | undefined,\n // v2.3.10 (defect #34, round-4): anonymous responses surface correlationId\n // (no session row exists for unverified callers).\n correlationId: (apiResponse as Record<string, unknown>).correlationId as string | undefined,\n // 3.12.0 (Trust Record): server-echoed attempt-chain handle.\n attemptId: (apiResponse as Record<string, unknown>).attemptId as string | undefined,\n runtimeChallenge: (apiResponse as Record<string, unknown>).runtimeChallenge as\n | RuntimeChallengeResult\n | undefined,\n tokenGuidance: (apiResponse as Record<string, unknown>).tokenGuidance as\n | TokenGuidance\n | undefined,\n recommendation: (apiResponse as Record<string, unknown>)\n .recommendation as EnhancedVerificationResult['recommendation'],\n recommendationReasons: (apiResponse as Record<string, unknown>).recommendationReasons as\n | string[]\n | undefined,\n warningHeader: (apiResponse as Record<string, unknown>).warningHeader as\n | { name: string; value: string }\n | undefined,\n stepUpApproval: (apiResponse as Record<string, unknown>).stepUpApproval as\n | StepUpApprovalInfo\n | undefined,\n settlement: (apiResponse as Record<string, unknown>).settlement as\n | SettlementArtifact\n | undefined,\n settlementOutcome: (apiResponse as Record<string, unknown>).settlementOutcome as\n | SettlementOutcomeInfo\n | undefined,\n settlementToken: (apiResponse as Record<string, unknown>).settlementToken as\n | MerchantSettlementToken\n | undefined,\n };\n\n // Enforce AstraSync recommendation\n if (result.recommendation === 'deny') {\n // Round-18 G4: recommendation-driven deny lands on the success-path\n // construction (identity was resolved). Flip policy only — identity stays\n // verified — so adapters return 403 (re-auth won't help; the policy\n // decision is the blocker).\n result.policyAllowed = false;\n // 3.6.0: server-sent top-level denialReasons wins; recommendationReasons\n // reconstruction is the fallback for older backends.\n result.denialReasons = serverDenialReasons ??\n result.recommendationReasons ?? ['Access denied by AstraSync recommendation'];\n result.guidance = result.runtimeChallenge\n ? {\n message: `Verification failed: ${result.runtimeChallenge.reason || 'runtime challenge failed'}`,\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n }\n : {\n message: result.recommendationReasons?.[0] || 'Access denied by AstraSync recommendation',\n registrationUrl: urls?.registrationUrl ?? '',\n documentationUrl: urls?.documentationUrl ?? '',\n };\n } else if (result.recommendation === 'step_up_required') {\n // The escalation signal rides on `requiresStepUp` / `stepUpApproval`, not\n // on any masquerade of the (now-removed) access band.\n result.requiresStepUp = true;\n result.denialReasons = serverDenialReasons ??\n result.recommendationReasons ?? ['Step-up verification required'];\n }\n\n // Cache the result. Never cache denials (agent may fix challenge endpoint\n // and retry) NOR step-up escalations (3.6.0 — the same bug the Java SDK\n // had: a cached step_up_required verdict keeps denying retries the owner\n // has already approved, and its pollUrl goes stale once consumed/expired).\n // Escalations stay uncached even when the caller pins an explicit cacheTtl.\n const escalates =\n result.requiresStepUp === true ||\n result.requiresApproval === true ||\n result.recommendation === 'step_up_required';\n if (mergedConfig.cacheTtl !== 0 && result.recommendation !== 'deny' && !escalates) {\n cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);\n }\n\n return result;\n}\n\n/**\n * Record a counterparty's grant/deny decision for a verification session.\n * Fire-and-forget — errors are silently swallowed.\n */\nexport async function recordDecision(\n config: GatewayConfig,\n sessionId: string,\n decision: 'granted' | 'denied',\n reason?: string\n): Promise<void> {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n\n await sdkFetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ decision, reason }),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Report post-hoc consideration/outcome data for an attempt chain (Trust\n * Record). Use when the signal never reached verify-access: a\n * catalog served from a local cache, a transport-side deny (sku not found,\n * over budget), or a terminal outcome (settled / blocked on step-up).\n * Authenticated with the same credentials as verify(); the backend responds\n * 202 and folds the data into the attempt chain keyed by `attemptId`.\n *\n * Fire-and-forget — errors are silently swallowed, never throws.\n */\nexport async function reportAttempt(config: GatewayConfig, report: AttemptReport): Promise<void> {\n const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl!;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n\n // counterpartyId resolution mirrors reportUnregisteredAttempt: an explicit\n // report value wins; otherwise attribute to the configured endpoint.\n const body = {\n ...report,\n ...(!report.counterpartyId &&\n config.counterpartyId && { counterpartyId: config.counterpartyId }),\n };\n\n await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Fetch the per-route policy for an endpoint from the AstraSync backend.\n * v2.9.7 moved policy authority into the dashboard — the SDK no longer\n * accepts `routes` from merchant-side source code, it fetches them from\n * here on init (and refreshes periodically).\n *\n * Returns `null` when the request fails for any reason — the caller decides\n * how to fall back (the middleware allows-all when no policy is loaded so\n * a misconfigured init doesn't take down the merchant's API).\n */\nexport async function fetchRoutes(\n config: GatewayConfig,\n counterpartyId: string\n): Promise<RouteAccessConfigShape[] | null> {\n if (!counterpartyId) return null;\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n try {\n const response = await sdkFetch(\n `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,\n { method: 'GET', headers }\n );\n if (!response.ok) return null;\n const body = (await response.json()) as { data?: { routes?: RouteAccessConfigShape[] } };\n return body.data?.routes ?? [];\n } catch {\n return null;\n }\n}\n\n/**\n * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the\n * server's `EndpointRoute` type and the SDK's `RouteAccessConfig` — same\n * JSON moves between server and SDK unchanged.\n */\nexport interface RouteAccessConfigShape {\n pattern: string;\n method: string;\n /** Pass through unenforced (observe). Replaces `minAccessLevel: 'none'`. */\n observe?: boolean;\n minTrustScore?: number;\n requiredPurposes?: string[];\n allowedPurposes?: string[];\n allowedJurisdictions?: string[];\n maxDuration?: number;\n maxTransactionValue?: number;\n requirePurpose?: boolean;\n /** Send-mapping — see RouteAccessConfig in types.ts. */\n purpose?: string;\n action?: string;\n}\n\n/**\n * Verify an agent AND automatically record the grant/deny decision.\n *\n * This is the recommended entry point for counterparties that call verify()\n * directly (e.g. MCP servers) rather than using createMiddleware().\n * It adds createSession: true, then fire-and-forgets the decision.\n */\nexport async function verifyAndRecord(\n config: GatewayConfig,\n request: VerificationRequest,\n options?: VerifyOptions\n): Promise<VerificationResult> {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n const result = await verify(mergedConfig, { ...request, createSession: true }, options);\n const sessionId = (result as EnhancedVerificationResult).sessionId;\n\n if (sessionId) {\n // Round-18 G4: a session is \"granted\" only if identity verified AND\n // policy allowed; either failing is a deny.\n if (result.identityVerified && result.policyAllowed) {\n recordDecision(mergedConfig, sessionId, 'granted').catch(() => {});\n } else {\n recordDecision(mergedConfig, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n }\n\n return result;\n}\n\n/**\n * Report an unregistered agent attempt (no AstraSync credentials).\n * Called by SDK adapters when an agent is redirected to /docs/agent-access.\n * Fire-and-forget — errors are silently swallowed.\n */\nexport async function reportUnregisteredAttempt(\n config: GatewayConfig,\n data: {\n /**\n * 3.6.0: optional — the backend attributes by counterpartyId first (sent\n * from config below) and requires at least ONE of counterpartyId/URL.\n * A null/undefined URL is omitted from the body, not sent as null.\n */\n counterpartyUrl?: string;\n counterpartyType?: string;\n sourceIp?: string;\n userAgent?: string;\n requestPath?: string;\n requestMethod?: string;\n /**\n * 3.9.0 — edge-adapter evidence fields, persisted into the\n * event's eventData by the backend: `protocol` = detected transport/\n * credential protocol; `evidence` = light crypto-free detection detail.\n */\n protocol?: string;\n evidence?: Record<string, unknown>;\n /**\n * Maximal metadata capture — the full sanitised metadata for an\n * unregistered caller (every signal legitimately visible on the wire).\n * Persisted into eventData; feeds platform attribution and (via\n * correlationId) registration auto-fill. Fire-and-forget, so free.\n */\n observedMetadata?: ObservedMetadata;\n }\n): Promise<void> {\n const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl!;\n\n const { counterpartyUrl, ...rest } = data;\n const body = {\n ...rest,\n ...(counterpartyUrl && { counterpartyUrl }),\n ...(config.counterpartyId && { counterpartyId: config.counterpartyId }),\n };\n\n await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Report a counterparty-side PDLSS pre-check failure.\n * Called by SDK adapters when the agent's requested PDLSS exceeds\n * counterparty-defined maximums BEFORE calling verify-access.\n * Fire-and-forget — errors are silently swallowed.\n */\nexport async function reportCounterpartyPreCheckFailure(\n config: GatewayConfig,\n data: {\n agentId: string;\n counterpartyUrl: string;\n counterpartyType?: string;\n failures: Array<{\n field: string;\n requested: string | number;\n limit: string | number | string[];\n message: string;\n }>;\n requestPath?: string;\n requestMethod?: string;\n }\n): Promise<void> {\n const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl!;\n\n await sdkFetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(data),\n }).catch(() => {\n /* fire-and-forget */\n });\n}\n\n/**\n * Quick verification — checks credentials and policy in one call.\n *\n * The return shape mirrors `VerificationResult`'s split — partners\n * writing custom handlers around `quickVerify` get the same identity/policy\n * distinction as those calling `verify()` directly. Map to HTTP status the\n * same way: `!identityVerified` → 401; `identityVerified && !policyAllowed`\n * → 403.\n */\nexport async function quickVerify(\n config: GatewayConfig,\n credentials: AgentCredentials\n): Promise<{\n identityVerified: boolean;\n policyAllowed: boolean;\n reason?: string;\n}> {\n const result = await verify(config, {\n credentials,\n purpose: 'verification',\n });\n\n return {\n identityVerified: result.identityVerified,\n policyAllowed: result.policyAllowed,\n reason: result.denialReasons?.[0],\n };\n}\n","/**\n * Step-up hold-and-poll (3.6.0) — the synchronous half of the MFA-style gate,\n * mirroring the Java SDK's `awaitStepUpApproval` / `pollStepUpStatus`.\n *\n * A verify() that comes back step_up_required carries a `stepUpApproval`\n * handle: `{ approvalId, pollUrl, expiresAt }`. The adapter HOLDS the original\n * request, polls the approval status, and on 'approved' re-verifies the same\n * request once (cache-bypassed) so the backend redeems the single-use approval\n * and returns a grant. Any other terminal outcome falls into the adapter's\n * normal fail-closed deny path.\n *\n * The poll endpoint is deliberately unauthenticated (it sits above the\n * backend router's `authenticate` middleware): the unguessable UUIDv4\n * approvalId is the capability token, and the route is rate-limited\n * (60/min/IP). No Authorization header is sent.\n */\n\nimport { sdkFetch } from '../http';\nimport { GatewayConfig, StepUpApprovalInfo, StepUpApprovalStatus, StepUpOutcome } from '../types';\n\nconst DEFAULT_POLL_INTERVAL_MS = 3000;\nconst MIN_POLL_INTERVAL_MS = 250;\nconst FALLBACK_MAX_WAIT_MS = 5 * 60 * 1000;\nconst EXPIRY_GRACE_MS = 5000;\nconst POLL_REQUEST_TIMEOUT_MS = 10_000;\n\n/** Resolve the absolute poll URL. pollUrl is server-relative\n * (`/api/step-up-approvals/poll/:id`), so join it to apiBaseUrl minus its\n * `/api` suffix (the origin) — same idiom as well-known.ts. Absolute URLs\n * pass through untouched. */\nfunction resolvePollUrl(config: GatewayConfig, pollUrl: string): string {\n if (pollUrl.startsWith('http')) return pollUrl;\n const origin = (config.apiBaseUrl ?? '').replace(/\\/api\\/?$/, '');\n return origin + pollUrl;\n}\n\n/**\n * One GET of the approval's poll endpoint. Returns the status string, or\n * null on any error / non-2xx / unparsable body — the hold loop treats null\n * as transient and just polls again.\n */\nexport async function pollStepUpStatus(\n config: GatewayConfig,\n approval: StepUpApprovalInfo\n): Promise<StepUpApprovalStatus | null> {\n if (!approval.pollUrl) return null;\n try {\n const res = await sdkFetch(resolvePollUrl(config, approval.pollUrl), {\n method: 'GET',\n signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS),\n });\n if (!res.ok) return null;\n const body = (await res.json()) as Record<string, unknown>;\n // Envelope shape: { success, data: { status, resolvedAt } } — a flat\n // `status` read hangs every hold (live-UAT catch). Envelope-first with a\n // flat fallback for forward compatibility, exactly like the Java SDK.\n const data = body?.data;\n const status =\n data && typeof data === 'object' ? (data as Record<string, unknown>).status : body?.status;\n return typeof status === 'string' ? (status as StepUpApprovalStatus) : null;\n } catch {\n return null; // transient poll failure — the loop just polls again\n }\n}\n\nfunction resolveDeadline(config: GatewayConfig, approval: StepUpApprovalInfo): number {\n const now = Date.now();\n const maxWait = config.stepUpMaxWaitMs ?? 0;\n if (maxWait > 0) return now + maxWait;\n // stepUpMaxWaitMs === 0: hold until the approval itself expires (+ a small\n // grace so an approval landing at the buzzer still resolves on the next\n // poll). Missing/unparsable expiresAt → fixed 5-min fallback (Java parity).\n if (approval.expiresAt) {\n const expiry = Date.parse(approval.expiresAt);\n if (!Number.isNaN(expiry)) return Math.max(now, expiry) + EXPIRY_GRACE_MS;\n }\n return now + FALLBACK_MAX_WAIT_MS;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Block until a pending step-up approval reaches a terminal state or the wait\n * budget runs out. Returns the terminal status, or 'timeout'.\n *\n * Unknown non-pending statuses (a future backend state) still terminate the\n * hold — they are returned as-is and land in the deny path, which is the safe\n * reading of \"not approved\".\n */\nexport async function awaitStepUpApproval(\n config: GatewayConfig,\n approval: StepUpApprovalInfo\n): Promise<StepUpOutcome> {\n const deadline = resolveDeadline(config, approval);\n const pollInterval = Math.max(\n MIN_POLL_INTERVAL_MS,\n config.stepUpPollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS\n );\n\n while (Date.now() < deadline) {\n const status = await pollStepUpStatus(config, approval);\n if (status && status !== 'pending') {\n return status as StepUpOutcome;\n }\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await sleep(Math.min(pollInterval, remaining));\n }\n return 'timeout';\n}\n","/**\n * Direct-path step-up approval gate (post-3.1.0 F2 follow-up).\n *\n * The verify-access spending-Limit ladder returns an \"allowed-but-escalate\"\n * outcome for a transaction value in the human-in-the-loop band\n * `[autonomousThreshold, hardLimit)`: `policyAllowed: true` (it is NOT a deny)\n * plus `requiresStepUp` / `requiresApproval`. The bridge blocks these; the\n * direct-path adapters historically gated on `identityVerified && policyAllowed`\n * alone and would therefore ADMIT (and let the merchant settle) the very\n * purchase the bridge blocks - a cross-path bypass.\n *\n * The backend now creates a pending step-up approval record and returns a\n * `stepUpApproval` object with `{ approvalId, pollUrl, expiresAt }` in the\n * verify-access response. The owner can approve/deny from the dashboard\n * (Activity → Pending Verifications). Future channels: mobile push, browser\n * extension.\n *\n * Direct-path adapters (Express/MCP/Next.js) fail closed BY DEFAULT. The\n * `stepUpApproval` info is included in the deny response so integrations can\n * surface it (\"your agent owner needs to approve this\") or poll it themselves.\n * 3.6.0 adds an opt-in hold-and-poll (`stepUpMaxWaitMs` on GatewayConfig, see\n * ./stepup-poll.ts): the adapter holds the request, polls the approval, and on\n * 'approved' re-verifies once (cache-bypassed) so the backend redeems the\n * single-use approval — the MFA model the Java SDK ships default-on. Opt-in\n * here because a minor release must not silently convert instant 403s into\n * multi-minute holds (client timeouts, connection pools, edge wall-clocks).\n *\n * Detection keys on the granular Limit flags (`requiresStepUp` /\n * `requiresApproval`, set from the verify-access `access` block) rather than\n * the `recommendation` umbrella - both because those flags ARE what drive a\n * `step_up_required` recommendation server-side, and because it keeps the\n * unverified-agent-policy `audit` outcome (a deliberate allow-and-log) from\n * being caught here.\n */\nimport type { VerificationResult, StepUpApprovalInfo } from '../types';\n\nconst APPROVAL_REASON =\n 'Transaction is above the autonomous limit and requires human approval. The agent owner can approve or deny this transaction in the AstraSync dashboard.';\n\n/** True when the outcome needs human step-up/approval. */\nexport function requiresHumanApproval(result: VerificationResult): boolean {\n return result.requiresStepUp === true || result.requiresApproval === true;\n}\n\n/**\n * Annotate a result in place with the structured approval-required failure +\n * denial reason, so the adapters' existing deny renderers surface it like any\n * other failure. Mirrors the bridge's `commerce.intent.approval_required`.\n */\nexport function annotateApprovalRequired(result: VerificationResult): void {\n result.failures = [\n ...(result.failures ?? []),\n { dimension: 'commerce.intent.approval_required', message: APPROVAL_REASON },\n ];\n result.denialReasons = [APPROVAL_REASON, ...(result.denialReasons ?? [])];\n}\n\n/**\n * Extract step-up approval polling info from the verification result, if\n * present. Returns undefined when no approval was created (e.g. transaction\n * below the autonomous threshold, or the backend couldn't create one).\n */\nexport function getApprovalPollingInfo(result: VerificationResult): StepUpApprovalInfo | undefined {\n return result.stepUpApproval;\n}\n","/**\n * Settlement authorization — the value-aware, FAIL-CLOSED gate a direct merchant\n * MUST call before settling a priced cart (post-#447 partner round, finding #1).\n *\n * The bug it closes: the SDK request middleware performs a header-only ACCESS\n * check and never sends the transaction VALUE to verify-access, so the limit\n * engine never evaluates value and returns `grant` — a fully SDK-compliant\n * merchant settles every band, with the agent's PDLSS spend limits silently\n * unenforced. The bridge is safe only because `confirm_purchase` re-verifies\n * with the authoritative session total.\n *\n * The authoritative value exists ONLY after the merchant prices the cart (in the\n * handler, after the middleware), and it must be the MERCHANT's priced total —\n * never an agent-suppliable header (spoofable). So value enforcement is a\n * settlement-time, merchant-invoked call that mirrors the bridge: verify the\n * priced value against the agent's limits and refuse settlement unless it\n * cleanly grants.\n */\nimport type {\n GatewayConfig,\n VerificationResult,\n EnhancedVerificationResult,\n AccessFailure,\n StepUpApprovalInfo,\n} from './types';\nimport { verify } from './verify';\nimport { requiresHumanApproval } from './adapters/approval-gate';\n\nexport interface SettlementRequest {\n /** The agent's ASTRA-id (the caller you are about to settle for). */\n agentId: string;\n /** The MERCHANT's authoritative priced total for the cart. Never an agent-supplied amount. */\n value: number;\n /** ISO-4217 currency of `value`. */\n currency: string;\n /** Defaults to the canonical commerce pair; override for custom categories (e.g. 'trading' / 'trading.execute'). */\n purpose?: string;\n action?: string;\n}\n\nexport interface SettlementDecision {\n /** TRUE only on a clean grant. A step-up/approval outcome, any deny, a missing value, or a verify error all → false. */\n authorized: boolean;\n recommendation?: EnhancedVerificationResult['recommendation'];\n reason?: string;\n failures?: AccessFailure[];\n correlationId?: string;\n /** Present when the transaction is in the human-approval band — the owner can approve via the poll URL. */\n stepUpApproval?: StepUpApprovalInfo;\n}\n\n/**\n * Authorize a settlement of `value` for `agentId` against the agent's PDLSS\n * limits. FAIL-CLOSED: returns `authorized:false` on a missing/invalid value,\n * a verify-access error, a step-up/approval outcome (the value is in the\n * human-approval band and cannot complete autonomously), or any policy deny.\n * Settle ONLY when `authorized === true`.\n */\nexport async function authorizeSettlement(\n config: GatewayConfig,\n req: SettlementRequest\n): Promise<SettlementDecision> {\n // Fail closed on a missing/invalid authoritative value — never settle without one.\n if (typeof req.value !== 'number' || !Number.isFinite(req.value) || req.value <= 0) {\n return {\n authorized: false,\n recommendation: 'deny',\n reason:\n 'No valid transaction value supplied to authorizeSettlement; settlement refused (fail-closed). Pass the merchant-priced cart total as `value`.',\n failures: [\n {\n dimension: 'commerce.settlement.value_missing',\n message:\n 'A positive, authoritative transaction value is required to authorize settlement.',\n },\n ],\n };\n }\n\n let result: VerificationResult;\n try {\n result = await verify(config, {\n credentials: { astraId: req.agentId },\n purpose: req.purpose ?? 'shopping',\n action: req.action ?? 'shopping.purchase',\n transactionValue: req.value,\n currency: req.currency,\n });\n } catch (err) {\n // Fail closed on any verify error — do not settle on an unknown decision.\n return {\n authorized: false,\n recommendation: 'deny',\n reason: `Settlement verification failed (${\n err instanceof Error ? err.message : String(err)\n }); settlement refused (fail-closed).`,\n failures: [\n {\n dimension: 'commerce.settlement.verify_error',\n message:\n 'verify-access could not be reached or returned an error; settlement is refused.',\n },\n ],\n };\n }\n\n const recommendation = (result as EnhancedVerificationResult).recommendation;\n // Authorized ONLY on a clean grant: identity verified, policy allowed, NOT in\n // the human-approval band, and the recommendation (when present) is `grant`.\n const authorized =\n result.identityVerified === true &&\n result.policyAllowed === true &&\n !requiresHumanApproval(result) &&\n (recommendation === undefined || recommendation === 'grant');\n\n return {\n authorized,\n recommendation,\n reason: authorized\n ? undefined\n : (result.denialReasons?.[0] ??\n (requiresHumanApproval(result)\n ? 'Transaction is above the autonomous limit and requires human approval; settlement cannot be authorized automatically.'\n : \"Settlement not authorized by the agent's PDLSS limits.\")),\n failures: result.failures,\n correlationId: result.correlationId,\n stepUpApproval: requiresHumanApproval(result) ? result.stepUpApproval : undefined,\n };\n}\n","/**\n * AstraSync Universal Verification Gateway - Express Middleware\n *\n * Express.js middleware for verifying AI agents on API endpoints.\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { createMiddleware } from '@astrasyncai/verification-gateway/express';\n *\n * const app = express();\n *\n * app.use(createMiddleware({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * apiKey: process.env.ASTRASYNC_API_KEY,\n * counterpartyId: 'ASTRAE-...', // your registered endpoint id\n * }));\n * ```\n *\n * Per-route policy (which paths are gated, trust floors, PDLSS purposes) is\n * configured in the AstraSync dashboard, not in code — the middleware\n * fetches it automatically on init and refreshes periodically. There is no\n * `routes` option; a `routes` key in the config object is ignored (with a\n * warning) since v2.9.7.\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport type {\n ExpressMiddlewareOptions,\n AgentCredentials,\n VerificationResult,\n EnhancedVerificationResult,\n RouteAccessConfig,\n AstraSyncCredentials,\n VerificationRequest,\n} from '../types';\nimport { awaitStepUpApproval } from './stepup-poll';\nimport {\n verify,\n extractCredentials,\n recordDecision,\n reportCounterpartyPreCheckFailure,\n fetchRoutes,\n} from '../verify';\nimport { extractHttpCredentials } from '../transport/http';\nimport { MCP_VERIFIED_HOP_HEADER, parseVerifiedHop, isVerifiedHopValidFor } from '../verified-hop';\nimport { resolveHttpPdlss, type HttpPdlssResolution } from './http-pdlss';\nimport { requiresHumanApproval, annotateApprovalRequired } from './approval-gate';\nimport { performCounterpartyPreCheck } from '../pdlss-pre-check';\nimport { prefetchWellKnown, getWellKnownUrls } from '../well-known';\nimport { buildSdkObservedMetadata } from '../metadata-capture';\nimport { createAnonymousBeacon } from './anonymous-beacon';\n\n/**\n * Extend Express Request with verification result\n */\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n agentVerification?: VerificationResult;\n }\n }\n}\n\n/**\n * Default credential extractor\n */\nfunction defaultExtractCredentials(req: Request): AgentCredentials {\n return extractCredentials(\n req.headers as Record<string, string | string[] | undefined>,\n req.query as Record<string, string | undefined>\n );\n}\n\n/**\n * Extract extended AstraSync credentials (X-Astra-* headers) from Express request.\n * Returns null if no AstraSync headers are present.\n */\nexport function extractAstraSyncCredentials(req: Request): AstraSyncCredentials | null {\n return extractHttpCredentials(req.headers as Record<string, string | string[] | undefined>);\n}\n\n/** Read a possibly-array header value as a single string. */\nfunction headerValue(value: string | string[] | undefined): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value[0];\n return undefined;\n}\n\n/**\n * Resolve the canonical {purpose, action} pair for a request.\n * Replaces the gen-1 `defaultExtractPurpose` method-inference (`read_data`/\n * `write_data`) and the hardwired `action: req.method.toUpperCase()` — the\n * transport verb never travels as a PDLSS action. Full precedence chains\n * live in http-pdlss.ts.\n */\nfunction resolveRequestPdlss(\n req: Request,\n routeConfig: { purpose?: string; action?: string } | null,\n customExtractPurpose: ((req: Request) => string | undefined) | undefined,\n customExtractAction: ((req: Request) => string | undefined) | undefined\n): HttpPdlssResolution {\n return resolveHttpPdlss({\n method: req.method,\n astraPurpose: headerValue(req.headers['x-astra-purpose']),\n astraAction: headerValue(req.headers['x-astra-action']),\n legacyPurpose: headerValue(req.headers['x-purpose'] ?? req.headers['X-Purpose']),\n queryPurpose: typeof req.query.purpose === 'string' ? req.query.purpose : undefined,\n routePurpose: routeConfig?.purpose,\n routeAction: routeConfig?.action,\n hasCustomPurposeExtractor: !!customExtractPurpose,\n customPurpose: customExtractPurpose?.(req),\n hasCustomActionExtractor: !!customExtractAction,\n customAction: customExtractAction?.(req),\n });\n}\n\n/**\n * Match a route pattern against a path.\n *\n * Historically the SDK's\n * matchRoute was case-sensitive while Express's default `case sensitive\n * routing` is FALSE. A customer policy `/api/admin/*` did NOT match\n * `/api/ADMIN/users` → SDK returned `no-match` → request passed ungated →\n * Express routed it to the admin handler. The case-insensitive codepath\n * below closes the bypass.\n *\n * Ships in SHADOW MODE in SDK 2.4.13: by default the case-sensitive\n * regex is still authoritative; the case-insensitive variant is\n * computed in parallel and logged when results diverge. Follow-up\n * release flips the default to case-insensitive after 1-week\n * observation. Customers can flip early by setting\n * `caseInsensitiveRouteMatch: true` on the middleware options.\n */\nfunction matchRoute(\n pattern: string,\n path: string,\n opts?: { caseInsensitive?: boolean; correlationId?: string; logShadowDivergence?: boolean }\n): boolean {\n // Convert pattern to regex\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\//g, '\\\\/');\n\n const caseSensitiveRegex = new RegExp(`^${regexPattern}$`);\n const caseSensitiveResult = caseSensitiveRegex.test(path);\n\n if (!opts?.caseInsensitive && !opts?.logShadowDivergence) {\n return caseSensitiveResult;\n }\n\n const caseInsensitiveRegex = new RegExp(`^${regexPattern}$`, 'i');\n const caseInsensitiveResult = caseInsensitiveRegex.test(path);\n\n // Shadow logging: emit only when results diverge so operators can grep\n // their own logs for the bypass class without log volume spam.\n if (opts?.logShadowDivergence && caseSensitiveResult !== caseInsensitiveResult) {\n // eslint-disable-next-line no-console\n console.warn(\n `[SHADOW] matchRoute case-insensitive would change result: pattern=${pattern} path=${path} ` +\n `caseSensitive=${caseSensitiveResult} caseInsensitive=${caseInsensitiveResult} correlationId=${opts.correlationId ?? 'unknown'}`\n );\n }\n\n return opts?.caseInsensitive ? caseInsensitiveResult : caseSensitiveResult;\n}\n\n/**\n * Find the route configuration for a request\n */\nfunction findRouteConfig(\n routes: RouteAccessConfig[],\n path: string,\n method: string,\n opts?: { caseInsensitive?: boolean; correlationId?: string; logShadowDivergence?: boolean }\n): RouteAccessConfig | undefined {\n return routes.find((route) => {\n const methodMatches =\n route.method === '*' || route.method.toUpperCase() === method.toUpperCase();\n const pathMatches = matchRoute(route.pattern, path, opts);\n return methodMatches && pathMatches;\n });\n}\n\n/**\n * Default denied handler\n *\n * The response body carries the full `failures[]`\n * array and the `correlationId` so partners can render per-dimension UX\n * and tie a denial back to a server log line. Previously the merchant only\n * got the first denialReason — meaningful detail was thrown away before\n * the response left the SDK. Also stamps `X-Astra-Gateway-Mode: enforced`\n * so partners can tell a gate-evaluated denial apart from a gate-skipped\n * pass-through (the `unenforced` complement).\n */\nfunction dedupeFailures(result: VerificationResult): void {\n if (result.failures && result.failures.length > 1) {\n const seen = new Set<string>();\n result.failures = result.failures.filter((f) => {\n const key = `${f.dimension}|${f.message}|${(f as { guidance?: string }).guidance ?? ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n }\n if (result.denialReasons && result.denialReasons.length > 1) {\n result.denialReasons = [...new Set(result.denialReasons)];\n }\n}\n\nfunction defaultOnDenied(result: VerificationResult, _req: Request, res: Response): void {\n // 4.0.0 BREAKING: when this integration's OWN API key was rejected by the\n // backend (misconfigured marker), the inbound agent did nothing wrong and\n // re-authenticating won't help — a 401 both blames the agent and invites\n // re-auth loops. Answer 503: this site's verification layer is down, by\n // the operator's own configuration. No Retry-After — retrying is futile\n // until the operator rotates the key.\n if (result.misconfigured) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.status(503).json({\n success: false,\n error: {\n code: 'MERCHANT_VERIFICATION_MISCONFIGURED',\n message: result.denialReasons?.[0] || \"This site's AstraSync integration is misconfigured\",\n guidance: result.guidance,\n failures: result.failures,\n correlationId: result.correlationId,\n },\n });\n return;\n }\n\n // Round-18 G4: identity-verification failures → 401 (re-authenticate);\n // identity-verified-but-policy-denied → 403 (re-auth won't help; update\n // PDLSS scope or escalate to step-up). Maps to the two distinct recovery\n // actions that HTTP middleware acts on without parsing bodies. The\n // impossible state `!identityVerified && policyAllowed` falls into the\n // `!identityVerified` branch — identity is the more-fundamental missing\n // precondition.\n const statusCode = !result.identityVerified ? 401 : 403;\n\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n\n res.status(statusCode).json({\n success: false,\n error: {\n code: !result.identityVerified ? 'UNAUTHORIZED' : 'INSUFFICIENT_ACCESS',\n message: result.denialReasons?.[0] || 'Access denied',\n guidance: result.guidance,\n // Round-10: aggregated per-dimension detail + correlation handle.\n failures: result.failures,\n correlationId: result.correlationId,\n stepUpApproval: result.stepUpApproval,\n // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /\n // expired / consumed / timeout). Absent when the feature is off.\n ...(result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }),\n },\n });\n}\n\n/**\n * Refresh interval for the remote-fetched route policy. Default: every 5\n * minutes. Override via `routesRefreshMs` on the middleware options. Each\n * middleware instance keeps its own cache; multiple instances pointing at the\n * same endpoint will each fetch independently.\n */\nconst DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1000;\n\n/**\n * Create Express middleware for agent verification.\n *\n * v2.9.7 moved per-route policy authority out of merchant-side source code\n * into the AstraSync dashboard. `createMiddleware` no longer accepts a\n * `routes` array — it fetches the endpoint's stored policy via\n * `GET /endpoints/:counterpartyId/routes` on init and refreshes\n * periodically. Policy edits in the dashboard take effect on the next\n * refresh (or sooner if the operator manually restarts the SDK).\n *\n * `counterpartyId` is required: the SDK can't know which endpoint's policy\n * to fetch without it. Local-development workflows that don't have an\n * AstraSync endpoint registered can omit it — the middleware logs a\n * one-time warning and falls through (allows all) until a policy is\n * fetchable.\n */\nexport function createMiddleware(options: ExpressMiddlewareOptions): RequestHandler {\n // Guard against configs authored for pre-2.9.7 SDKs: a `routes` array in\n // merchant source is silently dead config (the type contract rejects it at\n // literal call sites, but variable-typed configs slip through) — and dead\n // route config means the author believes paths are gated that aren't.\n if ('routes' in options) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored — ' +\n 'configure route policy in your AstraSync dashboard.'\n );\n }\n const {\n extractCredentials: customExtractCredentials,\n extractPurpose: customExtractPurpose,\n extractAction: customExtractAction,\n skipPaths = [],\n onDenied = defaultOnDenied,\n recordDecisions,\n enableRuntimeChallenge = true,\n routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,\n failOnError = 'open',\n caseInsensitiveRouteMatch = false,\n anonymousBeacon = true,\n trustVerifiedHop = false,\n verifiedHopMaxAgeMs,\n ...config\n } = options;\n\n // v2.5.0: fire-and-forget pre-fetch of well-known URLs\n if (config.apiBaseUrl) {\n prefetchWellKnown(config.apiBaseUrl).catch(() => {});\n }\n\n // Dashboard-driven anonymous-traffic beacon for the pass-through paths\n // (no matching route / route gated at `none`). Fire-and-forget: never\n // awaited, never delays next(). See ./anonymous-beacon.ts.\n const emitAnonymousBeacon = anonymousBeacon\n ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? 'api' })\n : undefined;\n const beaconPassThrough = emitAnonymousBeacon\n ? (req: Request): void => {\n const xff = req.headers['x-forwarded-for'];\n const xffStr = Array.isArray(xff) ? xff.join(', ') : xff;\n emitAnonymousBeacon({\n requestPath: req.path,\n requestMethod: req.method,\n counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get('host')}`,\n sourceIp: req.ip ?? (xffStr ? xffStr.split(',')[0].trim() : undefined),\n rawHeaders: req.headers as Record<string, string | string[] | undefined>,\n });\n }\n : undefined;\n\n // Per-middleware-instance route cache. Populated on first fetch; refreshed\n // every `routesRefreshMs`. Until first successful fetch we hold an empty\n // array which means \"no per-route gating active\" — the middleware falls\n // through. Pre-fix the array came from merchant source, which both broke\n // the auth-boundary story (defect 24) and silently disagreed with the\n // dashboard.\n let cachedRoutes: RouteAccessConfig[] = [];\n let lastFetchAt = 0;\n let refreshing: Promise<void> | null = null;\n let warnedNoCounterparty = false;\n let warnedEmptyRoutes = false;\n\n async function refreshRoutes(): Promise<void> {\n if (!config.counterpartyId) {\n if (!warnedNoCounterparty) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway] No counterpartyId configured — falling through (allow all). ' +\n 'Per-route policy lives in the AstraSync dashboard now; register the endpoint and ' +\n 'set counterpartyId in your middleware config to enforce policy.'\n );\n warnedNoCounterparty = true;\n }\n return;\n }\n const fetched = await fetchRoutes(config, config.counterpartyId);\n if (fetched) {\n cachedRoutes = fetched;\n lastFetchAt = Date.now();\n // v2.3.8 (defect #25): if the fetch succeeded but returned an empty\n // policy, the endpoint is registered correctly but the operator hasn't\n // configured any routes yet — every request will fall through ungated.\n // Surface this loudly once so silent pass-through can't go unnoticed.\n if (cachedRoutes.length === 0 && !warnedEmptyRoutes) {\n // Audit F-PROBE-01: app.astrasync.ai doesn't resolve in DNS today;\n // dashboard actually lives at astrasync.ai/dashboard. Use that as\n // the fallback. If DevOps provisions app.astrasync.ai later, the\n // dashboardUrl config option lets merchants override.\n const dashboard = config.dashboardUrl ?? 'https://astrasync.ai/dashboard';\n // eslint-disable-next-line no-console\n console.warn(\n `[VerificationGateway] No route policy configured for ${config.counterpartyId}. ` +\n `Gateway is in pass-through mode for ALL traffic until you add at least one route. ` +\n `Configure at ${dashboard}/dashboard/endpoints/${config.counterpartyId}/routes`\n );\n warnedEmptyRoutes = true;\n }\n }\n }\n\n // Eager first fetch so the first request after init has policy loaded.\n // Errors are swallowed (handled by fetchRoutes returning null).\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n try {\n // Check if path should be skipped\n const shouldSkip = skipPaths.some((pattern) => matchRoute(pattern, req.path));\n if (shouldSkip) {\n return next();\n }\n\n // Wait for in-flight init fetch (only on the very first request) so we\n // don't admit traffic with no policy loaded.\n if (refreshing) {\n await refreshing.catch(() => {});\n }\n // Time-based refresh: kick off a background refresh if the cache is\n // stale. Doesn't block the current request — readers see whatever is\n // cached at this moment; the next request will see the refreshed copy.\n if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n }\n\n // Find route configuration\n // Audit F-A6-31 shadow-mode wiring: pass caseInsensitive flag (default\n // false in 2.4.13) + always log divergences so merchants can grep for\n // would-have-matched results during the 1-week observation window.\n const correlationId =\n (req.headers['x-request-id'] as string | undefined) ||\n (req.headers['x-correlation-id'] as string | undefined);\n const routeConfig = findRouteConfig(cachedRoutes, req.path, req.method, {\n caseInsensitive: caseInsensitiveRouteMatch,\n logShadowDivergence: true,\n correlationId,\n });\n\n // If no route config, skip verification (allow through)\n if (!routeConfig) {\n if (config.setPassThroughHeader) {\n // Round-10 (#49, O10): `unenforced` replaces the previous\n // `pass-through` label. The previous name conflated \"gateway\n // didn't evaluate policy\" with \"request succeeded end-to-end\" —\n // the downstream handler may still return any status. The new\n // semantic describes the GATE state only.\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader(\n 'X-Astra-Gateway-Reason',\n cachedRoutes.length === 0 ? 'no-policy' : 'no-match'\n );\n }\n // Anonymous-traffic beacon: this request never reaches verify-access,\n // so bot/agent-shaped callers would otherwise be invisible to the\n // dashboard. Fire-and-forget — does not delay next().\n beaconPassThrough?.(req);\n return next();\n }\n\n // v2.5.0: resolve well-known URLs (cached; prefetched at middleware creation)\n const wellKnownUrls = config.apiBaseUrl\n ? await getWellKnownUrls(config.apiBaseUrl).catch(() => undefined)\n : undefined;\n\n // Extract credentials (hoisted from below the route-none check so the\n // round-12 F9 evaluateAlwaysIfCredentialed flag can decide whether to\n // evaluate vs short-circuit).\n const credentials = customExtractCredentials\n ? customExtractCredentials(req)\n : defaultExtractCredentials(req);\n\n // Round-12 (F9): route-none short-circuit unless the caller wants\n // evaluation-without-enforcement. With evaluateAlwaysIfCredentialed\n // set to true AND credentials present, the middleware calls\n // verify-access for audit + req.agentVerification population, then\n // proceeds without gating. Default behaviour (flag off) preserves\n // pre-F9 short-circuit semantics.\n const shouldEnforce = !routeConfig.observe;\n if (routeConfig.observe && (!config.evaluateAlwaysIfCredentialed || !credentials.astraId)) {\n if (config.setPassThroughHeader) {\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader('X-Astra-Gateway-Reason', 'route-observe');\n }\n // Anonymous-traffic beacon (see the no-route-match branch above).\n beaconPassThrough?.(req);\n return next();\n }\n\n // Inner-hop dedupe: a trusted upstream AstraSync hop (edge gateway or\n // MCP outer hop) already verified this exact ASTRA-id moments ago —\n // accept the fresh marker and skip the duplicate verify-access call.\n // Mirrors the MCP adapter contract: no req.agentVerification on a\n // hop-skip. The marker must match the request's own X-Astra-Id.\n if (trustVerifiedHop && credentials.astraId) {\n const hopRaw = req.headers[MCP_VERIFIED_HOP_HEADER.toLowerCase()];\n const hopValue =\n typeof hopRaw === 'string' ? hopRaw : Array.isArray(hopRaw) ? hopRaw[0] : undefined;\n const marker = parseVerifiedHop(hopValue);\n if (\n isVerifiedHopValidFor(marker, credentials.astraId, {\n ...(verifiedHopMaxAgeMs !== undefined ? { maxAgeMs: verifiedHopMaxAgeMs } : {}),\n })\n ) {\n return next();\n }\n }\n\n // v2.3.0: anonymous traffic no longer short-circuits client-side.\n // The server applies the endpoint's `unverifiedAgentPolicy` (deny /\n // allow_partial / allow_full) and emits the verification event +\n // blockchain record per the canonical flow. SDK forwards verbatim.\n\n // Resolve the canonical {purpose, action} pair (Bug 14, §4.6): dashboard\n // route mapping → custom extractors → agent X-Astra-* headers →\n // method-table fallback. The transport verb never travels as the action.\n const pdlssPair = resolveRequestPdlss(\n req,\n routeConfig,\n customExtractPurpose,\n customExtractAction\n );\n const purpose = pdlssPair.purpose;\n if (config.debug) {\n // Same telemetry shape as the MCP adapter — adoption tracking and\n // support triage read the *_source fields to see which integration\n // path each partner uses (route mapping vs headers vs fallback).\n // eslint-disable-next-line no-console\n console.debug('[express-middleware] pdlss resolved', {\n purpose_source: pdlssPair.purposeSource,\n resolved_purpose: pdlssPair.purpose,\n action_source: pdlssPair.actionSource,\n resolved_action: pdlssPair.action,\n });\n }\n\n // Extract full AstraSync credentials (includes PDLSS from X-Astra-* headers)\n const astraCreds = extractAstraSyncCredentials(req);\n\n // Auto-detect counterparty URL from the request if not explicitly configured.\n // Since the SDK is installed at this endpoint, we always know the origin.\n const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get('host')}`;\n\n // Step 2: Counterparty-side PDLSS pre-check — compare agent's requested PDLSS\n // against counterparty-defined maximums on the route config.\n // Rejects immediately if outside limits, BEFORE calling verify-access.\n const preCheckFailures = performCounterpartyPreCheck(routeConfig, astraCreds, purpose);\n if (preCheckFailures.length > 0) {\n // Round-18 G4: counterparty pre-check failure — request rejected\n // before reaching verify-access. Neither identity nor policy was\n // remotely verified; both axes truthfully false.\n const result: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: preCheckFailures.map((f) => f.message),\n guidance: {\n message: 'Request exceeds counterparty-defined PDLSS limits.',\n registrationUrl: wellKnownUrls?.registrationUrl ?? '',\n documentationUrl: wellKnownUrls?.documentationUrl ?? '',\n },\n verifiedAt: new Date(),\n };\n\n req.agentVerification = result;\n\n // Fire-and-forget: notify AstraSync of the pre-check failure\n reportCounterpartyPreCheckFailure(config, {\n agentId: astraCreds?.agentId || credentials.astraId || 'unknown',\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'api',\n failures: preCheckFailures,\n requestPath: req.path,\n requestMethod: req.method,\n }).catch(() => {});\n\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // Step 3: Call AstraSync verify-access with runtime challenge enabled\n const shouldRecordDecisions = recordDecisions !== false;\n const forwardedFor = req.headers['x-forwarded-for'];\n const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(', ') : forwardedFor;\n // Audit F-A6-34: previously the LEFTMOST X-Forwarded-For entry was\n // taken as the original client IP. That value is attacker-controlled\n // whenever the customer's reverse proxy doesn't strip\n // client-supplied X-Forwarded-For — an attacker prepends\n // `X-Forwarded-For: 1.1.1.1` and we audit the spoofed IP. Now we\n // prefer req.ip (which Express resolves via configured `trust proxy`\n // hop count — the customer's responsibility to set correctly per\n // their actual hop chain). XFF still provides a fallback for\n // customers without `trust proxy` configured, but emits a one-time\n // warning when used so they know to fix.\n const originalClientIp =\n req.ip ?? (forwardedForStr ? forwardedForStr.split(',')[0].trim() : undefined);\n if (!req.ip && forwardedForStr) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway] req.ip unset — falling back to leftmost X-Forwarded-For. ' +\n 'Configure Express trust proxy correctly to avoid spoofable client IPs in audit logs.'\n );\n }\n const agentCardUrl =\n typeof req.headers['x-astrasync-agent-card'] === 'string'\n ? (req.headers['x-astrasync-agent-card'] as string)\n : undefined;\n\n // P1 (SDK 3.5.0): when extractTransactionValue is configured, include\n // the value in verify-access so PDLSS limit evaluation runs at\n // middleware time. Must return major units (dollars, not cents).\n let txValue: number | undefined;\n let txCurrency: string | undefined;\n if (config.extractTransactionValue) {\n try {\n const extracted = config.extractTransactionValue(req);\n if (extracted) {\n txValue = extracted.value;\n txCurrency = extracted.currency;\n }\n } catch (e) {\n if (config.debug) {\n // eslint-disable-next-line no-console\n console.warn('[VerificationGateway] extractTransactionValue threw:', e);\n }\n }\n }\n\n const verificationRequest: VerificationRequest = {\n credentials,\n purpose,\n action: pdlssPair.action,\n resource: req.path,\n createSession: shouldRecordDecisions,\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'api',\n enableRuntimeChallenge,\n durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,\n ...(txValue !== undefined && { transactionValue: txValue }),\n ...(txCurrency && { currency: txCurrency }),\n callerMetadata: {\n sourceIp: originalClientIp,\n userAgent: req.headers['user-agent'] as string | undefined,\n referer: req.headers.referer as string | undefined,\n host: req.headers.host as string | undefined,\n forwardedFor: forwardedForStr,\n agentCardUrl,\n // Workstream D — capture EVERY inbound header (SDK-only merchants\n // have no edge to do it upstream) plus the CDN-derived connection\n // block. Local string work, secrets stripped; out of the verify\n // cache key so it doesn't defeat caching.\n observedMetadata: buildSdkObservedMetadata(req.headers),\n },\n };\n let result = await verify(config, verificationRequest);\n\n // Attach result to request\n req.agentVerification = result;\n let sessionId = (result as EnhancedVerificationResult).sessionId;\n\n // 3.6.0 hold-and-poll (opt-in via stepUpMaxWaitMs): HOLD a step-up\n // outcome, poll the approval, and on 'approved' re-verify the same\n // request once (cache-bypassed — the retry must reach the backend to\n // redeem the single-use approval). Every non-approved outcome falls\n // through to the existing fail-closed branches below with\n // result.stepUpOutcome stamped for the deny body.\n if (\n config.stepUpMaxWaitMs !== undefined &&\n result.policyAllowed &&\n requiresHumanApproval(result) &&\n result.stepUpApproval?.pollUrl\n ) {\n const outcome = await awaitStepUpApproval(config, result.stepUpApproval);\n res.setHeader('X-Astra-Step-Up', outcome);\n if (outcome === 'approved') {\n result = await verify(config, verificationRequest, { bypassCache: true });\n req.agentVerification = result;\n sessionId = (result as EnhancedVerificationResult).sessionId;\n } else {\n result.stepUpOutcome = outcome;\n }\n }\n\n // Denied verifications short-circuit here: failing either identity OR\n // policy already means \"deny.\" We check that first.\n // 4.5.0 (probe F1 follow-through): the gate is the SERVER's decision —\n // `policyAllowed` is true exactly when the backend allowed the call\n // (every deny/guidance/api-error shape sets it false), so gating on it\n // alone preserves the endpoint policy verbatim. `identityVerified` no\n // longer gates here: anonymous callers granted by an\n // audit/allow_partial/allow_full endpoint policy are honestly\n // identity-unverified yet server-allowed, and re-deriving a deny from\n // identity would override the backend evaluator (the SDK-pre-check\n // asymmetry antipattern). Identity still picks 401-vs-403 in the deny\n // body builder.\n if (!result.policyAllowed) {\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // F2 direct-path fail-closed: an \"allowed-but-escalate\" outcome\n // (step-up / requires-approval, policyAllowed:true) cannot be completed\n // autonomously. The backend creates a step-up approval record and returns\n // it on `result.stepUpApproval`; deny here — symmetric with the bridge —\n // and surface the polling info in the deny response body.\n if (requiresHumanApproval(result)) {\n annotateApprovalRequired(result);\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // Round-12 (F9): evaluation-without-enforcement. When the route is\n // 'none' but we ran verify-access for audit, skip the gates and call\n // next() — the result is on req.agentVerification for the handler\n // to render tier-aware responses (e.g. anonymous vs verified\n // catalog view on the same path).\n if (!shouldEnforce) {\n if (config.setPassThroughHeader) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.setHeader('X-Astra-Gateway-Reason', 'evaluated-not-enforced');\n }\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n return next();\n }\n\n // The access decision is the server's (identityVerified / policyAllowed,\n // above) — resting on a verified ID + runtime challenge + PDLSS match +\n // trust score. The only client-side refinement is the per-route trust\n // floor below; there is no access-level band (removed in SDK 5.0.0).\n\n // Per-route trust tightening (only refinement that still gates).\n if (routeConfig.minTrustScore && result.agent) {\n if (result.agent.trustScore < routeConfig.minTrustScore) {\n // 3.2.0: qualitative — never embed the score or the threshold in an\n // agent-visible message (trust is a system-internal signal; exposing\n // the number is a gaming vector — post-3.1.0 feedback #2).\n const trustFailure = {\n dimension: 'endpoint.trust',\n message: 'Trust below the route requirement for this endpoint.',\n guidance:\n \"Trust is below this route's floor. Trust is not overridable — the agent either meets the endpoint's trust policy or it doesn't. Raise the agent's trust via real signals (KYD, blockchain registration, agent-card), or have the operator lower the route's minTrustScore.\",\n };\n result.failures = [...(result.failures ?? []), trustFailure];\n result.denialReasons = [trustFailure.message];\n if (!result.guidance && wellKnownUrls) {\n result.guidance = {\n message: trustFailure.message,\n registrationUrl: wellKnownUrls.registrationUrl,\n documentationUrl: wellKnownUrls.documentationUrl,\n };\n }\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', trustFailure.message).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n }\n\n // All checks passed — record grant decision\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n // v2.3.8 (defect #26): if the endpoint's `unverifiedAgentPolicy` is\n // `'audit'` (allow + soft-launch warning), the server returns the\n // header to relay. Lift it onto the merchant's response BEFORE\n // calling next() so downstream handlers and the eventual response\n // back to the agent both carry it.\n const enhancedResult = result as EnhancedVerificationResult;\n if (enhancedResult.warningHeader) {\n res.setHeader(enhancedResult.warningHeader.name, enhancedResult.warningHeader.value);\n }\n next();\n } catch (error) {\n // Audit F-A1-06: shadow-mode logging for fail-closed default migration.\n // Always log `[SHADOW] would-have-denied` so merchants can grep their\n // own application logs for would-have-been-denied impact during the\n // observation window. Actual deny/admit behavior controlled by\n // failOnError option (default 'open' for backward compatibility).\n const errorClass = error instanceof Error ? error.constructor.name : typeof error;\n const correlationId =\n (req.headers['x-request-id'] as string | undefined) ||\n (req.headers['x-correlation-id'] as string | undefined) ||\n `gen-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n // eslint-disable-next-line no-console\n console.error('[VerificationGateway] Middleware error:', error);\n // eslint-disable-next-line no-console\n console.warn(\n `[SHADOW] would-have-denied: errorClass=${errorClass} route=${req.method}:${req.path} merchantId=${config.counterpartyId ?? 'unknown'} correlationId=${correlationId}`\n );\n\n if (failOnError === 'closed') {\n const result: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: [`Verification middleware internal error: ${errorClass}`],\n failures: [\n {\n dimension: 'middleware.internal_error',\n message: `Middleware threw ${errorClass} — failing closed`,\n },\n ],\n verifiedAt: new Date(),\n correlationId,\n };\n const catchUrls = config.apiBaseUrl\n ? await getWellKnownUrls(config.apiBaseUrl).catch(() => undefined)\n : undefined;\n if (catchUrls) {\n result.guidance = {\n message: `Middleware threw ${errorClass} — failing closed`,\n registrationUrl: catchUrls.registrationUrl,\n documentationUrl: catchUrls.documentationUrl,\n };\n }\n dedupeFailures(result);\n return onDenied(result, req, res);\n }\n\n next();\n }\n };\n}\n\n// `requireAccess` and `verifyOnly` were removed in v2.9.7. Both injected a\n// local `routes` array into the merchant's source code, which is the exact\n// dual-config attack vector defect 24 closed. Per-route policy now lives in\n// the AstraSync dashboard (gated by team.role admin auth + audit + alerts).\n// To tighten a route, set its `minTrustScore` (+ purpose/jurisdiction/value\n// gates) in the dashboard. For \"verify but don't block,\" set the route to\n// `observe` (or run the endpoint in an audit `unverifiedAgentPolicy`).\n","/**\n * HTTP Transport Adapter\n *\n * Maps AstraSync credentials to/from HTTP headers (X-Astra-* convention).\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\nconst HEADER_PREFIX = 'X-Astra-';\n\n/**\n * Inject AstraSync credentials into HTTP headers.\n */\nexport function setHttpHeaders(\n headers: Record<string, string>,\n credentials: AstraSyncCredentials\n): Record<string, string> {\n const result = { ...headers };\n\n result[`${HEADER_PREFIX}ID`] = credentials.agentId;\n\n if (credentials.verifyUrl) {\n result[`${HEADER_PREFIX}Verify`] = credentials.verifyUrl;\n }\n\n if (credentials.challengeUrl) {\n result[`${HEADER_PREFIX}Challenge`] = credentials.challengeUrl;\n }\n\n if (credentials.pdlss?.purpose) {\n // 3.1.0 (Bug 14, §4.6): the action ALSO travels on its own dedicated\n // header so new-SDK receivers get the clean two-axis pair. The colon\n // form below is kept as the back-compat channel — pre-3.1.0 receivers\n // split on ':' and take the category prefix.\n const purposeValue = credentials.pdlss.purpose.action\n ? `${credentials.pdlss.purpose.category}:${credentials.pdlss.purpose.action}`\n : credentials.pdlss.purpose.category;\n result[`${HEADER_PREFIX}Purpose`] = purposeValue;\n if (credentials.pdlss.purpose.action) {\n result[`${HEADER_PREFIX}Action`] = credentials.pdlss.purpose.action;\n }\n }\n\n if (credentials.pdlss?.duration?.maxSessionDuration) {\n result[`${HEADER_PREFIX}Duration`] = String(credentials.pdlss.duration.maxSessionDuration);\n }\n\n if (credentials.pdlss?.scope?.jurisdiction) {\n result[`${HEADER_PREFIX}Scope`] = credentials.pdlss.scope.jurisdiction;\n }\n\n return result;\n}\n\n/**\n * Extract AstraSync credentials from HTTP headers.\n */\nexport function extractHttpCredentials(\n headers: Record<string, string | string[] | undefined>\n): AstraSyncCredentials | null {\n const getValue = (key: string): string | undefined => {\n const v = headers[key] ?? headers[key.toLowerCase()];\n return Array.isArray(v) ? v[0] : v;\n };\n\n const agentId = getValue(`${HEADER_PREFIX}ID`) ?? getValue('x-astra-id');\n if (!agentId) return null;\n\n const credentials: AstraSyncCredentials = { agentId };\n\n const verifyUrl = getValue(`${HEADER_PREFIX}Verify`) ?? getValue('x-astra-verify');\n if (verifyUrl) credentials.verifyUrl = verifyUrl;\n\n const challengeUrl = getValue(`${HEADER_PREFIX}Challenge`) ?? getValue('x-astra-challenge');\n if (challengeUrl) credentials.challengeUrl = challengeUrl;\n\n const purpose = getValue(`${HEADER_PREFIX}Purpose`) ?? getValue('x-astra-purpose');\n if (purpose) {\n const [category, action] = purpose.split(':');\n credentials.pdlss = {\n ...credentials.pdlss,\n purpose: { category, action },\n };\n }\n\n // 3.1.0 (Bug 14, §4.6): dedicated action header — overrides any colon-form\n // remainder parsed above (the dedicated header is the canonical channel).\n const astraAction = getValue(`${HEADER_PREFIX}Action`) ?? getValue('x-astra-action');\n if (astraAction) {\n credentials.pdlss = {\n ...credentials.pdlss,\n purpose: { category: credentials.pdlss?.purpose?.category ?? '', action: astraAction },\n };\n }\n\n const duration = getValue(`${HEADER_PREFIX}Duration`) ?? getValue('x-astra-duration');\n if (duration) {\n credentials.pdlss = {\n ...credentials.pdlss,\n duration: { maxSessionDuration: parseInt(duration, 10) },\n };\n }\n\n const scope = getValue(`${HEADER_PREFIX}Scope`) ?? getValue('x-astra-scope');\n if (scope) {\n credentials.pdlss = {\n ...credentials.pdlss,\n scope: { jurisdiction: scope },\n };\n }\n\n return credentials;\n}\n","/**\n * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.\n *\n * Header carrying upstream verify-access proof so an inner-hop endpoint can\n * dedupe (skip verify-access when the same ASTRA-id was already verified a\n * few ms earlier). Emitted by the MCP adapter toward tool fetches and by the\n * edge gateway toward the origin at authenticate/authorize depth. Value\n * format:\n *\n * {astraId};{sessionId};{checkedAt-ms}\n *\n * Receivers MUST validate that `checkedAt` is recent (≤ 60s window\n * recommended) and that `astraId` matches the agent identity claimed on the\n * inner hop. The header alone is NOT proof-of-identity — it's an UNSIGNED\n * dedupe advisory: trust it (`trustVerifiedHop`) only where every network\n * path to the inner hop crosses a stripping gateway or an equivalent trusted\n * boundary, exactly like the unsigned X-AstraSync-* attestation headers.\n * Pair with the existing X-Astra-Id auth.\n */\n\nexport const MCP_VERIFIED_HOP_HEADER = 'X-Astra-Verified-Hop';\n\n/** Default acceptable age (ms) for an X-Astra-Verified-Hop header. */\nexport const MCP_VERIFIED_HOP_MAX_AGE_MS = 60_000;\n\nexport interface VerifiedHopMarker {\n astraId: string;\n sessionId?: string;\n checkedAt: number; // epoch ms\n}\n\nexport function serializeVerifiedHop(marker: VerifiedHopMarker): string {\n return `${marker.astraId};${marker.sessionId ?? ''};${marker.checkedAt}`;\n}\n\nexport function parseVerifiedHop(value: string | undefined | null): VerifiedHopMarker | null {\n if (!value) return null;\n const parts = value.split(';');\n if (parts.length !== 3) return null;\n const [astraId, sessionId, checkedAtRaw] = parts;\n if (!astraId) return null;\n const checkedAt = Number(checkedAtRaw);\n if (!Number.isFinite(checkedAt) || checkedAt <= 0) return null;\n return {\n astraId,\n ...(sessionId ? { sessionId } : {}),\n checkedAt,\n };\n}\n\n/**\n * Returns true when `marker.astraId` matches the inner-hop's claimed\n * ASTRA-id AND the marker is recent enough. Inner-hop middleware uses this\n * to skip a duplicate verify-access call.\n */\nexport function isVerifiedHopValidFor(\n marker: VerifiedHopMarker | null,\n expectedAstraId: string,\n opts: { maxAgeMs?: number; now?: number } = {}\n): boolean {\n if (!marker) return false;\n if (marker.astraId !== expectedAstraId) return false;\n const maxAge = opts.maxAgeMs ?? MCP_VERIFIED_HOP_MAX_AGE_MS;\n const now = opts.now ?? Date.now();\n return now - marker.checkedAt <= maxAge && now >= marker.checkedAt;\n}\n","/**\n * Shared purpose/action resolver for the HTTP adapters (express + nextjs) —\n * the vocabulary-unification layer.\n *\n * The PDLSS two-axis contract: `purpose` = bare category noun (`shopping`,\n * `data`, custom nouns like `trading`); `action` = dotted verb\n * (`shopping.search`) or an enumerated transport token. Transport verbs\n * (GET/POST/...) NEVER travel as PDLSS actions — they map through the pinned\n * method table below.\n *\n * SELF-CONTAINED on purpose: this published package cannot depend on the\n * private @astrasyncai/pdlss-vocab workspace package, so the constants are\n * duplicated here and pinned strictly equal by a monorepo CI test\n * (vocab-equality.test.ts). Change them in BOTH places or that test fails.\n */\n\n/** Pinned method→action derivation table. */\nexport const HTTP_METHOD_ACTION_TABLE: Readonly<Record<string, string>> = {\n GET: 'data.read',\n HEAD: 'data.read',\n OPTIONS: 'data.read',\n POST: 'data.write',\n PUT: 'data.write',\n PATCH: 'data.write',\n DELETE: 'data.delete',\n};\n\n/** Unknown methods are treated as mutating until proven otherwise. */\nexport const DEFAULT_HTTP_ACTION = 'data.write';\n\n/** Generic category emitted when nothing supplies a domain purpose. */\nexport const DEFAULT_HTTP_PURPOSE = 'data';\n\nexport function actionForHttpMethod(method: string): string {\n return HTTP_METHOD_ACTION_TABLE[method.toUpperCase()] ?? DEFAULT_HTTP_ACTION;\n}\n\nexport type HttpPurposeSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'legacy_header'\n | 'query'\n | 'action_derived'\n | 'transport_default';\n\nexport type HttpActionSource =\n | 'route_config'\n | 'custom_extractor'\n | 'header'\n | 'purpose_header_derived'\n | 'method_table';\n\nexport interface HttpPdlssInput {\n method: string;\n /** `X-Astra-Purpose` header value (agent's declaration). */\n astraPurpose?: string;\n /** `X-Astra-Action` header value (agent's declaration, symmetric with MCP). */\n astraAction?: string;\n /** Legacy `x-purpose` header — deprecated, removal scheduled for 4.0.0. */\n legacyPurpose?: string;\n /** Legacy `?purpose` query param (express only) — deprecated, removal 4.0.0. */\n queryPurpose?: string;\n /** Dashboard route config send-mapping (RouteAccessConfig.purpose/.action). */\n routePurpose?: string;\n routeAction?: string;\n /** Results of the merchant's extractPurpose/extractAction options. */\n customPurpose?: string;\n hasCustomPurposeExtractor?: boolean;\n customAction?: string;\n hasCustomActionExtractor?: boolean;\n}\n\nexport interface HttpPdlssResolution {\n purpose: string;\n action: string;\n purposeSource: HttpPurposeSource;\n actionSource: HttpActionSource;\n}\n\n/**\n * Normalize an `X-Astra-Purpose` header value.\n * - colon form `\"category:action\"` (legacy wire shape): take the prefix; the\n * remainder is free-text and exists in no vocabulary — discard it and let\n * the method table supply the action (matches pre-3.1.0 discard behavior).\n * - dotted form `\"shopping.purchase\"` (the shape older docs taught): prefix\n * becomes the purpose, the WHOLE token becomes an action candidate.\n * - bare token: purpose verbatim.\n */\nexport function normalizePurposeHeader(value: string): {\n purpose: string;\n actionCandidate?: string;\n} {\n const colon = value.indexOf(':');\n if (colon >= 0) {\n return { purpose: value.slice(0, colon) };\n }\n const dot = value.indexOf('.');\n if (dot > 0 && dot < value.length - 1) {\n return { purpose: value.slice(0, dot), actionCandidate: value };\n }\n return { purpose: value };\n}\n\n/**\n * Resolve the {purpose, action} pair for one HTTP request.\n *\n * Precedence (both axes):\n * action: route mapping → extractAction option → X-Astra-Action header →\n * candidate from a dotted X-Astra-Purpose → pinned method table\n * purpose: route mapping → extractPurpose option → X-Astra-Purpose →\n * legacy x-purpose / ?purpose → category prefix of the resolved\n * action → 'data'\n *\n * A configured custom extractor masks the header/legacy/query steps of its\n * axis (it replaces the default chain, as extractPurpose always has); when it\n * returns undefined the axis falls through to the table/prefix fallback.\n * The route mapping is merchant policy fetched from the dashboard — it\n * outranks agent-supplied headers the way MCP toolGates do.\n */\nexport function resolveHttpPdlss(input: HttpPdlssInput): HttpPdlssResolution {\n const fromHeader = input.astraPurpose ? normalizePurposeHeader(input.astraPurpose) : undefined;\n\n // ── Action axis ──\n let action: string;\n let actionSource: HttpActionSource;\n if (input.routeAction) {\n action = input.routeAction;\n actionSource = 'route_config';\n } else if (input.hasCustomActionExtractor && input.customAction) {\n action = input.customAction;\n actionSource = 'custom_extractor';\n } else if (!input.hasCustomActionExtractor && input.astraAction) {\n action = input.astraAction;\n actionSource = 'header';\n } else if (!input.hasCustomActionExtractor && fromHeader?.actionCandidate) {\n action = fromHeader.actionCandidate;\n actionSource = 'purpose_header_derived';\n } else {\n action = actionForHttpMethod(input.method);\n actionSource = 'method_table';\n }\n\n // ── Purpose axis ──\n let purpose: string | undefined;\n let purposeSource: HttpPurposeSource | undefined;\n if (input.routePurpose) {\n purpose = input.routePurpose;\n purposeSource = 'route_config';\n } else if (input.hasCustomPurposeExtractor) {\n if (input.customPurpose) {\n purpose = input.customPurpose;\n purposeSource = 'custom_extractor';\n }\n } else if (fromHeader) {\n purpose = fromHeader.purpose;\n purposeSource = 'header';\n } else if (input.legacyPurpose) {\n purpose = input.legacyPurpose;\n purposeSource = 'legacy_header';\n } else if (input.queryPurpose) {\n purpose = input.queryPurpose;\n purposeSource = 'query';\n }\n\n if (!purpose) {\n // Keep the pair coherent: an agent that sent only X-Astra-Action (or a\n // route that mapped only the action) gets that action's own category.\n const dot = action.indexOf('.');\n if (dot > 0) {\n purpose = action.slice(0, dot);\n purposeSource = 'action_derived';\n } else {\n purpose = DEFAULT_HTTP_PURPOSE;\n purposeSource = 'transport_default';\n }\n }\n\n return { purpose, action, purposeSource: purposeSource!, actionSource };\n}\n","/**\n * Counterparty-side PDLSS pre-check.\n *\n * Compares the agent's requested PDLSS dimensions (from X-Astra-* headers)\n * against the counterparty-defined maximums on the route config.\n * Returns an array of failures — empty means all checks passed.\n *\n * This runs BEFORE calling verify-access on AstraSync. If it fails,\n * the request is rejected immediately without calling the platform.\n */\n\nimport type { RouteAccessConfig, AstraSyncCredentials, CounterpartyPreCheckFailure } from './types';\n\nexport function performCounterpartyPreCheck(\n routeConfig: RouteAccessConfig,\n astraCreds: AstraSyncCredentials | null,\n purpose: string | undefined\n): CounterpartyPreCheckFailure[] {\n const failures: CounterpartyPreCheckFailure[] = [];\n\n // Check purpose against allowedPurposes whitelist. Route allow-lists are an\n // OPTIONAL per-route refinement — undefined/empty = \"skip, let the backend\n // evaluator be the authoritative gate\". The backend's PDLSS evaluator\n // enforces the agent's own declared policy (round-18.5 F3 fail-closed there\n // is correct: the agent declared its allowlist or didn't). Treating an\n // undefined route allow-list as fail-closed breaks every partner that hasn't\n // enumerated allowedPurposes (which is most of them — round-18.5 originally\n // shipped this and was reverted in 2.4.11 after partner-wide auth break).\n if (routeConfig.allowedPurposes && routeConfig.allowedPurposes.length > 0 && purpose) {\n if (!routeConfig.allowedPurposes.includes(purpose)) {\n failures.push({\n field: 'purpose',\n requested: purpose,\n limit: routeConfig.allowedPurposes,\n message: `Purpose \"${purpose}\" is not in the allowed list: [${routeConfig.allowedPurposes.join(', ')}]`,\n });\n }\n }\n\n // Check purpose against requiredPurposes (legacy field — agent must declare one of these)\n if (routeConfig.requiredPurposes && routeConfig.requiredPurposes.length > 0 && purpose) {\n if (!routeConfig.requiredPurposes.includes(purpose)) {\n failures.push({\n field: 'purpose',\n requested: purpose,\n limit: routeConfig.requiredPurposes,\n message: `Purpose \"${purpose}\" is not in the required list: [${routeConfig.requiredPurposes.join(', ')}]`,\n });\n }\n }\n\n // Check duration against maxDuration — range-check (unchanged; undefined =\n // no upper bound is conventional for opt-in range fields, not a request-\n // driven allow-list).\n if (routeConfig.maxDuration && astraCreds?.pdlss?.duration?.maxSessionDuration) {\n const requested = astraCreds.pdlss.duration.maxSessionDuration;\n if (requested > routeConfig.maxDuration) {\n failures.push({\n field: 'duration',\n requested,\n limit: routeConfig.maxDuration,\n message: `Requested duration ${requested}s exceeds maximum ${routeConfig.maxDuration}s`,\n });\n }\n }\n\n // Check jurisdiction against allowedJurisdictions. Same reasoning as\n // allowedPurposes above — route allow-lists are an optional per-route\n // refinement; undefined/empty = skip and defer to the backend evaluator.\n if (\n routeConfig.allowedJurisdictions &&\n routeConfig.allowedJurisdictions.length > 0 &&\n astraCreds?.pdlss?.scope?.jurisdiction\n ) {\n const requested = astraCreds.pdlss.scope.jurisdiction;\n if (!routeConfig.allowedJurisdictions.includes(requested)) {\n failures.push({\n field: 'jurisdiction',\n requested,\n limit: routeConfig.allowedJurisdictions,\n message: `Jurisdiction \"${requested}\" is not in the allowed list: [${routeConfig.allowedJurisdictions.join(', ')}]`,\n });\n }\n }\n\n return failures;\n}\n","/**\n * Maximal metadata capture — the shared, edge-safe sanitiser.\n *\n * AstraSync's thesis is total metadata capture: every header and connection\n * signal an inbound agent presents is a signal we want to keep. This module is\n * the ONE place that decides what is safe to store verbatim, what is a secret\n * to drop, and what credential headers reduce to a safe *format prefix* (a\n * platform signal, never the secret itself).\n *\n * It runs in three places that must agree byte-for-byte:\n * - the edge adapter (`@astrasyncai/adapter-lambda`) — the richest capture\n * point (full CloudFront header arrays),\n * - the SDK adapters (express / nextjs) — for SDK-only merchants with no edge,\n * - (indirectly) the backend, which stores whatever the above forward.\n *\n * Pure — no Node built-ins, no I/O — so it is safe in Lambda@Edge, the browser\n * build, and Deno. Capture is cheap: at the edge and SDK it is local string\n * work, and the backend stores it on a fire-and-forget event insert, so it adds\n * ZERO verify-access decision latency. Detection (which few signals imply which\n * vendor) is a separate, curated concern — see `platform-signatures.ts`.\n */\n\n/**\n * Version of the capture semantics (what is kept, dropped, reduced, or\n * derived — and under which key names).\n *\n * Capture semantics are FROZEN within a package major version: a given\n * `schemaVersion` always means the same field vocabulary and the same\n * keep/drop/reduce rules. The number bumps only on a SEMANTIC change to\n * capture (a renamed key, a changed reduction rule) — never for additive\n * signals, and never merely because the package version moved. To tell\n * builds apart, use the `sdkVersion` already present on the verify body;\n * `schemaVersion` answers the different question \"how do I interpret this\n * stored metadata?\".\n */\nexport const CAPTURE_SCHEMA_VERSION = 1;\n\n/**\n * The captured, sanitised view of an inbound agent's request metadata. Attached\n * to verify-access / beacon payloads as `callerMetadata.observedMetadata`.\n */\nexport interface ObservedMetadata {\n /** Header name → value, secrets removed, verbatim otherwise. */\n headers: Record<string, string>;\n /**\n * Safe key-format prefix of a credential header (e.g. `sk-ant-api03`,\n * `sk-proj`, `AIza`) — a platform signal, NEVER the secret. Absent if no\n * credential header was present or none matched a known format.\n */\n apiKeyFormat?: string;\n /**\n * The subset of `headers` that are known platform-signal headers\n * (`openai-organization`, `x-goog-user-project`, `anthropic-version`, …),\n * pulled out for convenient detection + display. Values are the same\n * sanitised strings as in `headers`.\n */\n platformHeaders?: Record<string, string>;\n /**\n * Connection-layer signals (IP, ASN, country, TLS version, HTTP version,\n * device class, TLS fingerprint). Edge adapters populate this from the\n * platform's native connection surface — the authoritative source. SDK\n * adapters populate it as a fallback via {@link deriveConnectionFromHeaders}\n * when a CDN in front of the merchant injected the equivalent headers;\n * absent when neither source had anything.\n */\n connection?: Record<string, string>;\n /**\n * Number of cookie pairs the caller sent. The `cookie` header VALUE is a\n * secret and is always dropped; the COUNT is a client-shape signal\n * (browsers carry cookies, most automation carries none) that would\n * otherwise be unobservable downstream. Absent when no cookie header\n * arrived.\n */\n cookieCount?: number;\n /**\n * Query-string parameter NAMES (deduped, lowercased) — values are NEVER\n * captured (they routinely carry OAuth codes, tokens, and PII, and no\n * deny-list is complete). Names alone fingerprint client shape. Populated\n * by the edge path, which sees the raw query string.\n */\n queryKeys?: string[];\n /**\n * Version of the capture semantics this object was produced under — see\n * {@link CAPTURE_SCHEMA_VERSION}. Optional for backward compatibility with\n * metadata captured before the field existed.\n */\n schemaVersion?: number;\n}\n\n/**\n * Result of sanitising a raw header map. `headers` is always present (possibly\n * empty); `apiKeyFormat` / `platformHeaders` only when a signal was found.\n */\nexport interface SanitizeHeadersResult {\n headers: Record<string, string>;\n apiKeyFormat?: string;\n platformHeaders?: Record<string, string>;\n /** Cookie-pair count; the cookie value itself is always dropped. */\n cookieCount?: number;\n}\n\n/**\n * Header names dropped entirely — genuine secrets or our own credentials that\n * describe the request's transport, not the agent. Matched case-insensitively\n * on the exact header name.\n */\nconst SECRET_HEADER_NAMES = new Set([\n 'cookie',\n 'set-cookie',\n 'x-csrf-token',\n 'proxy-authorization',\n 'x-astrasync-signature',\n 'x-astrasync-secret',\n 'x-hub-signature',\n 'x-hub-signature-256',\n // Short-lived verify dedupe token — must never persist in stored metadata.\n 'x-astra-verified-hop',\n]);\n\n/**\n * Header-name prefixes dropped entirely — our own credential / signing surface\n * (`x-astrasync-*`, `kya-*`) must never round-trip into stored metadata.\n */\nconst SECRET_HEADER_PREFIXES = ['x-astrasync-', 'kya-', 'kya_'];\n\n/**\n * Credential headers whose VALUE is a secret but whose FORMAT is a signal. We\n * keep the leading format prefix (up to the random tail) and drop the rest.\n */\nconst CREDENTIAL_HEADER_NAMES = new Set([\n 'authorization',\n 'x-api-key',\n 'x-goog-api-key',\n 'api-key',\n]);\n\n/**\n * Header names that carry a raw signature value (drop the value; the presence\n * is not worth a bloat risk). Matched as a suffix so `x-*-signature` variants\n * are covered without an exhaustive list.\n */\nfunction isSignatureHeader(name: string): boolean {\n return name === 'signature' || name.endsWith('-signature') || name.endsWith('-signature-256');\n}\n\n/**\n * Known platform-signal headers — pulled into `platformHeaders` for convenient\n * detection + display. Exact names plus a few prefixes (`x-goog-`,\n * `x-stainless-` — the OpenAI/Anthropic SDK client fingerprint headers).\n */\nconst PLATFORM_HEADER_NAMES = new Set([\n 'openai-organization',\n 'openai-project',\n 'openai-version',\n 'openai-processing-ms',\n 'anthropic-version',\n 'anthropic-beta',\n 'x-goog-user-project',\n 'x-goog-api-client',\n 'user-agent',\n 'x-agent-card-url',\n 'x-agent-provider',\n]);\n// `sec-ch-*` client hints are platform signals: Chromium forks (agentic\n// browsers included) often carry their real brand in `sec-ch-ua` even when\n// the UA string mimics stock Chrome.\nconst PLATFORM_HEADER_PREFIXES = [\n 'x-goog-',\n 'x-stainless-',\n 'x-anthropic-',\n 'x-openai-',\n 'sec-ch-',\n];\n\n/**\n * Known API-key format prefixes, longest-first so `sk-ant-api03` wins over\n * `sk-ant` and `sk-`. Each is the SAFE, non-secret leading token of a\n * credential; the random tail is never captured.\n */\nconst KEY_FORMAT_PREFIXES = [\n 'sk-ant-api03',\n 'sk-ant-api',\n 'sk-ant',\n 'sk-proj',\n 'sk-svcacct',\n 'sk-or-v1',\n 'sk-or',\n 'sk-lf',\n 'sk-',\n 'gsk_',\n 'aiza',\n 'ya29',\n 'ghp_',\n 'gho_',\n 'github_pat_',\n 'xai-',\n 'pplx-',\n 'r8_',\n 'hf_',\n 'astra-',\n 'astrae-',\n];\n\n/** Size caps — the only guard against jsonb bloat from a hostile POST. */\nexport const MAX_HEADERS = 64;\nexport const MAX_HEADER_VALUE_BYTES = 1024;\nexport const MAX_TOTAL_BYTES = 16 * 1024;\n\nfunction byteLength(s: string): number {\n // Edge-safe (no Buffer): count UTF-8 bytes without allocating a Buffer.\n let bytes = 0;\n for (let i = 0; i < s.length; i++) {\n const code = s.charCodeAt(i);\n if (code < 0x80) bytes += 1;\n else if (code < 0x800) bytes += 2;\n else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4;\n i++; // surrogate pair\n } else bytes += 3;\n }\n return bytes;\n}\n\n/**\n * Extract the safe key-format prefix from a credential header value. Strips a\n * leading `Bearer ` / `Basic ` scheme, then returns the longest known prefix\n * that the (lowercased) value starts with. Returns undefined for opaque values\n * (e.g. a bare UUID token) so we never guess a format we don't recognise.\n */\nexport function extractApiKeyFormat(rawValue: string): string | undefined {\n if (!rawValue) return undefined;\n let value = rawValue.trim();\n const spaceIdx = value.indexOf(' ');\n if (spaceIdx > 0) {\n const scheme = value.slice(0, spaceIdx).toLowerCase();\n if (scheme === 'bearer' || scheme === 'basic' || scheme === 'token') {\n value = value.slice(spaceIdx + 1).trim();\n }\n }\n const lower = value.toLowerCase();\n for (const prefix of KEY_FORMAT_PREFIXES) {\n if (lower.startsWith(prefix)) {\n // Return the prefix as-declared in the list (canonical casing).\n return prefix;\n }\n }\n return undefined;\n}\n\nfunction isSecretHeader(name: string): boolean {\n if (SECRET_HEADER_NAMES.has(name)) return true;\n if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;\n if (isSignatureHeader(name)) return true;\n return false;\n}\n\nfunction isPlatformHeader(name: string): boolean {\n if (PLATFORM_HEADER_NAMES.has(name)) return true;\n return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));\n}\n\n/**\n * Sanitise a raw header map for storage. Deny-lists genuine secrets, reduces\n * credential headers to a safe format prefix, keeps everything else verbatim,\n * and enforces the size caps that bound jsonb growth.\n *\n * Accepts any string→(string|string[]|undefined) map (Node's `req.headers`,\n * CloudFront's flattened headers, a plain object). Multi-value headers are\n * joined with `, ` per RFC 7230.\n */\nexport function sanitizeHeaders(\n raw: Record<string, string | string[] | undefined> | undefined | null\n): SanitizeHeadersResult {\n const headers: Record<string, string> = {};\n const platformHeaders: Record<string, string> = {};\n let apiKeyFormat: string | undefined;\n let cookieCount: number | undefined;\n let totalBytes = 0;\n let count = 0;\n\n if (!raw) return { headers };\n\n for (const rawName of Object.keys(raw)) {\n if (count >= MAX_HEADERS) break;\n const name = rawName.toLowerCase();\n const rawValue = raw[rawName];\n if (rawValue === undefined) continue;\n const joined = Array.isArray(rawValue) ? rawValue.join(', ') : String(rawValue);\n\n // Credential headers: capture the format prefix, drop the secret.\n if (CREDENTIAL_HEADER_NAMES.has(name)) {\n const fmt = extractApiKeyFormat(joined);\n if (fmt && !apiKeyFormat) apiKeyFormat = fmt;\n continue;\n }\n\n // Cookie: the value is a secret (dropped below), but the PAIR COUNT is a\n // client-shape signal worth keeping.\n if (name === 'cookie') {\n cookieCount = joined.split(';').filter((s) => s.trim().length > 0).length;\n }\n\n // Genuine secrets: drop entirely.\n if (isSecretHeader(name)) continue;\n\n // Everything else describing the agent: keep, bounded.\n let value = joined;\n if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {\n value = value.slice(0, MAX_HEADER_VALUE_BYTES);\n }\n const entryBytes = byteLength(name) + byteLength(value);\n if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;\n totalBytes += entryBytes;\n count++;\n headers[name] = value;\n if (isPlatformHeader(name)) platformHeaders[name] = value;\n }\n\n const result: SanitizeHeadersResult = { headers };\n if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;\n if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;\n if (cookieCount !== undefined) result.cookieCount = cookieCount;\n return result;\n}\n\n/**\n * Pull the known platform-signal headers out of an ALREADY-sanitised header\n * map. `sanitizeHeaders` already computes this as a by-product; this standalone\n * form is exported for call-sites (edge, tests) that hold a sanitised map and\n * want only the platform subset. Never re-run over raw (unsanitised) headers.\n */\nexport function extractPlatformHeaders(\n sanitized: Record<string, string> | undefined | null\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!sanitized) return out;\n for (const name of Object.keys(sanitized)) {\n if (isPlatformHeader(name.toLowerCase())) out[name.toLowerCase()] = sanitized[name];\n }\n return out;\n}\n\n/**\n * Precedence-ordered CDN header sources for each derived `connection` key.\n * First present header wins; the special `x-forwarded-for` source takes the\n * LEFTMOST (client) entry of the comma-separated chain.\n */\nconst CONNECTION_HEADER_SOURCES: ReadonlyArray<readonly [key: string, headers: readonly string[]]> =\n [\n ['ip', ['cf-connecting-ip', 'fastly-client-ip', 'true-client-ip', 'x-real-ip']],\n [\n 'country',\n ['cf-ipcountry', 'x-vercel-ip-country', 'cloudfront-viewer-country', 'fastly-geo-country'],\n ],\n ['region', ['x-vercel-ip-country-region', 'cloudfront-viewer-country-region']],\n ['countryRegionName', ['cloudfront-viewer-country-region-name']],\n ['city', ['x-vercel-ip-city', 'cloudfront-viewer-city']],\n ['latitude', ['x-vercel-ip-latitude', 'cloudfront-viewer-latitude']],\n ['longitude', ['x-vercel-ip-longitude', 'cloudfront-viewer-longitude']],\n ['postalCode', ['x-vercel-ip-postal-code', 'cloudfront-viewer-postal-code']],\n ['asn', ['cloudfront-viewer-asn']],\n ['tlsVersion', ['cloudfront-viewer-tls']],\n ['httpVersion', ['cloudfront-viewer-http-version']],\n ['timeZone', ['x-vercel-ip-timezone', 'cloudfront-viewer-time-zone']],\n ['metroCode', ['cloudfront-viewer-metro-code']],\n // TLS fingerprints can only be computed where TLS terminates. When a CDN\n // terminates TLS in front of the merchant, its fingerprint headers ARE the\n // connection-layer truth — normalising them here is the permanent design.\n // CloudFront delivers JA3/JA4 only via an origin request policy and only\n // for HTTPS viewer connections.\n ['tlsFingerprint', ['cf-ja3-hash', 'cloudfront-viewer-ja3-fingerprint']],\n ['ja4', ['cf-ja4', 'cloudfront-viewer-ja4-fingerprint']],\n // Header-structure fingerprint: browser/SDK-distinctive header ordering.\n ['headerOrder', ['cloudfront-viewer-header-order']],\n ['headerCount', ['cloudfront-viewer-header-count']],\n ];\n\n/**\n * Backend bound: observedMetadata.connection values longer than this fail\n * the platform's zod parse outright (boundedStringRecord(32, 256)), so every\n * emitter truncates — headerOrder routinely exceeds it.\n */\nexport const MAX_CONNECTION_VALUE_CHARS = 256;\n\n/**\n * Derive the connection-layer block from CDN-injected request headers.\n *\n * When a merchant's SDK-gated origin sits behind a CDN (Cloudflare, Fastly,\n * Vercel, CloudFront), the CDN has already seen the connection layer and\n * injected it as headers. This promotes those headers to the same\n * `connection` keys the edge adapters populate natively, so SDK-only\n * deployments still get IP / geo / TLS attribution. Precedence per key:\n *\n * - `ip`: `cf-connecting-ip` > `fastly-client-ip` > `true-client-ip` >\n * `x-real-ip` > `cloudfront-viewer-address` (port stripped) > leftmost\n * `x-forwarded-for`\n * - `country`: `cf-ipcountry` > `x-vercel-ip-country` >\n * `cloudfront-viewer-country` > `fastly-geo-country`\n * - `region` / `city` / `timeZone`: Vercel then CloudFront viewer headers\n * - `countryRegionName` / `asn` / `tlsVersion` / `httpVersion` /\n * `metroCode` / `headerOrder` / `headerCount`: `cloudfront-viewer-*`\n * - `tlsFingerprint`: `cf-ja3-hash` > `cloudfront-viewer-ja3-fingerprint`\n * - `ja4`: `cf-ja4` > `cloudfront-viewer-ja4-fingerprint`\n *\n * All keys are additive under `schemaVersion` 1 (the frozen-capture doctrine\n * bumps only for changed semantics, never for additive signals). Values are\n * truncated to MAX_CONNECTION_VALUE_CHARS — the platform's hard bound.\n *\n * Edge adapters keep their richer native collectors — native platform\n * signals are authoritative; this header derivation is the SDK-level\n * fallback. Header names are matched case-insensitively. Returns undefined\n * when no source header is present, so the `connection` key is simply\n * omitted (matching edge behaviour).\n */\nexport function deriveConnectionFromHeaders(\n headers: Record<string, string> | undefined | null\n): Record<string, string> | undefined {\n if (!headers) return undefined;\n const lower: Record<string, string> = {};\n for (const name of Object.keys(headers)) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) lower[name.toLowerCase()] = value;\n }\n\n const connection: Record<string, string> = {};\n for (const [key, sources] of CONNECTION_HEADER_SOURCES) {\n for (const source of sources) {\n const value = lower[source]?.trim();\n if (value) {\n connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);\n break;\n }\n }\n }\n // ip fallback 1: cloudfront-viewer-address arrives as ip:port — strip the\n // trailing port only (IPv6-safe), unlike the dedicated client-ip headers.\n // The port itself is kept as its own key: ephemeral-port patterns signal\n // NAT/proxy connection reuse.\n {\n const addr = lower['cloudfront-viewer-address']?.trim();\n const portMatch = addr?.match(/:(\\d+)$/);\n if (portMatch) connection.sourcePort = portMatch[1];\n if (!connection.ip && addr) connection.ip = addr.replace(/:\\d+$/, '');\n }\n // ip fallback 2: leftmost (client) hop of the x-forwarded-for chain.\n if (!connection.ip) {\n const xff = lower['x-forwarded-for'];\n const client = xff?.split(',')[0]?.trim();\n if (client) connection.ip = client;\n }\n // tlsCipher: CloudFront folds the cipher into the viewer-tls string\n // (`TLSv1.3:TLS_AES_128_GCM_SHA256:fullHandshake`). `tlsVersion` stays\n // verbatim (reducing it would be a semantic change → schema v2); the\n // cipher is pulled out additively so it is queryable on its own.\n if (!connection.tlsCipher) {\n const cipher = connection.tlsVersion?.split(':')[1];\n if (cipher) connection.tlsCipher = cipher;\n }\n\n return Object.keys(connection).length > 0 ? connection : undefined;\n}\n\n/**\n * The FULL metadata capture for one request at an SDK adapter (express /\n * nextjs / mcp): sanitised headers, the safe credential format prefix, the\n * platform-signal subset, the CDN-derived connection block, and the capture\n * schema version. This is the ONE builder all SDK adapters share, so their\n * verify-access bodies agree byte-for-byte.\n *\n * Connection derivation runs over the RAW header map (pre-cap) — the size\n * caps guard storage growth and must never hide a geo/IP header that\n * happened to arrive late in an oversized map.\n */\nexport function buildSdkObservedMetadata(\n rawHeaders: Record<string, string | string[] | undefined> | undefined | null\n): ObservedMetadata {\n const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);\n const flat: Record<string, string> = {};\n if (rawHeaders) {\n for (const name of Object.keys(rawHeaders)) {\n const value = rawHeaders[name];\n if (value === undefined) continue;\n flat[name.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value);\n }\n }\n const connection = deriveConnectionFromHeaders(flat);\n return {\n headers,\n ...(apiKeyFormat && { apiKeyFormat }),\n ...(platformHeaders && { platformHeaders }),\n ...(connection && { connection }),\n ...(cookieCount !== undefined && { cookieCount }),\n schemaVersion: CAPTURE_SCHEMA_VERSION,\n };\n}\n","/**\n * Edge verification config — the per-endpoint policy the Trusted Agent\n * Gateway edge adapters (e.g. `@astrasyncai/adapter-lambda`) fetch from the\n * AstraSync dashboard to decide how much verification friction to apply\n * to inbound traffic, and where.\n *\n * Fetch pattern mirrors `well-known.ts`: TTL cache + stale-while-revalidate\n * + in-flight dedupe, with a `_reset*` hook for tests. Fail posture is\n * deliberately asymmetric: this module can NEVER put a site into enforce\n * mode on its own — enforce only ever originates from a successfully\n * fetched config, and a config that has gone stale past `maxStaleMs`\n * degrades back to observe.\n *\n * Which EdgeConfig fields each integration consumes:\n *\n * | Field | Edge adapters | SDK adapters (express/nextjs/mcp) |\n * | ------------------------------ | ------------- | --------------------------------- |\n * | `mode` (observe/enforce) | yes | — |\n * | `depth` | yes | — |\n * | `pathRules` | yes | — |\n * | `sampling.anonymousBeaconRate` | yes | yes — the SDK anonymous beacon |\n * | `failurePosture` | yes | — |\n *\n * The observe/enforce × depth posture is EDGE-ONLY by design: SDK adapters\n * enforce via the dashboard route policy (`fetchRoutes`), not via this\n * config, and consume only the `sampling` block for their anonymous\n * traffic beacon.\n */\n\nimport { sdkFetch } from './http';\nimport type { GatewayConfig } from './types';\n\n/**\n * Edge posture. Canonical Trusted Agent Gateway vocabulary:\n * `observe` ≈ the gateway's `passive` posture (verify +\n * record, enforce nothing), `enforce` ≈ `active`. New value set on a new\n * field name — do NOT reuse `GatewayPosture`'s `active`/`passive` here\n * (different field, different meaning: posture governs an agent-side\n * gateway; mode governs counterparty-side edge interception).\n */\nexport type EdgeMode = 'observe' | 'enforce';\n\n/**\n * How deep the edge checks each request — what is it → who is it → are\n * they allowed:\n * - `classify` — UA / platform-fingerprint classification only; no\n * credential handling.\n * - `authenticate` — establish who is calling: detect and parse agent\n * credentials (X-Astra-*, VI SD-JWT, RFC 9421, ACP,\n * UCP, AP2…) and verify presented AstraSync identities.\n * - `authorize` — full policy decision: credentials cryptographically\n * proven and PDLSS-evaluated via a verify-access round\n * trip. (US spelling on the wire, matching\n * `authorizeSettlement` and HTTP `Authorization`.)\n */\nexport type EdgeVerificationDepth = 'classify' | 'authenticate' | 'authorize';\n\nexport interface EdgePathRule {\n /**\n * `*`-wildcard glob matched against the request path. Matching is\n * case-INsensitive and all regex metacharacters except `*` are\n * escaped. (Deliberately diverges from the express adapter's\n * `matchRoute`, which is historically case-sensitive by default —\n * new surface ships case-insensitive matching as the default.)\n */\n pattern: string;\n /** Pass the request through untouched (static assets); mode/depth ignored. */\n skip?: boolean;\n /** Override the top-level mode for this path. */\n mode?: EdgeMode;\n /** Override the top-level depth for this path. */\n depth?: EdgeVerificationDepth;\n}\n\nexport interface EdgeConfig {\n /** Shape version — bump on breaking changes. */\n version: 1;\n /** Default posture for paths no rule matches. */\n mode: EdgeMode;\n /** Default check depth for paths no rule matches. */\n depth: EdgeVerificationDepth;\n /** Ordered, first-match-wins. */\n pathRules: EdgePathRule[];\n sampling: {\n /** Fraction (0..1) of anonymous-bot requests that emit a beacon. */\n anonymousBeaconRate: number;\n };\n /**\n * 4.5.0: the EFFECTIVE failure posture is derived from the effective\n * mode — fail posture follows success posture. Observe fails open\n * (unreachable backend = pass-through, site never breaks); enforce fails\n * closed on verification-infrastructure failure (503\n * `VERIFICATION_UNAVAILABLE`, retry-later — see edge-core/pipeline). This\n * field is retained on the wire for adapter compatibility and as a future\n * explicit override; it is not consulted by the 4.5.x pipeline. Note the\n * distinction from CONFIG staleness: a config stale past 24h still has\n * enforce degraded to observe (`degradeToObserve`) — that is config-trust\n * hygiene, independent of runtime verification availability.\n */\n failurePosture: 'open' | 'closed';\n}\n\n/**\n * The safe default: observe-only, classification depth, nothing enforced.\n * Served by the backend when an endpoint has never been configured, and\n * used by `getEdgeConfig` whenever no config can be fetched.\n */\nexport const DEFAULT_EDGE_CONFIG: EdgeConfig = Object.freeze({\n version: 1,\n mode: 'observe',\n depth: 'classify',\n pathRules: [],\n sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),\n failurePosture: 'open',\n}) as EdgeConfig;\n\nconst EDGE_MODES: readonly string[] = ['observe', 'enforce'];\nconst EDGE_DEPTHS: readonly string[] = ['classify', 'authenticate', 'authorize'];\n\n/** Structural guard for configs arriving over the wire. */\nexport function isEdgeConfig(value: unknown): value is EdgeConfig {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Record<string, unknown>;\n if (v.version !== 1) return false;\n if (!EDGE_MODES.includes(v.mode as string)) return false;\n if (!EDGE_DEPTHS.includes(v.depth as string)) return false;\n if (!Array.isArray(v.pathRules)) return false;\n for (const rule of v.pathRules) {\n if (typeof rule !== 'object' || rule === null) return false;\n const r = rule as Record<string, unknown>;\n if (typeof r.pattern !== 'string' || r.pattern.length === 0) return false;\n if (r.mode !== undefined && !EDGE_MODES.includes(r.mode as string)) return false;\n if (r.depth !== undefined && !EDGE_DEPTHS.includes(r.depth as string)) return false;\n }\n const sampling = v.sampling as Record<string, unknown> | undefined;\n if (\n typeof sampling !== 'object' ||\n sampling === null ||\n typeof sampling.anonymousBeaconRate !== 'number' ||\n sampling.anonymousBeaconRate < 0 ||\n sampling.anonymousBeaconRate > 1\n ) {\n return false;\n }\n return v.failurePosture === 'open';\n}\n\nexport interface FetchEdgeConfigSuccess {\n edgeConfig: EdgeConfig;\n etag?: string;\n}\n\nexport type FetchEdgeConfigResult = FetchEdgeConfigSuccess | { notModified: true } | null;\n\n/**\n * Fetch the edge config for an endpoint from the AstraSync backend.\n * `GET {apiBaseUrl}/endpoints/:counterpartyId/edge-config` with the same\n * auth headers as `fetchRoutes`. Pass the cached `etag` to get a cheap\n * `{ notModified: true }` on 304. Returns `null` on any failure —\n * the caller decides how to fall back.\n */\nexport async function fetchEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { etag?: string; timeoutMs?: number }\n): Promise<FetchEdgeConfigResult> {\n if (!counterpartyId) return null;\n const headers: Record<string, string> = { Accept: 'application/json' };\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n headers['X-API-Key'] = config.apiKey;\n }\n if (opts?.etag) headers['If-None-Match'] = opts.etag;\n try {\n const response = await sdkFetch(\n `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,\n { method: 'GET', headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5000) }\n );\n if (response.status === 304) return { notModified: true };\n if (!response.ok) return null;\n const body = (await response.json()) as { data?: { edgeConfig?: unknown } };\n const edgeConfig = body.data?.edgeConfig;\n if (!isEdgeConfig(edgeConfig)) return null;\n return { edgeConfig, etag: response.headers.get('etag') ?? undefined };\n } catch {\n return null;\n }\n}\n\ninterface CacheEntry {\n config: EdgeConfig;\n etag?: string;\n /** When the entry was last confirmed fresh (fetch or 304). */\n lastSuccessAt: number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 1000;\nconst DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1000;\n\nconst cache = new Map<string, CacheEntry>();\nconst inflight = new Map<string, Promise<void>>();\n\nfunction cacheKey(apiBaseUrl: string, counterpartyId: string): string {\n return `${apiBaseUrl}|${counterpartyId}`;\n}\n\n/** Copy of `config` with every enforce (top-level and per-rule) degraded to observe. */\nexport function degradeToObserve(config: EdgeConfig): EdgeConfig {\n if (config.mode !== 'enforce' && !config.pathRules.some((r) => r.mode === 'enforce')) {\n return config;\n }\n return {\n ...config,\n mode: 'observe',\n pathRules: config.pathRules.map((r) => (r.mode === 'enforce' ? { ...r, mode: 'observe' } : r)),\n };\n}\n\nasync function revalidate(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string\n): Promise<void> {\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n const existing = inflight.get(key);\n if (existing) return existing;\n\n const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache.get(key)?.etag })\n .then((result) => {\n if (result === null) return; // failure — cache untouched, caller falls back\n const now = Date.now();\n if ('notModified' in result) {\n const entry = cache.get(key);\n if (entry) entry.lastSuccessAt = now;\n return;\n }\n cache.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });\n })\n .finally(() => {\n inflight.delete(key);\n });\n\n inflight.set(key, promise);\n return promise;\n}\n\n/**\n * Get the edge config for an endpoint, cached. Never throws, never blocks\n * longer than one fetch.\n *\n * - Fresh cache (within `ttlMs`) → cached config, no network.\n * - Stale cache → cached config immediately + background revalidate\n * (stale-while-revalidate). If the last successful fetch is older than\n * `maxStaleMs` (default 24h), any enforce is degraded to observe — a\n * long-dead backend can never keep a site enforcing.\n * - No cache → await one fetch; on failure return `DEFAULT_EDGE_CONFIG`\n * (observe-only). Defaults never enforce.\n */\nexport async function getEdgeConfig(\n config: Pick<GatewayConfig, 'apiBaseUrl' | 'apiKey'>,\n counterpartyId: string,\n opts?: { ttlMs?: number; maxStaleMs?: number }\n): Promise<EdgeConfig> {\n const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;\n const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;\n const key = cacheKey(config.apiBaseUrl, counterpartyId);\n\n const entry = cache.get(key);\n if (entry) {\n const age = Date.now() - entry.lastSuccessAt;\n if (age > ttlMs) {\n revalidate(config, counterpartyId).catch(() => {\n // background refresh failed — stale entry remains until next call\n });\n }\n return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;\n }\n\n await revalidate(config, counterpartyId).catch(() => {\n // fetch failed — fall through to defaults\n });\n return cache.get(key)?.config ?? DEFAULT_EDGE_CONFIG;\n}\n\n/**\n * First-match-wins path-rule lookup. Case-insensitive `*` globs with all\n * other regex metacharacters escaped (a literal `.` in a pattern matches\n * only `.`). Returns `undefined` when no rule matches — the caller applies\n * the config's top-level mode/depth.\n */\nexport function matchEdgePathRule(rules: EdgePathRule[], path: string): EdgePathRule | undefined {\n for (const rule of rules) {\n if (globToRegExp(rule.pattern).test(path)) return rule;\n }\n return undefined;\n}\n\nfunction globToRegExp(pattern: string): RegExp {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*');\n return new RegExp(`^${escaped}$`, 'i');\n}\n\n/** Reset cache — for testing only. */\nexport function _resetEdgeConfigCache(): void {\n cache.clear();\n inflight.clear();\n}\n","/**\n * Platform-agent fingerprint signatures — the shared registry of known\n * platform-agent UA / agent-card patterns (Claude / ChatGPT / Gemini /\n * Cursor / Goose).\n *\n * Single source of truth, lifted verbatim from the backend's\n * `platform-agent-detector.service` (which now imports detection from\n * here): the backend's verify-access anonymous handler and the edge\n * adapter (`@astrasyncai/adapter-lambda`) must classify identically or\n * the three-tier visibility numbers drift between capture points.\n *\n * Pure regex — no Node built-ins, edge-safe. Detection is regex-only for\n * v2.9 — TLS fingerprinting / behavioural signatures are deferred.\n */\n\nexport type PlatformAgentVendor =\n | 'claude'\n | 'chatgpt'\n | 'gemini'\n | 'cursor'\n | 'goose'\n | 'perplexity'\n | 'chatgpt-atlas'\n | 'perplexity-comet'\n | 'astrasync-sdk'\n | 'unknown';\n\nexport interface PlatformFingerprint {\n vendor: PlatformAgentVendor;\n /** A stable identifier used as the orphan-agent dedup key. */\n fingerprintKey: string;\n /** Human-readable name surfaced in the admin panel. */\n displayName: string;\n}\n\nexport interface PlatformDetectionInput {\n userAgent?: string;\n agentCardUrl?: string;\n /**\n * A safe API-key format prefix observed on the caller's\n * credential header (e.g. `sk-ant-api03`, `sk-proj`, `aiza`). A strong\n * platform signal; never the secret. Matched against `apiKeyFormatPatterns`.\n */\n apiKeyFormat?: string;\n /**\n * The sanitised platform-signal headers (lowercased names →\n * values), e.g. `openai-organization`, `x-goog-user-project`. Matched\n * against `headerPatterns` (which test on `name` and `name: value`).\n */\n platformHeaders?: Record<string, string>;\n /**\n * The caller's JA4 TLS-client fingerprint (from the connection capture).\n * Matched against `ja4Patterns`. A JA4 identifies the client TLS stack,\n * so signatures should pair it with other evidence when attributing a\n * vendor.\n */\n ja4?: string;\n /**\n * The caller's origin ASN (from the connection capture). Matched against\n * `asnList` by exact membership. An ASN alone attributes an entire cloud\n * provider — registry validation rejects ASN-only signatures.\n */\n asn?: string;\n}\n\n/**\n * A signature definition, generic over the vendor key. The seed constant\n * below uses the closed `PlatformAgentVendor` union; DB-promoted signatures\n * (backend dynamic registry, console round) carry arbitrary string vendors —\n * `matchPlatformSignature` accepts both.\n */\nexport interface PlatformSignatureDef<V extends string = string> {\n vendor: V;\n displayName: string;\n uaPatterns?: RegExp[];\n agentCardPatterns?: RegExp[];\n /**\n * Patterns tested against an observed API-key format prefix\n * (e.g. `/^sk-ant/i` → claude). A credential-header format is a stronger\n * platform signal than a spoofable User-Agent.\n */\n apiKeyFormatPatterns?: RegExp[];\n /**\n * Patterns tested against each observed platform-signal\n * header, as both `name` and `name: value` (so `/openai-organization/i` and\n * `/x-goog-user-project/i` match on presence).\n */\n headerPatterns?: RegExp[];\n /** Patterns tested against the observed JA4 TLS-client fingerprint. */\n ja4Patterns?: RegExp[];\n /** Exact ASN strings this signature matches (never regex). */\n asnList?: string[];\n}\n\n/**\n * A fingerprint whose vendor may be a dynamically-promoted (non-seed) key.\n * Structurally a superset of `PlatformFingerprint`.\n */\nexport interface DynamicPlatformFingerprint {\n vendor: string;\n fingerprintKey: string;\n displayName: string;\n}\n\n/**\n * Registry of known platform-agent signatures. Order matters — first match wins.\n *\n * Patterns are intentionally permissive (case-insensitive substring match) since\n * platform UA strings drift between versions. False positives are tolerable —\n * the orphan record is informational, not enforcement.\n */\nexport const PLATFORM_AGENT_SIGNATURES: ReadonlyArray<PlatformSignatureDef<PlatformAgentVendor>> = [\n {\n vendor: 'claude',\n displayName: 'Anthropic Claude',\n uaPatterns: [/claude/i, /anthropic/i],\n agentCardPatterns: [/anthropic\\.com/i, /claude\\.ai/i],\n apiKeyFormatPatterns: [/^sk-ant/i],\n headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i],\n },\n {\n vendor: 'chatgpt',\n displayName: 'OpenAI ChatGPT',\n uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\\d/i],\n agentCardPatterns: [/openai\\.com/i, /chatgpt\\.com/i],\n apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],\n headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i],\n },\n {\n vendor: 'gemini',\n displayName: 'Google Gemini',\n uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],\n agentCardPatterns: [/gemini\\.google\\.com/i, /ai\\.google\\.dev/i],\n apiKeyFormatPatterns: [/^aiza/i],\n headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i],\n },\n {\n vendor: 'cursor',\n displayName: 'Cursor',\n uaPatterns: [/cursor/i],\n agentCardPatterns: [/cursor\\.sh/i, /cursor\\.com/i],\n },\n {\n vendor: 'goose',\n displayName: 'Block Goose',\n uaPatterns: [/goose/i, /block-goose/i],\n agentCardPatterns: [/block\\.xyz\\/goose/i, /goose\\.tools/i],\n },\n {\n vendor: 'perplexity',\n displayName: 'Perplexity',\n uaPatterns: [/perplexity/i],\n agentCardPatterns: [/perplexity\\.ai/i],\n apiKeyFormatPatterns: [/^pplx-/i],\n },\n // Agentic browsers — versioned-token patterns ONLY (a stock Chrome UA must\n // never match). Distinct vendor keys (not 'chatgpt'/'perplexity'): the\n // browser product is a different surface than the assistant service, and\n // the DB registry mirrors one row per vendor. These sit after the primary\n // vendor entries so a UA carrying an explicit vendor token keeps its\n // primary attribution; a browser-shaped UA with the agentic token is\n // caught here BEFORE classify's human tier, which is what makes these\n // visits observable at all. Token drift is real (some builds mimic Chrome\n // outright) — re-verify against captured events when a new browser ships,\n // and check `sec-ch-ua` platformHeaders for the real brand.\n {\n vendor: 'chatgpt-atlas',\n displayName: 'ChatGPT Atlas browser',\n uaPatterns: [/\\batlas\\/\\d/i],\n headerPatterns: [/^sec-ch-ua: .*atlas/i],\n },\n {\n vendor: 'perplexity-comet',\n displayName: 'Perplexity Comet browser',\n uaPatterns: [/\\bcomet\\/\\d/i],\n headerPatterns: [/^sec-ch-ua: .*comet/i],\n },\n // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party\n // traffic must never pollute the unknown/anonymous pool it exists to audit.\n {\n vendor: 'astrasync-sdk',\n displayName: 'AstraSync SDK',\n uaPatterns: [/^astrasync-sdk\\//i],\n },\n];\n\n/**\n * Generic first-match-wins matcher over an arbitrary signature set. The\n * backend's dynamic registry merges the seed constant with DB-promoted\n * signatures and calls this — ONE matching implementation everywhere\n * (fingerprint-key rule included: vendor + lowercased UA basename before\n * the first space/slash, falling back to the agent-card host).\n */\nexport function matchPlatformSignature(\n signatures: ReadonlyArray<PlatformSignatureDef>,\n input: PlatformDetectionInput\n): DynamicPlatformFingerprint | undefined {\n const ua = input.userAgent ?? '';\n const cardUrl = input.agentCardUrl ?? '';\n const apiKeyFormat = input.apiKeyFormat ?? '';\n const ja4 = input.ja4 ?? '';\n const asn = input.asn ?? '';\n // Flatten platform headers to `name` and `name: value` lines for matching.\n const headerLines: string[] = [];\n if (input.platformHeaders) {\n for (const [name, value] of Object.entries(input.platformHeaders)) {\n headerLines.push(name, `${name}: ${value}`);\n }\n }\n\n for (const sig of signatures) {\n const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));\n const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));\n const keyMatch =\n apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));\n const headerMatch =\n headerLines.length > 0 &&\n sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));\n const ja4Match = ja4.length > 0 && sig.ja4Patterns?.some((p) => p.test(ja4));\n const asnMatch = asn.length > 0 && sig.asnList?.includes(asn);\n if (uaMatch || cardMatch || keyMatch || headerMatch || ja4Match || asnMatch) {\n const uaBase = ua.split(/[\\s/]/)[0]?.toLowerCase() ?? '';\n const cardHost = (() => {\n try {\n return cardUrl ? new URL(cardUrl).host : '';\n } catch {\n return '';\n }\n })();\n // Prefer a UA/card basename for the dedup key; fall back to the\n // credential format, then the connection fingerprint (still stable\n // per-vendor keys) when only a key/header/ja4/asn matched.\n const keyBasis =\n uaBase || cardHost || apiKeyFormat || ja4 || (asn && `asn${asn}`) || 'unknown';\n return {\n vendor: sig.vendor,\n fingerprintKey: `${sig.vendor}:${keyBasis}`,\n displayName: sig.displayName,\n };\n }\n }\n\n return undefined;\n}\n\n/**\n * Inspect caller metadata for a known SEED platform-agent fingerprint.\n * Returns undefined if no signature matches. (Backends with the dynamic\n * registry should call `matchPlatformSignature` over their merged set\n * instead — same semantics, live signature additions included.)\n */\nexport function detectPlatformFingerprint(\n input: PlatformDetectionInput\n): PlatformFingerprint | undefined {\n // Seed vendors are all members of the PlatformAgentVendor union, so the\n // narrowing cast is sound by construction.\n return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input) as\n | PlatformFingerprint\n | undefined;\n}\n","/**\n * Three-tier traffic classification (verified / identified-but-unregistered\n * / anonymous) plus the two non-tiers the gateway touches as little as\n * possible: `human` (zero network calls, zero logging) and `skipped`\n * (static assets / excluded paths).\n *\n * Cheapest checks first — the human path must add microseconds, not\n * milliseconds. Platform signatures are shared with the backend so the\n * edge and verify-access's anonymous handler classify identically.\n */\n\nimport { matchEdgePathRule, type EdgeConfig } from '../edge-config';\nimport { sanitizeHeaders } from '../metadata-capture';\nimport { detectPlatformFingerprint } from '../platform-signatures';\nimport { extractCredentials } from '../verify';\nimport { detectCommerce } from './detect';\nimport { headerValue } from './request';\nimport type { Classification, EffectivePolicy, NormalizedRequest } from './types';\n\n/** Extensions the gateway never classifies — static assets. */\nconst STATIC_EXTENSIONS =\n /\\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i;\n\n/**\n * AstraSync's own SDK traffic (`sdkFetch` stamps this UA on every outbound\n * SDK request). Whenever a deployment's API URL transits a gateway-fronted\n * distribution, the SDK's beacon/verify calls re-enter the gateway — and a\n * beacon that gets beaconed is a self-sustaining invocation loop (the 4.4.0\n * staging outage). Self-traffic is therefore a first-class tier: pass\n * through with ZERO beacons, verify calls, or logging, checked BEFORE the\n * credentials step (SDK verify calls carry a Bearer key and would otherwise\n * tier `verified` and re-enter at authenticate/authorize depth).\n *\n * Spoofing: a caller forging this UA gets pass-through — the same treatment\n * anonymous bots already get in both modes (they only dodge the sampled\n * anonymous beacon), and the origin's own auth still applies. No new bypass.\n */\nconst SELF_UA_PATTERN = /^astrasync-sdk\\//i;\n\n/** Non-browser, non-platform CLI/library UA tokens → anonymous bot. */\nconst BOT_UA_PATTERN =\n /curl|wget|python-requests|python-urllib|node-fetch|axios|got|okhttp|go-http-client|libwww|httpie|java\\/|ruby|php|scrapy|headless|phantomjs|selenium|playwright|puppeteer|bot|crawler|spider|slurp/i;\n\n/** Browser-shaped UA. */\nconst BROWSER_UA_PATTERN = /mozilla\\/\\d/i;\n\n/**\n * Resolve the effective mode/depth for a path from the EdgeConfig — ordered\n * first-match-wins rules with case-insensitive globs; no match falls through\n * to the config's top-level defaults. Static extensions are always skipped\n * regardless of rules (a rule can only skip MORE, never un-skip an asset).\n */\nexport function resolvePolicy(config: EdgeConfig, path: string): EffectivePolicy {\n if (STATIC_EXTENSIONS.test(path)) {\n return { mode: config.mode, depth: config.depth, skip: true };\n }\n const rule = matchEdgePathRule(config.pathRules, path);\n if (!rule) return { mode: config.mode, depth: config.depth, skip: false };\n return {\n mode: rule.mode ?? config.mode,\n depth: rule.depth ?? config.depth,\n skip: rule.skip === true,\n };\n}\n\n/**\n * Classify one request. Order (cheapest sufficient evidence wins):\n * 0. AstraSync SDK UA → `self` (own plumbing; never beaconed — loop-proof)\n * 1. X-Astra-* credentials → `verified` candidate\n * 2. commerce-protocol credentials on the wire → `identified`\n * 3. platform UA fingerprint (Claude/ChatGPT/Gemini/…) → `identified`\n * 4. bot-shaped UA / headerless non-browser → `anonymous-bot`\n * 5. everything browser-shaped → `human`\n *\n * `depth: 'classify'` skips step 2 (no body inspection, no header sniffing\n * beyond UA) — that is the zero-friction setting.\n */\nexport function classify(\n req: NormalizedRequest,\n host: string,\n depth: 'classify' | 'authenticate' | 'authorize'\n): Classification {\n const userAgent = headerValue(req, 'user-agent') ?? '';\n\n // 0. Our own SDK's outbound calls (beacons, verify-access, config\n // fetches). MUST precede the credentials check — see SELF_UA_PATTERN.\n if (SELF_UA_PATTERN.test(userAgent)) {\n return { tier: 'self' };\n }\n\n // 1. Native AstraSync credentials.\n const credentials = extractCredentials(req.headers, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { tier: 'verified', protocol: 'x-astra' };\n }\n\n // The key-format prefix + platform-signal headers are stronger,\n // less-spoofable platform signals than the UA. Compute once (cheap\n // string work) and feed every fingerprint call below.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);\n const detectionInput = { userAgent, apiKeyFormat, platformHeaders };\n\n // 2. Commerce-protocol credentials (skipped entirely at classify depth).\n if (depth !== 'classify') {\n const commerce = detectCommerce(req, host);\n if (commerce) {\n return {\n tier: 'identified',\n protocol: commerce.protocol,\n artifacts: commerce.artifacts,\n evidence: commerce.evidence,\n fingerprint: detectPlatformFingerprint(detectionInput),\n };\n }\n }\n\n // 3. Platform-agent fingerprint (UA, key-format, or platform header).\n const fingerprint = detectPlatformFingerprint(detectionInput);\n if (fingerprint) {\n return { tier: 'identified', protocol: 'platform-ua', fingerprint };\n }\n\n // 4. Bot-shaped: CLI/library UA, no UA at all, or any non-browser UA —\n // humans arrive with Mozilla-family UAs; everything else is automation.\n if (!userAgent || BOT_UA_PATTERN.test(userAgent) || !BROWSER_UA_PATTERN.test(userAgent)) {\n return { tier: 'anonymous-bot', evidence: { userAgent: userAgent || '(none)' } };\n }\n\n // 4b. Claims to be a browser but is missing every browser fetch-metadata\n // header — headless/spoofed. `sec-fetch-mode` is sent by all evergreen\n // browsers; its absence on a Mozilla UA is a strong bot signal.\n if (!headerValue(req, 'sec-fetch-mode') && !headerValue(req, 'accept-language')) {\n return { tier: 'anonymous-bot', evidence: { userAgent, spoofedBrowser: true } };\n }\n\n // 5. Human traffic — the gateway gets out of the way.\n return { tier: 'human' };\n}\n\n/** Exported for tests. */\nexport const _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN, SELF_UA_PATTERN };\n","/**\n * Time-budgeted event emission.\n *\n * Some edge runtimes (Lambda@Edge) have no background-work scheduler —\n * anything not awaited before the handler returns may never run. So every\n * telemetry call is awaited under an explicit budget and DROPPED on\n * timeout: latency to the customer's traffic is bounded, and a slow\n * AstraSync API costs telemetry, never page loads. Runtimes that provide\n * `waitUntil` (Cloudflare Workers, Vercel Edge, Fastly Compute) can pass\n * it via {@link EdgeCoreOptions.waitUntil} to take beacons off the latency\n * path entirely.\n */\n\nimport { reportUnregisteredAttempt } from '../verify';\nimport { buildObservedMetadata, headerValue } from './request';\nimport type { Classification, EdgeCoreOptions, NormalizedRequest } from './types';\n\n/** Await `promise` for at most `ms`; resolve `undefined` on timeout/error. */\nexport async function withBudget<T>(promise: Promise<T>, ms: number): Promise<T | undefined> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<undefined>((resolve) => {\n timer = setTimeout(() => resolve(undefined), ms);\n }),\n ]);\n } catch {\n return undefined;\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/**\n * Emit an unregistered-attempt beacon for `identified` (non-crypto depths)\n * and sampled `anonymous-bot` traffic. Unauthenticated by design; the\n * backend fingerprints the UA and find-or-provisions platform agents\n * server-side.\n */\nexport async function emitBeacon(\n options: EdgeCoreOptions,\n req: NormalizedRequest,\n classification: Classification,\n budgetMs: number\n): Promise<void> {\n const budgeted = withBudget(\n reportUnregisteredAttempt(\n { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },\n {\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: 'website',\n sourceIp: req.clientIp,\n userAgent: headerValue(req, 'user-agent'),\n requestPath: req.uri,\n requestMethod: req.method,\n // Evidence fields the backend persists into the event record.\n protocol: classification.protocol,\n evidence: classification.evidence,\n // The full sanitized header + connection capture for the\n // unregistered caller (fire-and-forget, so free).\n observedMetadata: buildObservedMetadata(req),\n }\n ),\n budgetMs\n );\n if (options.waitUntil) {\n options.waitUntil(budgeted);\n return;\n }\n await budgeted;\n}\n\n/** Deterministic-in-tests sampling gate. */\nexport function sampled(rate: number, random: () => number = Math.random): boolean {\n if (rate <= 0) return false;\n if (rate >= 1) return true;\n return random() < rate;\n}\n","/**\n * Anonymous-traffic beacon for the SDK middleware pass-through paths.\n *\n * When a request passes through UNGATED (no dashboard route matches it, or\n * the matching route is gated at `none`), no verify-access call happens and\n * the endpoint's dashboard is blind to that traffic. This module gives the\n * express/nextjs adapters the same lightweight visibility the edge adapters\n * already have: bot- and agent-shaped pass-through traffic emits a\n * fire-and-forget unregistered-attempt beacon, while human traffic and\n * static assets are never beaconed and credentialed agents are handled by\n * verify-access, not this beacon.\n *\n * Sampling is dashboard-driven: the endpoint's edge verification config\n * supplies `sampling.anonymousBeaconRate` (0 turns anonymous-bot sampling\n * off; platform-fingerprinted agents always beacon). Nothing here ever\n * waits on the request path — the beacon is never awaited, and the config\n * fetch runs in the background: until a config has arrived, no beacons are\n * sent. Merchants who must not emit any extra outbound calls can set\n * `anonymousBeacon: false` on the middleware options, which disables the\n * beacon (and its config fetch) entirely.\n */\n\nimport { _patterns } from '../edge-core/classify';\nimport { sampled } from '../edge-core/events';\nimport { getEdgeConfig, type EdgeConfig } from '../edge-config';\nimport { buildSdkObservedMetadata, sanitizeHeaders } from '../metadata-capture';\nimport { detectPlatformFingerprint } from '../platform-signatures';\nimport { extractCredentials, reportUnregisteredAttempt } from '../verify';\nimport type { GatewayConfig } from '../types';\n\n/** Raw (pre-sanitisation) header map as Node/Web adapters hold it. */\ntype RawHeaders = Record<string, string | string[] | undefined>;\n\nfunction readHeader(raw: RawHeaders, name: string): string | undefined {\n const value = raw[name];\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value[0];\n return undefined;\n}\n\n/**\n * How a pass-through request should be treated by the anonymous beacon:\n * - `never` — humans, static assets, and credentialed agents: no beacon.\n * - `platform` — a platform-fingerprinted agent (Claude/ChatGPT/Gemini/…):\n * beacon every time (unsampled) — these are exactly the\n * agents the dashboard's platform attribution exists for.\n * - `anonymous-bot` — non-browser automation with no platform signal:\n * beacon at the dashboard-configured sampling rate.\n */\nexport interface PassThroughTrafficClass {\n kind: 'never' | 'platform' | 'anonymous-bot';\n /** Detection protocol persisted with the beacon event. */\n protocol?: string;\n /** Light detection detail persisted with the beacon event. */\n evidence?: Record<string, unknown>;\n}\n\n/**\n * Classify one pass-through request for the anonymous beacon. Reuses the\n * edge classifier's heuristics (static-asset extensions, platform\n * fingerprints, browser-vs-bot UA shape) so the SDK and edge tiers agree on\n * what counts as agent traffic.\n */\nexport function classifyPassThroughTraffic(\n path: string,\n rawHeaders: RawHeaders\n): PassThroughTrafficClass {\n // Static assets: the beacon (like the gateway) gets out of the way.\n if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: 'never' };\n\n // Credentialed traffic is not anonymous — when a gated route sees these\n // credentials, verify-access records the caller; an unregistered-attempt\n // beacon would misfile it.\n const credentials = extractCredentials(rawHeaders, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { kind: 'never' };\n }\n\n const userAgent = readHeader(rawHeaders, 'user-agent') ?? '';\n\n // Platform-agent fingerprint (UA, credential key format, or a\n // platform-signal header) — a stronger, less-spoofable signal than the\n // UA alone, and it fires before the browser-shape check because several\n // platform agents present Mozilla-prefixed UAs.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);\n const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });\n if (fingerprint) {\n return {\n kind: 'platform',\n protocol: 'platform-ua',\n evidence: { vendor: fingerprint.vendor, userAgent: userAgent || '(none)' },\n };\n }\n\n // Bot-shaped: CLI/library UA, no UA at all, or any non-browser UA —\n // humans arrive with Mozilla-family UAs; everything else is automation.\n if (\n !userAgent ||\n _patterns.BOT_UA_PATTERN.test(userAgent) ||\n !_patterns.BROWSER_UA_PATTERN.test(userAgent)\n ) {\n return {\n kind: 'anonymous-bot',\n protocol: 'ua-heuristic',\n evidence: { userAgent: userAgent || '(none)' },\n };\n }\n\n // Claims to be a browser but sends none of the headers every evergreen\n // browser sends — headless/spoofed automation.\n if (!readHeader(rawHeaders, 'sec-fetch-mode') && !readHeader(rawHeaders, 'accept-language')) {\n return {\n kind: 'anonymous-bot',\n protocol: 'ua-heuristic',\n evidence: { userAgent, spoofedBrowser: true },\n };\n }\n\n // Human traffic — never beaconed, never logged.\n return { kind: 'never' };\n}\n\n/** Per-request input the middleware hands the beacon on a pass-through. */\nexport interface AnonymousBeaconInput {\n requestPath: string;\n requestMethod: string;\n /** Origin the SDK is protecting (auto-detected by the adapters). */\n counterpartyUrl?: string;\n /** Client IP as the adapter resolves it; falls back to X-Forwarded-For. */\n sourceIp?: string;\n rawHeaders: RawHeaders;\n}\n\n/** Fire-and-forget emitter — returns immediately, never throws. */\nexport type AnonymousBeaconEmitter = (input: AnonymousBeaconInput) => void;\n\n/**\n * Create the per-middleware-instance anonymous beacon.\n *\n * Requires a configured `counterpartyId` — sampling is a per-endpoint\n * dashboard setting and beacon events attribute to the endpoint; without\n * one, the returned emitter is a no-op.\n *\n * The emitter itself is synchronous: it classifies the request locally and\n * fire-and-forgets the report. The dashboard config is fetched in the\n * background (cached, stale-while-revalidate) and never awaited on the\n * request path; until the first config resolves, no beacons are emitted.\n */\nexport function createAnonymousBeacon(\n config: GatewayConfig,\n options?: {\n /** Counterparty type stamped on beacon events (adapter-specific default). */\n counterpartyType?: string;\n /** Injectable RNG for deterministic sampling in tests. */\n random?: () => number;\n }\n): AnonymousBeaconEmitter {\n const counterpartyId = config.counterpartyId;\n if (!counterpartyId) return () => {};\n\n const random = options?.random ?? Math.random;\n let edgeConfig: EdgeConfig | undefined;\n let refreshing = false;\n\n const refreshConfig = (): void => {\n if (refreshing) return;\n refreshing = true;\n getEdgeConfig(config, counterpartyId)\n .then((cfg) => {\n edgeConfig = cfg;\n })\n .catch(() => {})\n .finally(() => {\n refreshing = false;\n });\n };\n // Eager background fetch so early pass-through traffic already has a\n // sampling rate; requests arriving before it lands are simply not\n // beaconed (visibility is best-effort, latency is not negotiable).\n refreshConfig();\n\n return (input) => {\n try {\n // Keep the config fresh — getEdgeConfig serves its TTL cache and\n // revalidates in the background; this call is never awaited.\n refreshConfig();\n const cfg = edgeConfig;\n if (!cfg) return;\n\n const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);\n if (traffic.kind === 'never') return;\n if (traffic.kind === 'anonymous-bot' && !sampled(cfg.sampling.anonymousBeaconRate, random)) {\n return;\n }\n\n const userAgent = readHeader(input.rawHeaders, 'user-agent');\n const xff = input.rawHeaders['x-forwarded-for'];\n const xffStr = Array.isArray(xff) ? xff.join(', ') : xff;\n const sourceIp = input.sourceIp ?? xffStr?.split(',')[0]?.trim();\n\n reportUnregisteredAttempt(config, {\n ...(input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl }),\n counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? 'api',\n ...(sourceIp && { sourceIp }),\n ...(userAgent && { userAgent }),\n requestPath: input.requestPath,\n requestMethod: input.requestMethod,\n ...(traffic.protocol && { protocol: traffic.protocol }),\n ...(traffic.evidence && { evidence: traffic.evidence }),\n observedMetadata: buildSdkObservedMetadata(input.rawHeaders),\n }).catch(() => {});\n } catch {\n // The beacon must never break — or delay — the merchant's request.\n }\n };\n}\n","/**\n * AstraSync Universal Verification Gateway - Next.js Middleware\n *\n * Next.js middleware for verifying AI agents on web applications.\n * Serves the verification interstitial (an HTML overlay with registration\n * guidance) to unverified web-page traffic; API routes get structured JSON.\n *\n * @example\n * ```typescript\n * // middleware.ts\n * import { createMiddleware } from '@astrasyncai/verification-gateway/nextjs';\n *\n * export const middleware = createMiddleware({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * apiKey: process.env.ASTRASYNC_API_KEY,\n * counterpartyId: 'ASTRAE-...', // per-route policy is fetched from the dashboard\n * showInterstitial: true,\n * });\n *\n * export const config = {\n * matcher: ['/api/:path*', '/dashboard/:path*'],\n * };\n * ```\n */\n\nimport type { NextRequest } from 'next/server';\nimport type {\n NextJsMiddlewareOptions,\n AgentCredentials,\n VerificationResult,\n RouteAccessConfig,\n AstraSyncCredentials,\n VerificationRequest,\n StepUpOutcome,\n} from '../types';\nimport { awaitStepUpApproval } from './stepup-poll';\nimport { verify, reportCounterpartyPreCheckFailure, fetchRoutes } from '../verify';\nimport { extractHttpCredentials } from '../transport/http';\nimport { performCounterpartyPreCheck } from '../pdlss-pre-check';\nimport { buildSdkObservedMetadata } from '../metadata-capture';\nimport { createAnonymousBeacon } from './anonymous-beacon';\nimport { resolveHttpPdlss, type HttpPdlssResolution } from './http-pdlss';\nimport { requiresHumanApproval, annotateApprovalRequired } from './approval-gate';\nimport { MCP_VERIFIED_HOP_HEADER, parseVerifiedHop, isVerifiedHopValidFor } from '../verified-hop';\n\n/**\n * HTML-escape arbitrary string for safe interpolation into HTML text or\n * attribute values. Used by the interstitial HTML generator\n * to prevent reflected XSS from attacker-influenced denial messages.\n */\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Sanitize a URL for `href=`. Accepts only `http://` / `https://` schemes\n * (relative URLs allowed too); rejects `javascript:` / `data:` / `vbscript:`\n * and falls back to the supplied default on rejection. Then HTML-escapes\n * the result.\n */\nfunction sanitizeUrl(value: string | undefined, fallback: string): string {\n if (typeof value !== 'string' || value.length === 0) return escapeHtml(fallback);\n const trimmed = value.trim();\n if (/^javascript:|^data:|^vbscript:/i.test(trimmed)) return escapeHtml(fallback);\n if (/^https?:\\/\\//i.test(trimmed) || trimmed.startsWith('/')) {\n return escapeHtml(trimmed);\n }\n return escapeHtml(fallback);\n}\n\n/**\n * Extract credentials from Next.js request\n */\nfunction extractCredentialsFromNextRequest(request: NextRequest): AgentCredentials {\n const credentials: AgentCredentials = {};\n\n // Check for ASTRA-ID in headers\n const astraId = request.headers.get('x-astra-id') || request.headers.get('X-Astra-Id');\n if (astraId) {\n credentials.astraId = astraId;\n }\n\n // Check for API key\n const apiKey = request.headers.get('x-api-key') || request.headers.get('X-Api-Key');\n if (apiKey) {\n credentials.apiKey = apiKey;\n }\n\n // Check Authorization header\n const authHeader = request.headers.get('authorization');\n if (authHeader) {\n credentials.authorizationHeader = authHeader;\n if (authHeader.startsWith('Bearer ')) {\n credentials.jwt = authHeader.slice(7);\n }\n }\n\n // Check query parameters\n const url = new URL(request.url);\n const astraIdParam = url.searchParams.get('astraId');\n const apiKeyParam = url.searchParams.get('apiKey');\n\n if (astraIdParam && !credentials.astraId) {\n credentials.astraId = astraIdParam;\n }\n if (apiKeyParam && !credentials.apiKey) {\n credentials.apiKey = apiKeyParam;\n }\n\n return credentials;\n}\n\n/**\n * Match a route pattern against a path\n */\nfunction matchRoute(pattern: string, path: string): boolean {\n const regexPattern = pattern.replace(/\\*/g, '.*').replace(/\\//g, '\\\\/');\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(path);\n}\n\n/**\n * Find the route configuration for a request\n */\nfunction findRouteConfig(\n routes: RouteAccessConfig[],\n path: string,\n method: string\n): RouteAccessConfig | undefined {\n return routes.find((route) => {\n const methodMatches =\n route.method === '*' || route.method.toUpperCase() === method.toUpperCase();\n const pathMatches = matchRoute(route.pattern, path);\n return methodMatches && pathMatches;\n });\n}\n\n/**\n * Extract AstraSyncCredentials from Next.js request headers.\n * Returns null if no AstraSync headers are present.\n */\nfunction extractAstraSyncCredentialsFromNextRequest(\n request: NextRequest\n): AstraSyncCredentials | null {\n const headers: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return extractHttpCredentials(headers);\n}\n\n/**\n * Resolve the canonical {purpose, action} pair for a request.\n * Replaces the gen-1 method-inference (`read_data`/`write_data`) and the\n * hardwired verb action — the transport verb never travels as a PDLSS\n * action. Same resolver as the express adapter (http-pdlss.ts); nextjs has\n * no custom extractors and no query-param step (never existed here).\n */\nfunction resolveNextPdlss(\n request: NextRequest,\n routeConfig: { purpose?: string; action?: string } | null\n): HttpPdlssResolution {\n return resolveHttpPdlss({\n method: request.method,\n astraPurpose: request.headers.get('x-astra-purpose') ?? undefined,\n astraAction: request.headers.get('x-astra-action') ?? undefined,\n legacyPurpose: request.headers.get('x-purpose') ?? undefined,\n routePurpose: routeConfig?.purpose,\n routeAction: routeConfig?.action,\n });\n}\n\n/**\n * Generate the verification-interstitial HTML response served to unverified\n * web-page traffic.\n */\nfunction generateInterstitialHtml(\n result: VerificationResult,\n options: NextJsMiddlewareOptions\n): string {\n // result.guidance.message may quote attacker-controlled input from the\n // backend deny path (e.g. `Purpose \"<script>...\" is not in the allowed\n // list`). HTML-escape every interpolated value; validate URLs reject\n // non-http(s) schemes to prevent `javascript:` smuggling.\n const title = escapeHtml(options.commerceShield?.title || 'AstraSync Agent Verification');\n const message = escapeHtml(\n options.commerceShield?.message ||\n result.guidance?.message ||\n \"This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials.\"\n );\n const registrationUrl = sanitizeUrl(\n result.guidance?.registrationUrl,\n 'https://astrasync.ai/agents/register'\n );\n const docsUrl = sanitizeUrl(\n result.guidance?.documentationUrl,\n 'https://astrasync.ai/docs/agent-access'\n );\n const allowGuest = options.commerceShield?.allowGuestAccess ?? true;\n\n return `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${title}</title>\n <style>\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 20px;\n }\n .shield-container {\n background: rgba(255, 255, 255, 0.95);\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);\n max-width: 480px;\n width: 100%;\n padding: 40px;\n text-align: center;\n }\n .shield-icon {\n font-size: 48px;\n margin-bottom: 20px;\n }\n .shield-title {\n font-size: 24px;\n font-weight: 700;\n color: #1a1a2e;\n margin-bottom: 16px;\n }\n .shield-message {\n color: #4a5568;\n line-height: 1.6;\n margin-bottom: 24px;\n }\n .shield-steps {\n text-align: left;\n background: #f7fafc;\n border-radius: 8px;\n padding: 20px;\n margin-bottom: 24px;\n }\n .shield-steps h3 {\n font-size: 14px;\n font-weight: 600;\n color: #2d3748;\n margin-bottom: 12px;\n }\n .shield-steps ol {\n padding-left: 20px;\n color: #4a5568;\n }\n .shield-steps li {\n margin-bottom: 8px;\n }\n .shield-buttons {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n .btn {\n display: inline-block;\n padding: 14px 24px;\n border-radius: 8px;\n font-weight: 600;\n text-decoration: none;\n transition: all 0.2s;\n cursor: pointer;\n border: none;\n font-size: 16px;\n }\n .btn-primary {\n background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);\n color: white;\n }\n .btn-primary:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);\n }\n .btn-secondary {\n background: #e2e8f0;\n color: #4a5568;\n }\n .btn-secondary:hover {\n background: #cbd5e0;\n }\n .shield-footer {\n margin-top: 24px;\n font-size: 14px;\n color: #718096;\n }\n .shield-footer a {\n color: #6366f1;\n text-decoration: none;\n }\n .shield-footer a:hover {\n text-decoration: underline;\n }\n </style>\n</head>\n<body>\n <div class=\"shield-container\">\n <div class=\"shield-icon\">🛡️</div>\n <h1 class=\"shield-title\">${title}</h1>\n <p class=\"shield-message\">${message}</p>\n\n <div class=\"shield-steps\">\n <h3>To get verified access:</h3>\n <ol>\n <li>Register at <a href=\"${registrationUrl}\">astrasync.ai/agents/register</a></li>\n <li>Create and register your agent</li>\n <li>Add your ASTRA-ID to request headers</li>\n <li>Refresh this page</li>\n </ol>\n </div>\n\n <div class=\"shield-buttons\">\n <a href=\"${registrationUrl}\" class=\"btn btn-primary\">Register Now</a>\n ${allowGuest ? '<button onclick=\"window.location.reload()\" class=\"btn btn-secondary\">Continue as Guest (Limited)</button>' : ''}\n </div>\n\n <p class=\"shield-footer\">\n Learn more: <a href=\"${docsUrl}\">Agent Access Documentation</a>\n </p>\n </div>\n</body>\n</html>\n `.trim();\n}\n\nconst DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1000;\n\n/**\n * Create Next.js middleware for agent verification.\n *\n * v2.9.7 moved per-route policy out of merchant-side source code into the\n * AstraSync dashboard. The middleware fetches its routes from the backend\n * via `GET /endpoints/:counterpartyId/routes` on init and refreshes\n * periodically — see `ExpressMiddlewareOptions` for the rationale (a dual\n * config source silently conflicts with dashboard policy).\n */\nexport function createMiddleware(options: NextJsMiddlewareOptions) {\n // Guard against configs authored for pre-2.9.7 SDKs: a `routes` array in\n // merchant source is silently dead config — and dead route config means\n // the author believes paths are gated that aren't.\n if ('routes' in options) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway/Next.js] `routes` is dashboard-managed since v2.9.7; this option is ignored — ' +\n 'configure route policy in your AstraSync dashboard.'\n );\n }\n const {\n skipPaths = [],\n showInterstitial,\n showCommerceShield,\n enableRuntimeChallenge = true,\n routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,\n anonymousBeacon = true,\n trustVerifiedHop = false,\n verifiedHopMaxAgeMs,\n ...config\n } = options;\n\n // 4.1.0: `showInterstitial` supersedes the deprecated `showCommerceShield`\n // flag; the new name wins when both are set. Default remains true.\n const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;\n\n // Dashboard-driven anonymous-traffic beacon for the pass-through paths\n // (no matching route / route gated at `none`). Fire-and-forget: never\n // awaited, never delays the NextResponse. See ./anonymous-beacon.ts.\n const emitAnonymousBeacon = anonymousBeacon\n ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? 'website' })\n : undefined;\n const beaconPassThrough = emitAnonymousBeacon\n ? (request: NextRequest, pathname: string): void => {\n emitAnonymousBeacon({\n requestPath: pathname,\n requestMethod: request.method,\n counterpartyUrl: config.counterpartyUrl || request.nextUrl.origin,\n sourceIp: request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || undefined,\n rawHeaders: Object.fromEntries(request.headers.entries()),\n });\n }\n : undefined;\n\n let cachedRoutes: RouteAccessConfig[] = [];\n let lastFetchAt = 0;\n let refreshing: Promise<void> | null = null;\n let warnedNoCounterparty = false;\n\n async function refreshRoutes(): Promise<void> {\n if (!config.counterpartyId) {\n if (!warnedNoCounterparty) {\n // eslint-disable-next-line no-console\n console.warn(\n '[VerificationGateway/Next.js] No counterpartyId configured — falling through (allow all). ' +\n 'Per-route policy lives in the AstraSync dashboard now; register the endpoint and ' +\n 'set counterpartyId in your middleware config to enforce policy.'\n );\n warnedNoCounterparty = true;\n }\n return;\n }\n const fetched = await fetchRoutes(config, config.counterpartyId);\n if (fetched) {\n cachedRoutes = fetched;\n lastFetchAt = Date.now();\n }\n }\n\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n\n return async function middleware(request: NextRequest) {\n // Dynamic import NextResponse to avoid build issues\n const { NextResponse } = await import('next/server');\n\n const pathname = request.nextUrl.pathname;\n\n // Check if path should be skipped\n const shouldSkip = skipPaths.some((pattern) => matchRoute(pattern, pathname));\n if (shouldSkip) {\n return NextResponse.next();\n }\n\n if (refreshing) {\n await refreshing.catch(() => {});\n }\n if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {\n refreshing = refreshRoutes().finally(() => {\n refreshing = null;\n });\n }\n\n // Find route configuration (from remote-fetched cache)\n const routeConfig = findRouteConfig(cachedRoutes, pathname, request.method);\n\n // If no route config, allow through\n if (!routeConfig) {\n // Anonymous-traffic beacon: this request never reaches verify-access,\n // so bot/agent-shaped callers would otherwise be invisible to the\n // dashboard. Fire-and-forget — does not delay the response.\n beaconPassThrough?.(request, pathname);\n return NextResponse.next();\n }\n\n // Observe-only route: pass through unenforced.\n if (routeConfig.observe) {\n // Anonymous-traffic beacon (see the no-route-match branch above).\n beaconPassThrough?.(request, pathname);\n return NextResponse.next();\n }\n\n // Extract credentials\n const credentials = extractCredentialsFromNextRequest(request);\n\n // Inner-hop dedupe: a trusted upstream AstraSync hop (edge gateway or\n // MCP outer hop) already verified this exact ASTRA-id moments ago —\n // accept the fresh marker and skip the duplicate verify-access call.\n // Mirrors the express/MCP adapter contract. The marker must match the\n // request's own X-Astra-Id.\n if (trustVerifiedHop && credentials.astraId) {\n const marker = parseVerifiedHop(request.headers.get(MCP_VERIFIED_HOP_HEADER) ?? undefined);\n if (\n isVerifiedHopValidFor(marker, credentials.astraId, {\n ...(verifiedHopMaxAgeMs !== undefined ? { maxAgeMs: verifiedHopMaxAgeMs } : {}),\n })\n ) {\n return NextResponse.next();\n }\n }\n\n // v2.3.0: anonymous traffic no longer short-circuits client-side.\n // The server applies the endpoint's `unverifiedAgentPolicy` (deny /\n // allow_partial / allow_full) and emits the verification event +\n // blockchain record per the canonical flow. SDK forwards verbatim.\n\n // Auto-detect counterparty URL from the request if not explicitly configured.\n // Since the SDK is installed at this endpoint, we always know the origin.\n const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;\n\n // Resolve the canonical {purpose, action} pair (Bug 14, §4.6) and full\n // AstraSync credentials (includes PDLSS from X-Astra-* headers)\n const pdlssPair = resolveNextPdlss(request, routeConfig);\n const purpose = pdlssPair.purpose;\n if (config.debug) {\n // eslint-disable-next-line no-console\n console.debug('[nextjs-middleware] pdlss resolved', {\n purpose_source: pdlssPair.purposeSource,\n resolved_purpose: pdlssPair.purpose,\n action_source: pdlssPair.actionSource,\n resolved_action: pdlssPair.action,\n });\n }\n const astraCreds = extractAstraSyncCredentialsFromNextRequest(request);\n\n // Step 2: Counterparty-side PDLSS pre-check — compare agent's requested PDLSS\n // against counterparty-defined maximums on the route config.\n // Rejects immediately if outside limits, BEFORE calling verify-access.\n const preCheckFailures = performCounterpartyPreCheck(routeConfig, astraCreds, purpose);\n if (preCheckFailures.length > 0) {\n // Round-18 G4: counterparty pre-check failure — see express.ts for the\n // rationale. Neither axis verified remotely → both false.\n const preCheckResult: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: preCheckFailures.map((f) => f.message),\n guidance: {\n message: 'Request exceeds counterparty-defined PDLSS limits.',\n registrationUrl: `${config.apiBaseUrl?.replace('/api', '')}/agents/register`,\n documentationUrl: `${config.apiBaseUrl?.replace('/api', '')}/docs/pdlss`,\n },\n verifiedAt: new Date(),\n };\n\n // Fire-and-forget: notify AstraSync of the pre-check failure\n reportCounterpartyPreCheckFailure(config, {\n agentId: astraCreds?.agentId || credentials.astraId || 'unknown',\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'website',\n failures: preCheckFailures,\n requestPath: pathname,\n requestMethod: request.method,\n }).catch(() => {});\n\n // For API routes, return JSON\n if (pathname.startsWith('/api/')) {\n return NextResponse.json(\n {\n success: false,\n error: {\n code: 'PDLSS_PRE_CHECK_FAILED',\n message: preCheckResult.denialReasons?.[0] || 'PDLSS pre-check failed',\n guidance: preCheckResult.guidance,\n },\n },\n { status: 403 }\n );\n }\n\n // For web pages, show the verification interstitial\n if (interstitialEnabled) {\n return new NextResponse(generateInterstitialHtml(preCheckResult, options), {\n status: 200,\n headers: {\n 'Content-Type': 'text/html',\n 'X-AstraSync-Verification': 'commerce-shield',\n },\n });\n }\n\n return NextResponse.redirect(new URL('/unauthorized', request.url));\n }\n\n // Step 3: Call AstraSync verify-access with runtime challenge enabled\n const forwardedFor = request.headers.get('x-forwarded-for') || undefined;\n const originalClientIp = forwardedFor?.split(',')[0]?.trim();\n const verificationRequest: VerificationRequest = {\n credentials,\n purpose,\n action: pdlssPair.action,\n resource: pathname,\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'website',\n enableRuntimeChallenge,\n durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,\n callerMetadata: {\n sourceIp: originalClientIp,\n userAgent: request.headers.get('user-agent') || undefined,\n referer: request.headers.get('referer') || undefined,\n host: request.headers.get('host') || undefined,\n forwardedFor,\n agentCardUrl: request.headers.get('x-astrasync-agent-card') || undefined,\n // Workstream D — full sanitised header capture + CDN-derived\n // connection block (Web Headers → plain map).\n observedMetadata: buildSdkObservedMetadata(Object.fromEntries(request.headers.entries())),\n },\n };\n let result = await verify(config, verificationRequest);\n\n // 3.6.0 hold-and-poll (opt-in via stepUpMaxWaitMs) — see express.ts for\n // the full rationale. CAUTION on edge runtimes (~25s wall-clock budget):\n // set a small stepUpMaxWaitMs or gate in a Node route handler instead.\n // On 'approved' the same request is re-verified once, cache-bypassed, so\n // the backend redeems the single-use approval.\n let stepUpHoldOutcome: StepUpOutcome | undefined;\n if (\n config.stepUpMaxWaitMs !== undefined &&\n result.policyAllowed &&\n requiresHumanApproval(result) &&\n result.stepUpApproval?.pollUrl\n ) {\n stepUpHoldOutcome = await awaitStepUpApproval(config, result.stepUpApproval);\n if (stepUpHoldOutcome === 'approved') {\n result = await verify(config, verificationRequest, { bypassCache: true });\n } else {\n result.stepUpOutcome = stepUpHoldOutcome;\n }\n }\n\n // Round-18 G4: short-circuit on either axis failing (identity-fail or\n // policy-fail) — both encode the server-side trust-floor + PDLSS decision.\n // The access decision rests on a verified ID + runtime challenge + PDLSS\n // match + trust score; there is no access-level band (removed in SDK 5.0.0).\n // Per-route tightening is `route.minTrustScore` (below).\n // F2 direct-path fail-closed: a step-up / requires-approval outcome\n // (policyAllowed:true, allowed-but-escalate) cannot be completed\n // autonomously — deny and surface stepUpApproval polling info.\n // 4.5.0: gate on the SERVER decision only (`policyAllowed`) — anonymous\n // callers allowed by an audit/allow endpoint policy are honestly\n // identity-unverified; see express.ts for the full rationale.\n const approvalRequired = result.policyAllowed && requiresHumanApproval(result);\n if (approvalRequired) annotateApprovalRequired(result);\n\n if (!result.policyAllowed || approvalRequired) {\n // 4.0.0 BREAKING (API routes): this site's OWN key was rejected —\n // answer 503 with the dedicated code so agents don't read a merchant\n // misconfig as their own auth failure (see express.defaultOnDenied).\n // Web pages keep their existing shield/redirect flow — a human page\n // view must not turn into raw JSON because the operator rotated a key.\n if (result.misconfigured && pathname.startsWith('/api/')) {\n return NextResponse.json(\n {\n success: false,\n error: {\n code: 'MERCHANT_VERIFICATION_MISCONFIGURED',\n message:\n result.denialReasons?.[0] || \"This site's AstraSync integration is misconfigured\",\n guidance: result.guidance,\n failures: result.failures,\n correlationId: result.correlationId,\n },\n },\n { status: 503 }\n );\n }\n\n // For API routes, return JSON\n if (pathname.startsWith('/api/')) {\n return NextResponse.json(\n {\n success: false,\n error: {\n // Round-18 G4: 401 → identity missing (re-auth); 403 → identity\n // OK, policy denied (update PDLSS / step up).\n code: !result.identityVerified ? 'UNAUTHORIZED' : 'POLICY_DENIED',\n message: result.denialReasons?.[0] || 'Access denied',\n guidance: result.guidance,\n failures: result.failures,\n stepUpApproval: result.stepUpApproval,\n // 3.6.0: terminal outcome of an opt-in hold-and-poll wait.\n ...(result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }),\n },\n },\n {\n status: !result.identityVerified ? 401 : 403,\n ...(stepUpHoldOutcome && {\n headers: { 'X-Astra-Step-Up': stepUpHoldOutcome },\n }),\n }\n );\n }\n\n // For web pages, show the verification interstitial\n if (interstitialEnabled) {\n return new NextResponse(generateInterstitialHtml(result, options), {\n status: 200,\n headers: {\n 'Content-Type': 'text/html',\n 'X-AstraSync-Verification': 'commerce-shield',\n },\n });\n }\n\n // Redirect to unauthorized page\n return NextResponse.redirect(new URL('/unauthorized', request.url));\n }\n\n // All checks passed - continue with verification info in headers\n const response = NextResponse.next();\n\n // Add verification info to response headers\n // Round-18 G4: composite `verified` (identity AND policy) for legacy\n // header consumers; new headers expose each axis separately so middleware\n // chains can branch without re-running verify-access.\n response.headers.set(\n 'X-AstraSync-Verified',\n (result.identityVerified && result.policyAllowed).toString()\n );\n if (stepUpHoldOutcome) {\n response.headers.set('X-Astra-Step-Up', stepUpHoldOutcome);\n }\n response.headers.set('X-AstraSync-Identity-Verified', result.identityVerified.toString());\n response.headers.set('X-AstraSync-Policy-Allowed', result.policyAllowed.toString());\n\n if (result.agent) {\n response.headers.set('X-AstraSync-Agent-Id', result.agent.astraId);\n // 3.2.0 (post-3.1.0 feedback #2): the X-AstraSync-Trust-Score header is\n // no longer emitted — trust is a system-internal signal and this header\n // rode on the passthrough response toward the agent (gaming vector).\n }\n\n return response;\n };\n}\n\n/**\n * Helper to create matcher config\n */\nexport function createMatcherConfig(paths: string[]): { matcher: string[] } {\n return { matcher: paths };\n}\n","/**\n * AstraSync Universal Verification Gateway - SDK Adapter\n *\n * Direct SDK for verifying agents in any JavaScript/TypeScript environment.\n * Useful for agent-to-agent verification, serverless functions, or custom integrations.\n *\n * @example\n * ```typescript\n * import { createClient } from '@astrasyncai/verification-gateway/sdk';\n *\n * const gateway = createClient({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * });\n *\n * // Verify another agent before interacting\n * const result = await gateway.verify({\n * astraId: 'ASTRA-abc123',\n * purpose: 'data-exchange',\n * });\n *\n * if (result.identityVerified && result.policyAllowed) {\n * // Safe to interact with this agent\n * }\n * ```\n */\n\nimport type {\n SDKOptions,\n AgentCredentials,\n VerificationResult,\n VerificationRequest,\n GatewayConfig,\n} from '../types';\nimport { verify as coreVerify, quickVerify as coreQuickVerify, clearCache } from '../verify';\nimport { getTrustLevel } from '../trust-levels';\nimport { sdkFetch } from '../http';\n\n/**\n * Verification Gateway SDK Client\n */\nexport class VerificationGatewayClient {\n private config: GatewayConfig;\n private timeout: number;\n private retryConfig: { maxRetries: number; backoffMs: number };\n\n constructor(options: SDKOptions) {\n this.config = {\n apiBaseUrl: options.apiBaseUrl,\n apiKey: options.apiKey,\n minTrustScore: options.minTrustScore,\n minTrustScoreForFull: options.minTrustScoreForFull,\n cacheTtl: options.cacheTtl,\n debug: options.debug,\n customHeaders: options.customHeaders,\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: options.counterpartyType,\n // 5.4.1 (UAT2): previously dropped here despite being a typed, documented\n // GatewayConfig field — a client-driven confirmCheckout() could never\n // identify its endpoint by ASTRAE id, so merchants with multiple\n // endpoints on one origin (or a stale row sharing the URL) resolved\n // non-deterministically by URL and could miss the first-party gate.\n counterpartyId: options.counterpartyId,\n };\n\n this.timeout = options.timeout || 10000;\n this.retryConfig = options.retry || { maxRetries: 3, backoffMs: 1000 };\n }\n\n /**\n * Full verification with all details\n */\n async verify(options: {\n astraId?: string;\n apiKey?: string;\n jwt?: string;\n purpose?: string;\n action?: string;\n resourceType?: string;\n resource?: string;\n jurisdiction?: string;\n transactionValue?: number;\n currency?: string;\n isSubAgentRequest?: boolean;\n parentAgentId?: string;\n subAgentDepth?: number;\n counterpartyUrl?: string;\n counterpartyType?: string;\n }): Promise<VerificationResult> {\n const credentials: AgentCredentials = {\n astraId: options.astraId,\n apiKey: options.apiKey,\n jwt: options.jwt,\n };\n\n return this.executeWithRetry(() =>\n coreVerify(this.config, {\n credentials,\n purpose: options.purpose,\n action: options.action,\n resourceType: options.resourceType,\n resource: options.resource,\n jurisdiction: options.jurisdiction,\n transactionValue: options.transactionValue,\n currency: options.currency,\n isSubAgentRequest: options.isSubAgentRequest,\n parentAgentId: options.parentAgentId,\n subAgentDepth: options.subAgentDepth,\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: options.counterpartyType as VerificationRequest['counterpartyType'],\n })\n );\n }\n\n /**\n * 5.4.0 (astra-pay): confirm-leg of a checkout — the ONLY call that may fire\n * first-party charge-at-redeem (server-side settlement on the owner's saved\n * instrument). This is the supported public surface for the confirm leg;\n * `verify()` deliberately does not expose the checkout fields, so settlement\n * can never fire by accident from a generic verify.\n *\n * Sends `commercePhase: 'confirm'` plus the checkout session id (per-cart\n * idempotency) and line items (order/receipt plane), and identifies the\n * merchant via `counterpartyUrl`/`counterpartyType` (required — the backend\n * only settles a merchant-mediated grant against a first-party storefront).\n * `purpose`/`action` default to the canonical shopping pair.\n *\n * Returns the full `VerificationResult`: read `.settlementOutcome` for the\n * settled/failed/requires_action/no_instrument outcome (+ `orderId`), and the\n * identity/policy/`failures` fields for a denial. On any non-`confirm`/first-\n * party path `settlementOutcome` is simply absent — no money moves.\n *\n * 5.5.0 self-settling merchants (settlement_mode='self_settle'): the result\n * carries `.settlementToken` instead of a completed charge. Charge on your\n * own integration with Stripe idempotency key `voucher:<token.jti>` and\n * `metadata: { jti: token.jti, sessionId: token.sessionId }`, then call\n * `reportSettlement()` with the outcome. Treat any `settlementOutcome.status`\n * you don't recognize (e.g. `pending_merchant`) as PENDING, never failed.\n */\n async confirmCheckout(options: {\n astraId?: string;\n apiKey?: string;\n jwt?: string;\n purpose?: string;\n action?: string;\n transactionValue?: number;\n currency?: string;\n checkoutSessionId?: string;\n checkoutItems?: VerificationRequest['checkoutItems'];\n counterpartyUrl?: string;\n counterpartyType?: string;\n }): Promise<VerificationResult> {\n const credentials: AgentCredentials = {\n astraId: options.astraId,\n apiKey: options.apiKey,\n jwt: options.jwt,\n };\n\n return this.executeWithRetry(() =>\n coreVerify(\n this.config,\n {\n credentials,\n purpose: options.purpose ?? 'shopping',\n action: options.action ?? 'shopping.purchase',\n transactionValue: options.transactionValue,\n currency: options.currency,\n commercePhase: 'confirm',\n checkoutSessionId: options.checkoutSessionId,\n checkoutItems: options.checkoutItems,\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: options.counterpartyType as VerificationRequest['counterpartyType'],\n },\n // 5.4.1 (UAT2 Bug B): the confirm leg must always reach the backend —\n // a cached quote-leg grant carries no settlementOutcome and would\n // silently skip settlement.\n { bypassCache: true }\n )\n );\n }\n\n /**\n * 5.5.0 (astra-pay): report a self-settled charge outcome back to the\n * platform — the other half of the `settlementToken` contract. Call after\n * your PaymentIntent reaches a terminal state so the buyer's dashboard,\n * /orders and the agent's poll surface reconcile. Authenticated with this\n * client's api key (must be the merchant's own). Amounts must match the\n * order EXACTLY (integer minor units) or the report is rejected whole\n * (409 amount_mismatch). Replays of the same terminal state are safe.\n */\n async reportSettlement(options: {\n sessionId: string;\n status: 'settled' | 'declined' | 'failed';\n amountMinor: number;\n currency: string;\n /** Stripe PaymentIntent id — REQUIRED when status is 'settled'. */\n processorRef?: string;\n failureCode?: string;\n }): Promise<{ orderId: string; status: string; alreadySettled?: boolean }> {\n const base = this.config.apiBaseUrl.replace(/\\/+$/, '');\n const res = await sdkFetch(`${base}/merchant/settlements/report`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n // Same auth pair as every backend call the SDK makes (verify.ts).\n ...(this.config.apiKey\n ? { Authorization: `Bearer ${this.config.apiKey}`, 'X-API-Key': this.config.apiKey }\n : {}),\n },\n body: JSON.stringify(options),\n });\n const json = (await res.json().catch(() => ({}))) as {\n success?: boolean;\n data?: { orderId: string; status: string; alreadySettled?: boolean };\n error?: string;\n };\n if (!res.ok || !json.success || !json.data) {\n throw new Error(`reportSettlement failed (${res.status}): ${json.error ?? 'unknown error'}`);\n }\n return json.data;\n }\n\n /**\n * Quick verification — checks credentials and policy in one call.\n *\n * The return shape mirrors `VerificationResult`'s identity/policy\n * split. Map to HTTP status the same way: `!identityVerified` → 401,\n * `identityVerified && !policyAllowed` → 403.\n */\n async quickVerify(credentials: { astraId?: string; apiKey?: string; jwt?: string }): Promise<{\n identityVerified: boolean;\n policyAllowed: boolean;\n reason?: string;\n }> {\n return this.executeWithRetry(() => coreQuickVerify(this.config, credentials));\n }\n\n /**\n * Verify a specific ASTRA-ID\n */\n async verifyAstraId(\n astraId: string,\n options?: {\n purpose?: string;\n action?: string;\n }\n ): Promise<VerificationResult> {\n return this.verify({\n astraId,\n purpose: options?.purpose,\n action: options?.action,\n });\n }\n\n /**\n * Verify using an API key\n */\n async verifyApiKey(\n apiKey: string,\n options?: {\n purpose?: string;\n action?: string;\n }\n ): Promise<VerificationResult> {\n return this.verify({\n apiKey,\n purpose: options?.purpose,\n action: options?.action,\n });\n }\n\n /**\n * Clear the verification cache\n */\n clearCache(): void {\n clearCache();\n }\n\n /**\n * Execute a function with retry logic\n */\n private async executeWithRetry<T>(fn: () => Promise<T>): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {\n try {\n // Add timeout\n const result = await Promise.race([\n fn(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Request timeout')), this.timeout)\n ),\n ]);\n\n return result;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on last attempt\n if (attempt < this.retryConfig.maxRetries) {\n // Exponential backoff\n const backoff = this.retryConfig.backoffMs * Math.pow(2, attempt);\n await new Promise((resolve) => setTimeout(resolve, backoff));\n }\n }\n }\n\n throw lastError || new Error('Verification failed after retries');\n }\n}\n\n/**\n * Create a new SDK client\n */\nexport function createClient(options: SDKOptions): VerificationGatewayClient {\n return new VerificationGatewayClient(options);\n}\n\n/**\n * One-shot verification without creating a client\n */\nexport async function verifyOnce(\n options: SDKOptions & {\n astraId?: string;\n apiKey?: string;\n jwt?: string;\n purpose?: string;\n action?: string;\n }\n): Promise<VerificationResult> {\n const client = createClient(options);\n return client.verify(options);\n}\n\n// Re-export utilities for convenience\nexport { getTrustLevel };\n","/**\n * Cross-Protocol Transport Module\n *\n * Provides adapters for injecting/extracting AstraSync credentials\n * across HTTP, A2A, and MCP protocols.\n */\n\nimport type { AstraSyncCredentials, ProtocolTransport } from '../types';\nimport { setHttpHeaders, extractHttpCredentials } from './http';\nimport { setA2AMetadata, extractA2ACredentials } from './a2a';\nimport { setMcpMeta, extractMcpCredentials } from './mcp';\n\nexport { setHttpHeaders, extractHttpCredentials } from './http';\nexport { setA2AMetadata, extractA2ACredentials } from './a2a';\nexport { setMcpMeta, extractMcpCredentials } from './mcp';\n\n// Commerce protocol extractors + verifiers (PR 4+5)\nexport * from './purpose-mapping';\nexport * from './transaction-value';\nexport * from './rfc9421';\nexport * from './rfc9421-verify';\nexport * from './ucp';\nexport * from './acp';\nexport * from './vi';\nexport * from './stripe-webhook';\nexport * from './constraint-eval';\nexport * from './identity-binding';\nexport * from './ap2';\nexport * from './ap2-verify';\nexport * from './acp-verify';\nexport * from './mpp';\nexport * from './mpp-verify';\nexport * from './x402';\nexport * from './vi-verify';\nexport * from './commerce-pipeline';\nexport * from './extractor-registry';\nexport * from './registry/types';\nexport { createVisaRegistry } from './registry/visa';\nexport { createMastercardRegistry } from './registry/mastercard';\nexport { createWebBotAuthRegistry } from './registry/web-bot-auth';\n\n/**\n * Auto-detect protocol from request/context shape.\n */\nexport function detectProtocol(context: Record<string, unknown>): ProtocolTransport {\n // A2A: has metadata block with task-like structure\n if (context.metadata && typeof context.metadata === 'object') {\n return 'a2a';\n }\n\n // MCP: has _meta block (MCP convention)\n if (context._meta && typeof context._meta === 'object') {\n return 'mcp';\n }\n\n // Default to HTTP\n return 'http';\n}\n\n/**\n * Apply credentials to any protocol target.\n */\nexport function applyCredentials(\n protocol: ProtocolTransport,\n target: Record<string, unknown>,\n credentials: AstraSyncCredentials\n): Record<string, unknown> {\n switch (protocol) {\n case 'http':\n return setHttpHeaders(target as Record<string, string>, credentials);\n case 'a2a':\n return setA2AMetadata(target, credentials);\n case 'mcp':\n return setMcpMeta(target, credentials);\n default:\n return target;\n }\n}\n\n/**\n * Extract credentials from any protocol context.\n */\nexport function extractCredentialsFromProtocol(\n protocol: ProtocolTransport,\n context: Record<string, unknown>\n): AstraSyncCredentials | null {\n switch (protocol) {\n case 'http':\n return extractHttpCredentials(context as Record<string, string | string[] | undefined>);\n case 'a2a':\n return extractA2ACredentials(context);\n case 'mcp':\n return extractMcpCredentials(context);\n default:\n return null;\n }\n}\n","/**\n * A2A (Agent-to-Agent) Transport Adapter\n *\n * Maps AstraSync credentials to/from A2A task metadata.astrasync block.\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\ninterface A2ATask {\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface AstraSyncMetadata {\n agentId: string;\n verifyUrl?: string;\n challengeUrl?: string;\n purpose?: { category: string; action?: string };\n duration?: { maxSessionDuration?: number };\n scope?: { jurisdiction?: string };\n}\n\n/**\n * Add AstraSync credentials to an A2A task's metadata block.\n */\nexport function setA2AMetadata(\n task: A2ATask,\n credentials: AstraSyncCredentials,\n): A2ATask {\n const astrasync: AstraSyncMetadata = {\n agentId: credentials.agentId,\n };\n\n if (credentials.verifyUrl) astrasync.verifyUrl = credentials.verifyUrl;\n if (credentials.challengeUrl) astrasync.challengeUrl = credentials.challengeUrl;\n if (credentials.pdlss?.purpose) astrasync.purpose = credentials.pdlss.purpose;\n if (credentials.pdlss?.duration) astrasync.duration = credentials.pdlss.duration;\n if (credentials.pdlss?.scope) astrasync.scope = credentials.pdlss.scope;\n\n return {\n ...task,\n metadata: {\n ...task.metadata,\n astrasync,\n },\n };\n}\n\n/**\n * Extract AstraSync credentials from an A2A task's metadata block.\n */\nexport function extractA2ACredentials(task: A2ATask): AstraSyncCredentials | null {\n const meta = task.metadata?.astrasync as AstraSyncMetadata | undefined;\n if (!meta?.agentId) return null;\n\n const credentials: AstraSyncCredentials = {\n agentId: meta.agentId,\n };\n\n if (meta.verifyUrl) credentials.verifyUrl = meta.verifyUrl;\n if (meta.challengeUrl) credentials.challengeUrl = meta.challengeUrl;\n\n if (meta.purpose || meta.duration || meta.scope) {\n credentials.pdlss = {};\n if (meta.purpose) credentials.pdlss.purpose = meta.purpose;\n if (meta.duration) credentials.pdlss.duration = meta.duration;\n if (meta.scope) credentials.pdlss.scope = meta.scope;\n }\n\n return credentials;\n}\n","/**\n * MCP (Model Context Protocol) Transport Adapter\n *\n * Maps AstraSync credentials to/from MCP params._meta.astrasync block.\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\ninterface McpParams {\n _meta?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ninterface AstraSyncMeta {\n agentId: string;\n verifyUrl?: string;\n challengeUrl?: string;\n purpose?: { category: string; action?: string };\n duration?: { maxSessionDuration?: number };\n scope?: { jurisdiction?: string };\n}\n\n/**\n * Add AstraSync credentials to MCP params' _meta block.\n */\nexport function setMcpMeta(\n params: McpParams,\n credentials: AstraSyncCredentials,\n): McpParams {\n const astrasync: AstraSyncMeta = {\n agentId: credentials.agentId,\n };\n\n if (credentials.verifyUrl) astrasync.verifyUrl = credentials.verifyUrl;\n if (credentials.challengeUrl) astrasync.challengeUrl = credentials.challengeUrl;\n if (credentials.pdlss?.purpose) astrasync.purpose = credentials.pdlss.purpose;\n if (credentials.pdlss?.duration) astrasync.duration = credentials.pdlss.duration;\n if (credentials.pdlss?.scope) astrasync.scope = credentials.pdlss.scope;\n\n return {\n ...params,\n _meta: {\n ...params._meta,\n astrasync,\n },\n };\n}\n\n/**\n * Extract AstraSync credentials from MCP params' _meta block.\n */\nexport function extractMcpCredentials(params: McpParams): AstraSyncCredentials | null {\n const meta = params._meta?.astrasync as AstraSyncMeta | undefined;\n if (!meta?.agentId) return null;\n\n const credentials: AstraSyncCredentials = {\n agentId: meta.agentId,\n };\n\n if (meta.verifyUrl) credentials.verifyUrl = meta.verifyUrl;\n if (meta.challengeUrl) credentials.challengeUrl = meta.challengeUrl;\n\n if (meta.purpose || meta.duration || meta.scope) {\n credentials.pdlss = {};\n if (meta.purpose) credentials.pdlss.purpose = meta.purpose;\n if (meta.duration) credentials.pdlss.duration = meta.duration;\n if (meta.scope) credentials.pdlss.scope = meta.scope;\n }\n\n return credentials;\n}\n","/**\n * Protocol request -> AstraSync PDLSS purpose category mapping.\n *\n * Commerce purpose mapping table, extended with MPP + x402\n * entries (April 2026 protocol landscape).\n */\n\nexport type CommercePurpose =\n | 'commerce.checkout.create'\n | 'commerce.checkout.update'\n | 'commerce.checkout.confirm'\n | 'commerce.checkout.cancel'\n | 'commerce.payment.execute'\n | 'commerce.payment.stream'\n | 'commerce.delegation.intent'\n | 'commerce.delegation.checkout'\n | 'commerce.delegation.payment'\n | 'commerce.identity_probe'\n | 'commerce.browsing';\n\nconst UCP_ROUTES: Array<{ method: string; pattern: RegExp; purpose: CommercePurpose }> = [\n { method: 'POST', pattern: /^\\/checkout[-_]sessions\\/?$/, purpose: 'commerce.checkout.create' },\n {\n method: 'PUT',\n pattern: /^\\/checkout[-_]sessions\\/[^/]+\\/?$/,\n purpose: 'commerce.checkout.update',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout[-_]sessions\\/[^/]+\\/complete\\/?$/,\n purpose: 'commerce.payment.execute',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout[-_]sessions\\/[^/]+\\/cancel\\/?$/,\n purpose: 'commerce.checkout.cancel',\n },\n];\n\nconst ACP_ROUTES: Array<{ method: string; pattern: RegExp; purpose: CommercePurpose }> = [\n { method: 'POST', pattern: /^\\/checkout_sessions\\/?$/, purpose: 'commerce.checkout.create' },\n {\n method: 'POST',\n pattern: /^\\/checkout_sessions\\/[^/]+\\/?$/,\n purpose: 'commerce.checkout.update',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout_sessions\\/[^/]+\\/complete\\/?$/,\n purpose: 'commerce.payment.execute',\n },\n {\n method: 'POST',\n pattern: /^\\/checkout_sessions\\/[^/]+\\/cancel\\/?$/,\n purpose: 'commerce.checkout.cancel',\n },\n {\n method: 'POST',\n pattern: /^\\/agentic_commerce\\/delegate_payment\\/?$/,\n purpose: 'commerce.delegation.payment',\n },\n];\n\nexport function mapUCPRequestToPurpose(method: string, path: string): CommercePurpose | null {\n const normalizedMethod = method.toUpperCase();\n const normalizedPath = stripQuery(path);\n for (const route of UCP_ROUTES) {\n if (route.method === normalizedMethod && route.pattern.test(normalizedPath)) {\n return route.purpose;\n }\n }\n return null;\n}\n\nexport function mapACPRequestToPurpose(method: string, path: string): CommercePurpose | null {\n const normalizedMethod = method.toUpperCase();\n const normalizedPath = stripQuery(path);\n for (const route of ACP_ROUTES) {\n if (route.method === normalizedMethod && route.pattern.test(normalizedPath)) {\n return route.purpose;\n }\n }\n return null;\n}\n\nexport type AP2MandateType = 'intent_mandate' | 'cart_mandate' | 'payment_mandate';\nexport function mapAP2MandateToPurpose(mandateType: AP2MandateType): CommercePurpose {\n switch (mandateType) {\n case 'intent_mandate':\n return 'commerce.delegation.intent';\n case 'cart_mandate':\n return 'commerce.checkout.confirm';\n case 'payment_mandate':\n return 'commerce.payment.execute';\n }\n}\n\nexport type VIMandateType = 'checkout' | 'payment' | 'checkout.open' | 'payment.open';\nexport function mapVIMandateToPurpose(mandateType: VIMandateType): CommercePurpose {\n switch (mandateType) {\n case 'checkout':\n return 'commerce.checkout.confirm';\n case 'payment':\n return 'commerce.payment.execute';\n case 'checkout.open':\n return 'commerce.delegation.checkout';\n case 'payment.open':\n return 'commerce.delegation.payment';\n }\n}\n\nexport type RFC9421Tag = 'browse' | 'purchase' | undefined;\nexport function mapRFC9421TagToPurpose(tag: RFC9421Tag): CommercePurpose {\n if (tag === 'purchase') return 'commerce.payment.execute';\n return 'commerce.browsing';\n}\n\nexport type MPPIntent = 'charge' | 'session';\nexport function mapMPPRequestToPurpose(\n intent: MPPIntent | undefined,\n amount: number | undefined\n): CommercePurpose {\n if (typeof amount === 'number' && amount === 0) return 'commerce.identity_probe';\n if (intent === 'session') return 'commerce.payment.stream';\n return 'commerce.payment.execute';\n}\n\nexport function mapX402RequestToPurpose(amount: number | undefined): CommercePurpose {\n if (typeof amount === 'number' && amount === 0) return 'commerce.identity_probe';\n return 'commerce.payment.execute';\n}\n\nfunction stripQuery(path: string): string {\n const q = path.indexOf('?');\n return q === -1 ? path : path.slice(0, q);\n}\n\n/**\n * Informational Stripe webhook events surfaced as trust signals on\n * `CommerceContext.trustSignals` but NOT routed to a PDLSS purpose.\n */\nexport const STRIPE_WEBHOOK_INFORMATIONAL_EVENTS = [\n 'payment_intent.succeeded',\n 'payment_intent.payment_failed',\n 'charge.refunded',\n 'checkout.session.completed',\n 'customer.subscription.created',\n] as const;\nexport type StripeWebhookInformationalEvent = (typeof STRIPE_WEBHOOK_INFORMATIONAL_EVENTS)[number];\n\nexport function isStripeWebhookInformational(eventType: string): boolean {\n return (STRIPE_WEBHOOK_INFORMATIONAL_EVENTS as readonly string[]).includes(eventType);\n}\n","/**\n * Per-protocol transaction-value normalization.\n *\n * Each protocol encodes amount/currency differently. This module produces a\n * uniform `TransactionValueContext` with `source` recording the extraction\n * path so trace logs can show where the value came from.\n *\n * Amount unit: \"major units\" (dollars/euros/etc. for fiat; native unit for\n * tokens — we do NOT convert across currencies). UCP/ACP totals are in\n * cents, so we divide by 100. MPP/x402/VI pass through as declared.\n */\n\nexport interface TransactionValueContext {\n protocol: 'vi' | 'ap2' | 'ucp' | 'acp' | 'mpp' | 'x402' | 'agentpay' | 'tap';\n amount: number;\n currency: string;\n source: string;\n /** When true, the amount is in raw atomic/minor units and could NOT be\n * converted to major units (unknown token decimals). The limit engine\n * must fail-closed — never compare raw units against major-unit limits. */\n rawUnits?: boolean;\n}\n\nexport function extractUCPTransactionValue(input: {\n totals?: Array<{ type?: string; amount?: number; currency?: string }>;\n}): TransactionValueContext | null {\n const totals = input.totals ?? [];\n const total = totals.find((t) => t.type === 'total') ?? totals[0];\n if (!total || typeof total.amount !== 'number' || !total.currency) return null;\n return {\n protocol: 'ucp',\n amount: total.amount / 100,\n currency: total.currency,\n source: `totals[type=${total.type ?? 'unknown'}].amount`,\n };\n}\n\nexport function extractACPTransactionValue(input: {\n totals?: Array<{ type?: string; amount?: number; currency?: string }>;\n}): TransactionValueContext | null {\n const totals = input.totals ?? [];\n const total = totals.find((t) => t.type === 'total') ?? totals[0];\n if (!total || typeof total.amount !== 'number' || !total.currency) return null;\n return {\n protocol: 'acp',\n amount: total.amount / 100,\n currency: total.currency,\n source: `totals[type=${total.type ?? 'unknown'}].amount`,\n };\n}\n\nexport interface VIClaimsForValue {\n constraints?: {\n paymentAmount?: { currency?: string; min?: number; max?: number };\n };\n l3aPaymentAmount?: { currency?: string; amount?: number };\n}\n\nexport function extractVITransactionValue(\n claims: VIClaimsForValue\n): TransactionValueContext | null {\n const l3a = claims.l3aPaymentAmount;\n if (l3a && typeof l3a.amount === 'number' && l3a.currency) {\n return {\n protocol: 'vi',\n amount: l3a.amount,\n currency: l3a.currency,\n source: 'L3a.payment.amount',\n };\n }\n const bound = claims.constraints?.paymentAmount;\n if (bound && typeof bound.max === 'number' && bound.currency) {\n return {\n protocol: 'vi',\n amount: bound.max,\n currency: bound.currency,\n source: 'L2.payment.constraints.amount.max',\n };\n }\n return null;\n}\n\nexport interface AP2PaymentMandateForValue {\n payment_details_total?: { amount?: { value?: string | number; currency?: string } };\n}\n\nexport function extractAP2TransactionValue(\n mandate: AP2PaymentMandateForValue | undefined\n): TransactionValueContext | null {\n const amt = mandate?.payment_details_total?.amount;\n if (!amt || !amt.currency) return null;\n const n = typeof amt.value === 'string' ? Number(amt.value) : amt.value;\n if (typeof n !== 'number' || !Number.isFinite(n)) return null;\n return {\n protocol: 'ap2',\n amount: n,\n currency: amt.currency,\n source: 'payment_mandate.payment_details_total.amount',\n };\n}\n\nexport interface MPPChallengeForValue {\n method?: string;\n request?: { amount?: number; currency?: string } & Record<string, unknown>;\n}\n\nexport function extractMPPTransactionValue(\n challenge: MPPChallengeForValue\n): TransactionValueContext | null {\n const req = challenge.request;\n if (!req || typeof req.amount !== 'number' || !req.currency) return null;\n return {\n protocol: 'mpp',\n amount: req.amount,\n currency: req.currency,\n source: `challenge.request.amount (method=${challenge.method ?? 'unknown'})`,\n };\n}\n\nexport interface X402RequestForValue {\n maxAmountRequired?: number;\n amount?: number;\n asset?: string;\n currency?: string;\n}\n\nconst KNOWN_TOKEN_DECIMALS: Record<string, number> = {\n USDC: 6,\n USDT: 6,\n DAI: 18,\n ETH: 18,\n WETH: 18,\n};\n\nexport function extractX402TransactionValue(\n req: X402RequestForValue\n): TransactionValueContext | null {\n const rawAmount = req.maxAmountRequired ?? req.amount;\n const currency = req.currency ?? req.asset;\n if (typeof rawAmount !== 'number' || !currency) return null;\n const source = req.maxAmountRequired !== undefined ? 'maxAmountRequired' : 'amount';\n\n const decimals = KNOWN_TOKEN_DECIMALS[currency.toUpperCase()];\n if (decimals !== undefined) {\n return {\n protocol: 'x402',\n amount: rawAmount / Math.pow(10, decimals),\n currency,\n source,\n };\n }\n\n return {\n protocol: 'x402',\n amount: rawAmount,\n currency,\n source,\n rawUnits: true,\n };\n}\n","/**\n * RFC 9421 HTTP Message Signatures parser.\n *\n * Wraps `structured-headers` (transitive dep of http-message-signatures) to\n * parse the Signature-Input and Signature Dictionary headers per RFC 9421\n * Section 2.\n *\n * Produces structured metadata (kid, algorithm, covered components, tag,\n * created/expires/nonce, signature bytes) without verifying the signature —\n * verification lives in rfc9421-verify.ts.\n *\n * Shared by:\n * - Agent Pay (Mastercard) — kid resolves via Mastercard Agent Registry\n * - TAP (Visa) — kid resolves via Visa JWKS\n * - Web Bot Auth (generic transport substrate) — kid resolves via\n * /.well-known/http-message-signatures-directory\n */\n\nimport { parseDictionary } from 'structured-headers';\n\nexport interface RFC9421SignatureParams {\n /** The label identifying the signature in the Dictionary header (e.g. \"sig1\"). */\n label: string;\n /** Key ID used to look up the verifying key in the relevant registry. */\n kid: string;\n /** Algorithm declared in the Signature-Input params (e.g. \"ecdsa-p256-sha256\", \"ed25519\"). */\n alg?: string;\n /** Covered components, in order, per RFC 9421 Section 2.1. */\n covered: string[];\n /** Base64url-encoded signature bytes extracted from the paired Signature header. */\n signatureBase64: string;\n /** Unix seconds when the signature was created. */\n created?: number;\n /** Unix seconds when the signature expires. */\n expires?: number;\n /** Nonce (opaque string) for replay protection. */\n nonce?: string;\n /** Tag parameter. For Agent Pay/TAP this is \"browse\" or \"purchase\"; undefined otherwise. */\n tag?: 'browse' | 'purchase' | string;\n}\n\nexport interface ParsedRFC9421 {\n signatures: RFC9421SignatureParams[];\n}\n\n/**\n * Parse the RFC 9421 Signature-Input and Signature headers from a request or response.\n * Returns all signatures present (a single message may carry multiple labelled signatures).\n *\n * Returns null if either header is missing or malformed.\n */\nexport function parseRFC9421(\n headers: Record<string, string | string[] | undefined>\n): ParsedRFC9421 | null {\n const sigInput = readHeader(headers, 'signature-input');\n const sig = readHeader(headers, 'signature');\n if (!sigInput || !sig) return null;\n\n let inputDict;\n let sigDict;\n try {\n inputDict = parseDictionary(sigInput);\n sigDict = parseDictionary(sig);\n } catch {\n return null;\n }\n\n const signatures: RFC9421SignatureParams[] = [];\n\n for (const [label, entry] of inputDict) {\n // entry.value is the inner list of covered components; entry[1] is the params Map.\n const innerList = Array.isArray(entry)\n ? entry[0]\n : (entry as { value?: unknown; params?: unknown }).value;\n const params = Array.isArray(entry)\n ? entry[1]\n : (entry as { value?: unknown; params?: unknown }).params;\n if (!Array.isArray(innerList) || !params) continue;\n\n const covered: string[] = [];\n for (const item of innerList as Array<[unknown, Map<string, unknown>]>) {\n const [bare] = Array.isArray(item) ? item : [item];\n if (typeof bare === 'string') covered.push(bare);\n else if (bare && typeof bare === 'object' && 'toString' in bare) covered.push(String(bare));\n }\n\n const paramsMap = params as Map<string, unknown>;\n const kid = coerceString(paramsMap.get('keyid'));\n if (!kid) continue;\n\n const sigEntry = sigDict.get(label);\n if (!sigEntry) continue;\n\n const sigBare = Array.isArray(sigEntry) ? sigEntry[0] : (sigEntry as { value?: unknown }).value;\n const signatureBase64 = extractBase64(sigBare);\n if (!signatureBase64) continue;\n\n signatures.push({\n label,\n kid,\n alg: coerceString(paramsMap.get('alg')),\n covered,\n signatureBase64,\n created: coerceNumber(paramsMap.get('created')),\n expires: coerceNumber(paramsMap.get('expires')),\n nonce: coerceString(paramsMap.get('nonce')),\n tag: coerceString(paramsMap.get('tag')),\n });\n }\n\n if (signatures.length === 0) return null;\n return { signatures };\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | null {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw.join(', ');\n return null;\n }\n }\n return null;\n}\n\nfunction coerceString(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (value == null) return undefined;\n if (typeof value === 'object' && 'toString' in (value as object)) {\n const s = String(value);\n return s.length > 0 ? s : undefined;\n }\n return undefined;\n}\n\nfunction coerceNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'bigint') return Number(value);\n return undefined;\n}\n\nfunction extractBase64(value: unknown): string | null {\n if (value instanceof Uint8Array) return bufferToBase64(value);\n if (value instanceof ArrayBuffer) return bufferToBase64(new Uint8Array(value));\n if (ArrayBuffer.isView(value)) {\n const v = value as ArrayBufferView;\n return bufferToBase64(new Uint8Array(v.buffer, v.byteOffset, v.byteLength));\n }\n if (typeof value === 'string') {\n if (value.startsWith(':') && value.endsWith(':')) return value.slice(1, -1);\n return value;\n }\n return null;\n}\n\nfunction bufferToBase64(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString('base64');\n}\n","/**\n * RFC 9421 HTTP Message Signatures verification.\n *\n * Wraps http-message-signatures (dhensby) verifyMessage() with a RegistryResolver\n * hook for kid → JWK lookup. Library handles canonicalization + ES256/EdDSA/\n * HMAC/RSA verification; we supply the key-finding callback and policy around\n * clock skew.\n *\n * Shared by:\n * - Agent Pay (Mastercard) — resolver = createMastercardRegistry\n * - TAP (Visa) — resolver = createVisaRegistry\n * - Web Bot Auth (generic) — resolver = createWebBotAuthRegistry\n */\n\nimport { httpbis, type VerifierFinder, type VerifyingKey } from 'http-message-signatures';\nimport type { JWK } from 'jose';\nimport type { RegistryResolver } from './registry/types';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface RFC9421VerifyRequest {\n method: string;\n url: string;\n headers: Record<string, string | string[]>;\n body?: string;\n}\n\nexport interface RFC9421VerifyOptions {\n resolver: RegistryResolver;\n /** Seconds of tolerance around created/expires. Default 60 (tightened from 300). */\n clockSkewSec?: number;\n /** Injectable for deterministic tests. */\n now?: () => number;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface RFC9421VerifyResult {\n ok: boolean;\n kid?: string;\n registry?: RegistryResolver['name'];\n algorithm?: string;\n error?: string;\n}\n\nexport async function verifyRFC9421(\n request: RFC9421VerifyRequest,\n options: RFC9421VerifyOptions\n): Promise<RFC9421VerifyResult> {\n const { resolver } = options;\n const tolerance = options.clockSkewSec ?? 60;\n const nowSec = options.now ? options.now() : Math.floor(Date.now() / 1000);\n const nonceStore = options.nonceStore ?? defaultNonceStore;\n\n let resolvedKid: string | undefined;\n let resolvedAlg: string | undefined;\n let replayDetected = false;\n\n const keyLookup: VerifierFinder = async (parameters) => {\n const kid = typeof parameters.keyid === 'string' ? parameters.keyid : undefined;\n if (!kid) return null;\n resolvedKid = kid;\n const alg = typeof parameters.alg === 'string' ? parameters.alg : undefined;\n if (alg) resolvedAlg = alg;\n\n const origin = safeOrigin(request.url);\n const jwk = await resolver.resolve(kid, { origin, algorithm: alg });\n if (!jwk) return null;\n\n // Check clock-skew on this specific signature's created/expires.\n // SignatureParameters may carry Date, number, or ISO string per library.\n const created = toUnixSeconds(parameters.created);\n const expires = toUnixSeconds(parameters.expires);\n if (created !== undefined && Math.abs(nowSec - created) > tolerance) return null;\n if (expires !== undefined && nowSec > expires + tolerance) return null;\n\n // Audit F-A1-05: replay protection. RFC 9421 signatures include a\n // `nonce` parameter (optional but recommended for replay-sensitive\n // contexts). When present, register kid+nonce; reject duplicates\n // within the expiry window.\n const nonce = typeof parameters.nonce === 'string' ? parameters.nonce : undefined;\n if (nonce) {\n const expiresAtMs = (expires !== undefined ? expires + tolerance : nowSec + tolerance) * 1000;\n if (nonceStore.seen(`rfc9421:${kid}:${nonce}`, expiresAtMs)) {\n replayDetected = true;\n return null;\n }\n }\n\n return jwkToVerifyingKey(kid, jwk, alg);\n };\n\n try {\n const result = await httpbis.verifyMessage(\n {\n keyLookup,\n },\n normalizeRequest(request)\n );\n if (result === true) {\n return {\n ok: true,\n kid: resolvedKid,\n registry: resolver.name,\n algorithm: resolvedAlg,\n };\n }\n return {\n ok: false,\n kid: resolvedKid,\n registry: resolver.name,\n algorithm: resolvedAlg,\n error: replayDetected\n ? 'RFC9421 signature replay — already seen within tolerance window'\n : result === false\n ? 'signature invalid'\n : 'no signature found',\n };\n } catch (err) {\n return {\n ok: false,\n kid: resolvedKid,\n registry: resolver.name,\n algorithm: resolvedAlg,\n error: err instanceof Error ? err.message : 'verification error',\n };\n }\n}\n\nfunction normalizeRequest(request: RFC9421VerifyRequest): {\n method: string;\n url: string;\n headers: Record<string, string | string[]>;\n} {\n return {\n method: request.method.toUpperCase(),\n url: request.url,\n headers: request.headers,\n };\n}\n\nfunction safeOrigin(url: string): string | undefined {\n try {\n return new URL(url).origin;\n } catch {\n return undefined;\n }\n}\n\nasync function jwkToVerifyingKey(\n id: string,\n jwk: JWK,\n alg: string | undefined\n): Promise<VerifyingKey> {\n const algorithm = alg ?? inferAlgFromJwk(jwk);\n const { subtle } = await getCrypto();\n const importAlg = webCryptoImportAlgFor(algorithm);\n const verifyAlg = webCryptoAlgFor(algorithm);\n if (!importAlg || !verifyAlg) {\n return {\n id,\n algs: alg ? [alg] : undefined,\n verify: async () => false,\n };\n }\n const key = await subtle.importKey('jwk', jwk as JsonWebKey, importAlg, false, ['verify']);\n\n return {\n id,\n algs: alg ? [alg] : undefined,\n verify: async (data: Buffer, signature: Buffer): Promise<boolean> => {\n try {\n return await subtle.verify(verifyAlg, key, toArrayBuffer(signature), toArrayBuffer(data));\n } catch {\n return false;\n }\n },\n };\n}\n\nfunction inferAlgFromJwk(jwk: JWK): string {\n if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') return 'ed25519';\n if (jwk.kty === 'EC' && jwk.crv === 'P-256') return 'ecdsa-p256-sha256';\n if (jwk.kty === 'EC' && jwk.crv === 'P-384') return 'ecdsa-p384-sha384';\n if (jwk.kty === 'RSA') return 'rsa-v1_5-sha256';\n return 'ecdsa-p256-sha256';\n}\n\nfunction webCryptoAlgFor(\n rfc9421Alg: string\n): AlgorithmIdentifier | EcdsaParams | RsaPssParams | null {\n switch (rfc9421Alg) {\n case 'ed25519':\n return { name: 'Ed25519' };\n case 'ecdsa-p256-sha256':\n return { name: 'ECDSA', hash: 'SHA-256' };\n case 'ecdsa-p384-sha384':\n return { name: 'ECDSA', hash: 'SHA-384' };\n case 'rsa-v1_5-sha256':\n return { name: 'RSASSA-PKCS1-v1_5' };\n case 'rsa-pss-sha512':\n return { name: 'RSA-PSS', saltLength: 64 };\n default:\n return null;\n }\n}\n\nfunction webCryptoImportAlgFor(\n rfc9421Alg: string\n): AlgorithmIdentifier | EcKeyImportParams | RsaHashedImportParams | null {\n switch (rfc9421Alg) {\n case 'ed25519':\n return { name: 'Ed25519' };\n case 'ecdsa-p256-sha256':\n return { name: 'ECDSA', namedCurve: 'P-256' };\n case 'ecdsa-p384-sha384':\n return { name: 'ECDSA', namedCurve: 'P-384' };\n case 'rsa-v1_5-sha256':\n return { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };\n case 'rsa-pss-sha512':\n return { name: 'RSA-PSS', hash: 'SHA-512' };\n default:\n return null;\n }\n}\n\nfunction toArrayBuffer(buf: Buffer): ArrayBuffer {\n const out = new ArrayBuffer(buf.byteLength);\n new Uint8Array(out).set(buf);\n return out;\n}\n\nfunction toUnixSeconds(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (v instanceof Date) return Math.floor(v.getTime() / 1000);\n if (typeof v === 'string') {\n const parsed = Date.parse(v);\n if (Number.isFinite(parsed)) return Math.floor(parsed / 1000);\n }\n return undefined;\n}\n\nasync function getCrypto(): Promise<{ subtle: SubtleCrypto }> {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n return { subtle: globalThis.crypto.subtle };\n }\n // Node fallback\n const nodeCrypto = await import('node:crypto');\n return { subtle: nodeCrypto.webcrypto.subtle as SubtleCrypto };\n}\n","/**\n * Shared nonce/signature replay-protection store for transport verifiers.\n *\n * Rationale: every transport-signature verifier (RFC9421, VI, AP2, ACP,\n * MPP) validates a created/expires window, but without a seen-nonce\n * cache any captured signed request can be replayed within the (default\n * 300s, now tightened to 60s) tolerance window.\n *\n * This module ships a bounded in-memory LRU as the default. Production\n * deployments with multi-pod horizontal scaling SHOULD pass a shared store\n * (Redis-backed) via the verifier options to make replay protection global\n * rather than per-pod.\n *\n * The store interface is intentionally minimal: a single `seen(key,\n * expiresAt)` method that returns true iff the key was already recorded\n * (i.e. caller should reject as a replay). Callers compose the key from\n * whichever identifiers are unique to the signature (kid + nonce + sig\n * digest, typically).\n */\n\nexport interface NonceStore {\n /**\n * Record `key` as seen. Returns true iff the key was ALREADY present —\n * i.e. caller should reject the request as a replay. Returns false on\n * first sighting (caller should proceed).\n *\n * `expiresAtMs` is a hint for the store to evict entries that can no\n * longer cause harm (their signature window has elapsed).\n */\n seen(key: string, expiresAtMs: number): boolean;\n}\n\n/**\n * Default in-memory LRU. Per-process, lost on restart. Suitable for\n * single-pod deploys and for development; production multi-pod deploys\n * should pass a shared store.\n *\n * Capacity-bounded: once the limit is reached, the oldest entry is dropped\n * even if it hasn't yet expired. The limit (default 10k entries) is large\n * enough that meaningful replay windows shouldn't approach it; if a\n * deployment is hitting it, that's a signal to migrate to Redis.\n *\n * Also runs a lazy sweep on each `seen` call to evict entries past their\n * `expiresAtMs` — keeps memory bounded under burst load.\n */\nexport class InMemoryNonceStore implements NonceStore {\n private readonly entries = new Map<string, number>();\n private readonly capacity: number;\n private lastSweepMs = 0;\n\n constructor(capacity = 10_000) {\n this.capacity = capacity;\n }\n\n seen(key: string, expiresAtMs: number): boolean {\n const nowMs = Date.now();\n\n // Lazy sweep: at most once per second, walk expired entries.\n if (nowMs - this.lastSweepMs > 1000) {\n for (const [k, exp] of this.entries) {\n if (exp <= nowMs) this.entries.delete(k);\n }\n this.lastSweepMs = nowMs;\n }\n\n const existing = this.entries.get(key);\n if (existing !== undefined && existing > nowMs) {\n return true; // replay\n }\n\n // First sighting (or stale entry) — record + evict oldest if over capacity.\n if (this.entries.size >= this.capacity) {\n const oldest = this.entries.keys().next().value;\n if (oldest !== undefined) this.entries.delete(oldest);\n }\n this.entries.set(key, expiresAtMs);\n return false;\n }\n}\n\n/**\n * Process-wide singleton instance for convenience. Verifiers that don't\n * receive an explicit nonceStore in their options fall back to this.\n *\n * Memory-bounded at 10k entries by default; sufficient for a single pod\n * handling thousands of requests/sec where signatures only carry value\n * within their (60s default) expiry window.\n */\nexport const defaultNonceStore = new InMemoryNonceStore();\n","/**\n * UCP (Universal Commerce Protocol) checkout session extractor.\n *\n * Google + Shopify spec (ucp.dev). Extracts checkout session context from\n * incoming HTTP requests and, at registration time, validates the\n * `/.well-known/ucp` manifest via AJV against the mirrored JSON schema.\n */\n\nimport { sdkFetch } from '../http';\nimport { mapUCPRequestToPurpose, type CommercePurpose } from './purpose-mapping';\n\nexport interface UCPTotal {\n type?: string;\n amount?: number;\n currency?: string;\n}\n\nexport interface UCPCheckoutContext {\n sessionId?: string;\n endpoint: string;\n purpose: CommercePurpose | null;\n merchantDomain?: string;\n totals?: UCPTotal[];\n paymentMethod?: string;\n manifestUrl?: string;\n}\n\nexport interface UCPRequestLike {\n method: string;\n url: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\nexport function extractUCPContext(request: UCPRequestLike): UCPCheckoutContext | null {\n const { method, url } = request;\n if (!method || !url) return null;\n\n const parsedUrl = safeParseUrl(url);\n const path = parsedUrl?.pathname ?? url.split('?')[0];\n\n const purpose = mapUCPRequestToPurpose(method, path);\n const endpoint = `${method.toUpperCase()} ${path}`;\n const sessionId = extractSessionId(path);\n\n const body = (request.body ?? {}) as Record<string, unknown>;\n const totals = Array.isArray(body.totals) ? (body.totals as UCPTotal[]) : undefined;\n const paymentMethod = coerceString(body.payment_method ?? body.paymentMethod);\n const manifestUrl = coerceString(body.manifest_url ?? body.manifestUrl);\n\n const merchantDomain = extractMerchantDomain(body, parsedUrl);\n\n return {\n sessionId,\n endpoint,\n purpose,\n merchantDomain,\n totals,\n paymentMethod,\n manifestUrl,\n };\n}\n\n/**\n * Fetch and parse a UCP manifest at registration time. Returns parsed JSON\n * on success, null on any failure (network, parse, timeout). Does NOT throw.\n *\n * Schema validation is a separate step — see `validateUCPManifest`.\n */\nexport async function fetchUCPManifest(\n manifestUrl: string,\n options: { timeoutMs?: number } = {}\n): Promise<unknown | null> {\n const timeoutMs = options.timeoutMs ?? 3000;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await sdkFetch(manifestUrl, { signal: controller.signal });\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Validate a UCP manifest against the minimal shape we care about.\n *\n * The full UCP manifest schema lives upstream (ucp.dev) and is out of scope\n * to mirror here exhaustively. This function checks the structural guarantees\n * we depend on: required top-level fields (version, capabilities, endpoints).\n *\n * For full schema validation, consumers can pass their own AJV compiled\n * validator via `options.validator`.\n */\nexport interface UCPManifestValidationResult {\n ok: boolean;\n errors: string[];\n}\n\nexport function validateUCPManifest(\n manifest: unknown,\n options: { validator?: (m: unknown) => { ok: boolean; errors: string[] } } = {}\n): UCPManifestValidationResult {\n if (options.validator) return options.validator(manifest);\n\n const errors: string[] = [];\n if (!manifest || typeof manifest !== 'object') {\n return { ok: false, errors: ['manifest is not an object'] };\n }\n const m = manifest as Record<string, unknown>;\n if (typeof m.version !== 'string') errors.push('version is required and must be a string');\n if (!Array.isArray(m.capabilities)) errors.push('capabilities must be an array');\n if (!m.endpoints || typeof m.endpoints !== 'object') errors.push('endpoints must be an object');\n return { ok: errors.length === 0, errors };\n}\n\nfunction safeParseUrl(url: string): URL | null {\n try {\n return new URL(url, 'http://placeholder.invalid');\n } catch {\n return null;\n }\n}\n\nfunction extractSessionId(path: string): string | undefined {\n const match = path.match(/\\/checkout[-_]sessions\\/([^/?#]+)/);\n return match?.[1];\n}\n\nfunction extractMerchantDomain(\n body: Record<string, unknown>,\n parsedUrl: URL | null\n): string | undefined {\n const explicit = coerceString(body.merchant_domain ?? body.merchantDomain);\n if (explicit) return explicit;\n if (parsedUrl && parsedUrl.hostname !== 'placeholder.invalid') return parsedUrl.hostname;\n return undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * ACP (Agentic Commerce Protocol) request extractor.\n *\n * Co-maintained by OpenAI + Stripe. Spec at agenticcommerce.dev.\n *\n * Extracts ACP request context from HTTP requests:\n * - Multi-header parsing: Signature, Timestamp, Idempotency-Key,\n * Authorization: Bearer, API-Version\n * - Endpoint classification: Agentic Checkout (checkout_sessions.*) vs\n * Delegate Payment (agentic_commerce/delegate_payment)\n * - Payment token detection: spt_* (Stripe SharedPaymentToken),\n * vt_* (ACP vault token), unknown\n * - Totals + merchant extraction from body\n *\n * No signature verification here — see acp-verify.ts.\n */\n\nimport { mapACPRequestToPurpose, type CommercePurpose } from './purpose-mapping';\n\nexport type ACPEndpoint =\n | 'checkout_sessions.create'\n | 'checkout_sessions.update'\n | 'checkout_sessions.complete'\n | 'checkout_sessions.cancel'\n | 'delegate_payment'\n | 'unknown';\n\nexport type ACPPaymentTokenType = 'stripe-spt' | 'acp-vt' | 'other' | null;\n\nexport interface ACPTotal {\n type?: string;\n amount?: number;\n currency?: string;\n}\n\nexport interface ACPRequestContext {\n endpoint: ACPEndpoint;\n purpose: CommercePurpose | null;\n sessionId?: string;\n merchantId?: string;\n apiVersion?: string;\n bearer?: string;\n signatureHeader?: string;\n timestampHeader?: string;\n idempotencyKey?: string;\n paymentToken?: {\n raw?: string;\n type: ACPPaymentTokenType;\n provider?: string;\n };\n totals?: ACPTotal[];\n fulfillmentOption?: string;\n rawBody?: string;\n}\n\nexport interface ACPRequestLike {\n method: string;\n url: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: string;\n}\n\nexport function extractACPContext(request: ACPRequestLike): ACPRequestContext | null {\n const { method, url } = request;\n if (!method || !url) return null;\n\n const path = stripQuery(url.startsWith('http') ? new URL(url).pathname : url);\n\n const endpoint = classifyEndpoint(method, path);\n const purpose = mapACPRequestToPurpose(method, path);\n const sessionId = extractSessionId(path);\n\n const headers = request.headers ?? {};\n const signatureHeader = readHeader(headers, 'signature');\n const timestampHeader = readHeader(headers, 'timestamp');\n const idempotencyKey = readHeader(headers, 'idempotency-key');\n const apiVersion = readHeader(headers, 'api-version');\n const bearer = extractBearer(readHeader(headers, 'authorization'));\n\n const body = (request.body ?? {}) as Record<string, unknown>;\n const merchantId = coerceString(body.merchant_id ?? body.merchantId);\n const totals = Array.isArray(body.totals) ? (body.totals as ACPTotal[]) : undefined;\n const fulfillmentOption = extractFulfillmentOption(body);\n\n const paymentToken = extractPaymentToken(body);\n\n return {\n endpoint,\n purpose,\n sessionId,\n merchantId,\n apiVersion,\n bearer,\n signatureHeader,\n timestampHeader,\n idempotencyKey,\n paymentToken,\n totals,\n fulfillmentOption,\n rawBody: request.rawBody,\n };\n}\n\nfunction classifyEndpoint(method: string, path: string): ACPEndpoint {\n const m = method.toUpperCase();\n if (m !== 'POST') return 'unknown';\n if (/^\\/agentic_commerce\\/delegate_payment\\/?$/.test(path)) return 'delegate_payment';\n if (/^\\/checkout_sessions\\/?$/.test(path)) return 'checkout_sessions.create';\n if (/^\\/checkout_sessions\\/[^/]+\\/?$/.test(path)) return 'checkout_sessions.update';\n if (/^\\/checkout_sessions\\/[^/]+\\/complete\\/?$/.test(path)) return 'checkout_sessions.complete';\n if (/^\\/checkout_sessions\\/[^/]+\\/cancel\\/?$/.test(path)) return 'checkout_sessions.cancel';\n return 'unknown';\n}\n\nfunction extractSessionId(path: string): string | undefined {\n const match = path.match(/\\/checkout_sessions\\/([^/?#]+)/);\n return match?.[1];\n}\n\nfunction extractBearer(authHeader: string | undefined): string | undefined {\n if (!authHeader) return undefined;\n const match = authHeader.match(/^Bearer\\s+(.+)$/i);\n return match ? match[1].trim() : undefined;\n}\n\nfunction extractPaymentToken(body: Record<string, unknown>): ACPRequestContext['paymentToken'] {\n const paymentData = body.payment_data as Record<string, unknown> | undefined;\n if (!paymentData) return undefined;\n const raw = coerceString(paymentData.token);\n const provider = coerceString(paymentData.provider);\n if (!raw) return { raw: undefined, type: null, provider };\n const type = classifyPaymentToken(raw);\n return { raw, type, provider };\n}\n\nfunction classifyPaymentToken(token: string): ACPPaymentTokenType {\n if (token.startsWith('spt_')) return 'stripe-spt';\n if (token.startsWith('vt_')) return 'acp-vt';\n return 'other';\n}\n\nfunction extractFulfillmentOption(body: Record<string, unknown>): string | undefined {\n const direct = coerceString(body.fulfillment_option ?? body.fulfillmentOption);\n if (direct) return direct;\n const options = body.fulfillment_options;\n if (Array.isArray(options) && options.length > 0) {\n const first = options[0];\n if (first && typeof first === 'object') {\n const id = coerceString((first as Record<string, unknown>).id);\n if (id) return id;\n }\n }\n return undefined;\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | undefined {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw[0];\n }\n }\n return undefined;\n}\n\nfunction stripQuery(path: string): string {\n const q = path.indexOf('?');\n return q === -1 ? path : path.slice(0, q);\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * VI (Verifiable Intent) SD-JWT extraction.\n *\n * Open-sourced 5 March 2026 by Mastercard + Google (v0.1-draft).\n * VI is a 3-layer SD-JWT chain:\n * L1 — issuer → wallet (credential provider)\n * L2 — user → agent (cnf.jwk binding to L3 agent key)\n * L3 — agent → merchant (payment or checkout mandate, split into L3a / L3b\n * cross-referenced via transaction_id)\n *\n * This module does EXTRACTION ONLY — it decodes SD-JWT structure and pulls\n * out the mandate type, kid, executionMode, 8 constraint types, checkoutHash\n * (constraint type 8), transactionId, and raw layers for later verification.\n *\n * Signature verification lives in vi-verify.ts; this module uses @sd-jwt's\n * sync decoder with a SHA-256 hasher for structural parsing only.\n */\n\nimport { splitSdJwt, decodeSdJwtSync } from '@sd-jwt/core';\nimport { createHash } from 'node:crypto';\nimport type { VIMandateType } from './purpose-mapping';\n\nexport type { VIMandateType };\nexport type VIExecutionMode = 'Immediate' | 'Autonomous' | 'Both';\n\nexport interface VIAllowedParty {\n id?: string;\n name?: string;\n website?: string;\n}\n\nexport interface VILineItem {\n id?: string;\n acceptableItems?: string[];\n quantity?: number;\n}\n\nexport interface VIPaymentAmount {\n currency?: string;\n min?: number;\n max?: number;\n}\n\nexport interface VIBudgetLimit {\n currency?: string;\n max?: number;\n}\n\nexport interface VIRecurrence {\n frequency?: string;\n startDate?: string;\n endDate?: string;\n maxOccurrences?: number;\n}\n\nexport interface VIConstraints {\n allowedMerchants?: VIAllowedParty[];\n allowedPayees?: VIAllowedParty[];\n lineItems?: VILineItem[];\n paymentAmount?: VIPaymentAmount;\n budgetLimit?: VIBudgetLimit;\n recurrence?: VIRecurrence;\n agentRecurrence?: VIRecurrence;\n}\n\nexport interface VIExtractedClaims {\n mandateType: VIMandateType;\n kid?: string;\n executionMode?: VIExecutionMode;\n credentialProvider?: string;\n constraints: VIConstraints;\n /** VI constraint type 8 — SHA-256 of the paired L2 checkout disclosure. */\n checkoutHash?: string;\n transactionId?: string;\n rawLayers: { l1?: string; l2?: string; l3?: string };\n}\n\n/**\n * Extract VI claims from a compact SD-JWT string.\n *\n * Input shape:\n * <jwt>~<disclosure1>~<disclosure2>~...~<kbJwt?>\n *\n * Returns null if parsing fails at any layer. Does not verify signatures.\n */\nexport function extractVIClaims(sdJwtCompact: string): VIExtractedClaims | null {\n if (!sdJwtCompact || typeof sdJwtCompact !== 'string') return null;\n\n let decoded;\n try {\n decoded = decodeSdJwtSync(sdJwtCompact, sha256Sync);\n } catch {\n return null;\n }\n\n const split = safeSplit(sdJwtCompact);\n\n const payload = (decoded.jwt?.payload ?? {}) as Record<string, unknown>;\n const disclosures = decoded.disclosures ?? [];\n\n // Apply disclosures onto payload to resolve _sd references.\n // Disclosure from @sd-jwt/core has { key, value, digest() } where digest is\n // a function — we only need key+value here, so narrow via a structural cast.\n const claims = applyDisclosures(\n payload,\n disclosures as unknown as Array<{ key?: string; value?: unknown }>\n );\n\n const mandateType = coerceMandateType(\n claims.mandate_type ?? claims.mandateType ?? payload.mandate_type ?? payload.mandateType\n );\n if (!mandateType) return null;\n\n const kid = coerceString(\n (decoded.jwt?.header as Record<string, unknown> | undefined)?.kid ?? claims.kid ?? payload.kid\n );\n\n const executionMode = coerceExecutionMode(claims.execution_mode ?? claims.executionMode);\n const credentialProvider = coerceString(claims.iss ?? payload.iss);\n\n const constraints = extractConstraints(\n (claims.constraints ?? claims.default_constraints ?? {}) as Record<string, unknown>\n );\n\n const transactionId = coerceString(claims.transaction_id ?? claims.transactionId);\n const checkoutHash = coerceString(\n claims.checkout_hash ??\n claims.conditional_transaction_id ??\n (claims.payment_reference as Record<string, unknown> | undefined)?.checkout_hash\n );\n\n return {\n mandateType,\n kid,\n executionMode,\n credentialProvider,\n constraints,\n checkoutHash,\n transactionId,\n rawLayers: split,\n };\n}\n\nfunction safeSplit(compact: string): { l1?: string; l2?: string; l3?: string } {\n try {\n const { jwt, kbJwt } = splitSdJwt(compact);\n // VI layering maps loosely: the outer JWT is L3 (agent mandate), KB-JWT\n // (if present) is the key-binding proof, and disclosures carry L2/L1 fragments.\n return { l3: jwt, l2: kbJwt };\n } catch {\n return {};\n }\n}\n\nfunction applyDisclosures(\n payload: Record<string, unknown>,\n disclosures: Array<{ key?: string; value?: unknown }>\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...payload };\n for (const d of disclosures) {\n if (d.key && d.value !== undefined && !(d.key in result)) {\n result[d.key] = d.value;\n }\n }\n return result;\n}\n\nfunction extractConstraints(raw: Record<string, unknown>): VIConstraints {\n return {\n allowedMerchants: toAllowedPartyArray(raw.allowed_merchants ?? raw.allowedMerchants),\n allowedPayees: toAllowedPartyArray(raw.allowed_payees ?? raw.allowedPayees),\n lineItems: toLineItemArray(raw.line_items ?? raw.lineItems),\n paymentAmount: toPaymentAmount(raw.payment_amount ?? raw.paymentAmount),\n budgetLimit: toBudgetLimit(raw.budget_limit ?? raw.budgetLimit ?? raw.budget),\n recurrence: toRecurrence(raw.recurrence),\n agentRecurrence: toRecurrence(raw.agent_recurrence ?? raw.agentRecurrence),\n };\n}\n\nfunction toAllowedPartyArray(v: unknown): VIAllowedParty[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out: VIAllowedParty[] = [];\n for (const item of v) {\n if (item && typeof item === 'object') {\n const r = item as Record<string, unknown>;\n out.push({\n id: coerceString(r.id),\n name: coerceString(r.name),\n website: coerceString(r.website),\n });\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\nfunction toLineItemArray(v: unknown): VILineItem[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out: VILineItem[] = [];\n for (const item of v) {\n if (item && typeof item === 'object') {\n const r = item as Record<string, unknown>;\n const acc = r.acceptable_items ?? r.acceptableItems;\n out.push({\n id: coerceString(r.id),\n acceptableItems: Array.isArray(acc)\n ? (acc.filter((a) => typeof a === 'string') as string[])\n : undefined,\n quantity: coerceNumber(r.quantity),\n });\n }\n }\n return out.length > 0 ? out : undefined;\n}\n\nfunction toPaymentAmount(v: unknown): VIPaymentAmount | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n return {\n currency: coerceString(r.currency),\n min: coerceNumber(r.min),\n max: coerceNumber(r.max),\n };\n}\n\nfunction toBudgetLimit(v: unknown): VIBudgetLimit | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n return {\n currency: coerceString(r.currency),\n max: coerceNumber(r.max),\n };\n}\n\nfunction toRecurrence(v: unknown): VIRecurrence | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n return {\n frequency: coerceString(r.frequency),\n startDate: coerceString(r.start_date ?? r.startDate),\n endDate: coerceString(r.end_date ?? r.endDate),\n maxOccurrences: coerceNumber(r.max_occurrences ?? r.maxOccurrences),\n };\n}\n\nfunction coerceMandateType(v: unknown): VIMandateType | null {\n if (v === 'checkout' || v === 'payment' || v === 'checkout.open' || v === 'payment.open') {\n return v;\n }\n return null;\n}\n\nfunction coerceExecutionMode(v: unknown): VIExecutionMode | undefined {\n return v === 'Immediate' || v === 'Autonomous' || v === 'Both' ? v : undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n\nfunction coerceNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string') {\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\nfunction sha256Sync(data: string | ArrayBuffer): Uint8Array {\n const buf =\n typeof data === 'string' ? Buffer.from(data, 'utf-8') : Buffer.from(new Uint8Array(data));\n const hash = createHash('sha256').update(buf).digest();\n return new Uint8Array(hash.buffer, hash.byteOffset, hash.byteLength);\n}\n","/**\n * Stripe webhook HMAC-SHA256 verifier (inline).\n *\n * Stripe-Signature header format: \"t=TIMESTAMP,v1=HEX_SIGNATURE\"\n * - t: unix seconds when Stripe signed the webhook\n * - v1: HMAC-SHA256(webhook_secret, `${t}.${payload}`) as hex\n *\n * Multiple v1 signatures can coexist during secret rotation; any match wins.\n * Default tolerance on timestamp age: 300s (matches Stripe's own default).\n *\n * Documented at docs.stripe.com — we intentionally inline ~25 LOC rather\n * than pull in the full stripe npm package (MIT but 600KB+ with deps).\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\nexport interface VerifyStripeWebhookResult {\n ok: boolean;\n timestamp?: number;\n error?: string;\n}\n\nexport interface VerifyStripeWebhookOptions {\n toleranceSec?: number;\n /** Injectable for deterministic tests. */\n now?: () => number;\n}\n\nexport function verifyStripeWebhook(\n payload: string,\n signatureHeader: string | undefined,\n secret: string,\n options: VerifyStripeWebhookOptions = {}\n): VerifyStripeWebhookResult {\n if (!signatureHeader) return { ok: false, error: 'missing Stripe-Signature header' };\n if (!secret) return { ok: false, error: 'missing webhook secret' };\n\n const parsed = parseStripeSignature(signatureHeader);\n if (!parsed.timestamp) return { ok: false, error: 'malformed Stripe-Signature (missing t=)' };\n if (parsed.v1Signatures.length === 0) {\n return { ok: false, error: 'malformed Stripe-Signature (no v1=)' };\n }\n\n const tolerance = options.toleranceSec ?? 300;\n const now = options.now ? options.now() : Math.floor(Date.now() / 1000);\n if (Math.abs(now - parsed.timestamp) > tolerance) {\n return {\n ok: false,\n timestamp: parsed.timestamp,\n error: `timestamp outside tolerance (${tolerance}s)`,\n };\n }\n\n const signedPayload = `${parsed.timestamp}.${payload}`;\n const expected = createHmac('sha256', secret).update(signedPayload).digest();\n\n for (const candidateHex of parsed.v1Signatures) {\n const candidate = hexToBuffer(candidateHex);\n if (!candidate) continue;\n if (candidate.length !== expected.length) continue;\n if (timingSafeEqual(candidate, expected)) {\n return { ok: true, timestamp: parsed.timestamp };\n }\n }\n\n return { ok: false, timestamp: parsed.timestamp, error: 'signature mismatch' };\n}\n\ninterface ParsedStripeSignature {\n timestamp: number | null;\n v1Signatures: string[];\n}\n\nfunction parseStripeSignature(header: string): ParsedStripeSignature {\n let timestamp: number | null = null;\n const v1Signatures: string[] = [];\n for (const part of header.split(',')) {\n const [rawKey, rawValue] = part.split('=');\n if (!rawKey || !rawValue) continue;\n const key = rawKey.trim();\n const value = rawValue.trim();\n if (key === 't') {\n const n = Number(value);\n if (Number.isFinite(n)) timestamp = n;\n } else if (key === 'v1') {\n v1Signatures.push(value);\n }\n }\n return { timestamp, v1Signatures };\n}\n\nfunction hexToBuffer(hex: string): Buffer | null {\n if (!/^[0-9a-fA-F]+$/.test(hex) || hex.length % 2 !== 0) return null;\n return Buffer.from(hex, 'hex');\n}\n","/**\n * PDLSS constraint evaluation.\n *\n * Evaluates VI constraint types 1-4 (merchant/payee allowlists, line items,\n * payment amount) + MPP/x402 payment-method allowlist + spending-limit\n * against a transaction context.\n *\n * Types 5/6/7 (budget, recurrence, agent_recurrence) extract through but\n * enforcement is deferred to the cross-merchant budget service.\n * This module returns per-constraint {ok, reason} results\n * so a policy layer can decide hard-deny vs trust-signal.\n */\n\nimport type { VIConstraints, VIAllowedParty, VILineItem, VIPaymentAmount } from './vi';\n\nexport interface TransactionContext {\n amount?: number;\n currency?: string;\n merchant?: { id?: string; website?: string };\n payee?: { id?: string; website?: string };\n lineItems?: Array<{ id?: string; quantity?: number }>;\n /** For MPP / x402 payment-method enforcement. */\n paymentMethod?: string;\n}\n\nexport type ConstraintKey = 'merchant' | 'payee' | 'lineItems' | 'amount' | 'paymentMethod';\n\nexport interface ConstraintResult {\n ok: boolean;\n reason?: string;\n}\n\nexport interface ConstraintEvalResult {\n ok: boolean;\n results: Record<string, ConstraintResult>;\n reasons: string[];\n}\n\nexport interface VIConstraintEvalInput {\n constraints: VIConstraints;\n transaction: TransactionContext;\n}\n\nexport function evaluateVIConstraints(input: VIConstraintEvalInput): ConstraintEvalResult {\n const { constraints, transaction } = input;\n const results: Record<string, ConstraintResult> = {};\n\n if (constraints.allowedMerchants && constraints.allowedMerchants.length > 0) {\n results.merchant = evaluateAllowlist(\n 'merchant',\n constraints.allowedMerchants,\n transaction.merchant\n );\n }\n\n if (constraints.allowedPayees && constraints.allowedPayees.length > 0) {\n results.payee = evaluateAllowlist('payee', constraints.allowedPayees, transaction.payee);\n }\n\n if (constraints.lineItems && constraints.lineItems.length > 0) {\n results.lineItems = evaluateLineItems(constraints.lineItems, transaction.lineItems ?? []);\n }\n\n if (constraints.paymentAmount) {\n results.amount = evaluatePaymentAmount(constraints.paymentAmount, transaction);\n }\n\n const reasons: string[] = [];\n let ok = true;\n for (const [key, r] of Object.entries(results)) {\n if (!r.ok) {\n ok = false;\n reasons.push(r.reason ?? `${key} failed`);\n }\n }\n\n return { ok, results, reasons };\n}\n\nexport interface PaymentMethodAllowlistInput {\n allowedMethods?: string[];\n requestedMethod?: string;\n}\n\nexport function evaluatePaymentMethodAllowlist(\n input: PaymentMethodAllowlistInput\n): ConstraintResult {\n const allow = input.allowedMethods ?? [];\n if (allow.length === 0) return { ok: true };\n if (!input.requestedMethod) {\n return { ok: false, reason: 'no payment method in request; allowlist configured' };\n }\n const lowered = input.requestedMethod.toLowerCase();\n const allowed = allow.some((m) => m.toLowerCase() === lowered);\n if (!allowed) {\n return {\n ok: false,\n reason: `payment method \"${input.requestedMethod}\" not in allowlist [${allow.join(', ')}]`,\n };\n }\n return { ok: true };\n}\n\nexport interface SpendingLimitInput {\n limit?: { amount?: number; currency?: string };\n requested?: { amount?: number; currency?: string };\n}\n\nexport function evaluateSpendingLimit(input: SpendingLimitInput): ConstraintResult {\n const { limit, requested } = input;\n if (!limit || typeof limit.amount !== 'number') return { ok: true };\n if (!requested || typeof requested.amount !== 'number') return { ok: true };\n if (limit.currency && requested.currency && limit.currency !== requested.currency) {\n return {\n ok: false,\n reason: `currency mismatch: limit ${limit.currency} vs requested ${requested.currency}`,\n };\n }\n if (requested.amount > limit.amount) {\n return {\n ok: false,\n reason:\n `requested ${requested.amount} ${requested.currency ?? ''} exceeds limit ${limit.amount} ${limit.currency ?? ''}`.trim(),\n };\n }\n return { ok: true };\n}\n\nfunction evaluateAllowlist(\n kind: 'merchant' | 'payee',\n allowlist: VIAllowedParty[],\n actual: { id?: string; website?: string } | undefined\n): ConstraintResult {\n if (!actual || (!actual.id && !actual.website)) {\n return { ok: false, reason: `no ${kind} in transaction; allowlist configured` };\n }\n for (const entry of allowlist) {\n if (entry.id && actual.id && entry.id === actual.id) return { ok: true };\n if (entry.website && actual.website && domainsMatch(entry.website, actual.website)) {\n return { ok: true };\n }\n }\n const allowedDescriptors = allowlist.map(describeParty).join(', ');\n const actualDescriptor = describeParty(actual);\n return {\n ok: false,\n reason: `${kind} ${actualDescriptor} not in allowlist [${allowedDescriptors}]`,\n };\n}\n\nfunction evaluateLineItems(\n allowlist: VILineItem[],\n actualItems: Array<{ id?: string; quantity?: number }>\n): ConstraintResult {\n if (actualItems.length === 0) {\n return { ok: false, reason: 'no line items in transaction; allowlist configured' };\n }\n const reasons: string[] = [];\n for (const item of actualItems) {\n const match = allowlist.find(\n (a) => (a.id && a.id === item.id) || (a.acceptableItems ?? []).includes(item.id ?? '')\n );\n if (!match) {\n reasons.push(`line item \"${item.id ?? '(unnamed)'}\" not in allowlist`);\n continue;\n }\n if (\n typeof match.quantity === 'number' &&\n typeof item.quantity === 'number' &&\n item.quantity > match.quantity\n ) {\n reasons.push(\n `line item \"${item.id}\" quantity ${item.quantity} exceeds allowed ${match.quantity}`\n );\n }\n }\n return reasons.length === 0 ? { ok: true } : { ok: false, reason: reasons.join('; ') };\n}\n\nfunction evaluatePaymentAmount(\n bound: VIPaymentAmount,\n transaction: TransactionContext\n): ConstraintResult {\n if (typeof transaction.amount !== 'number') {\n return { ok: false, reason: 'no amount in transaction; paymentAmount bound configured' };\n }\n if (bound.currency && transaction.currency && bound.currency !== transaction.currency) {\n return {\n ok: false,\n reason: `currency mismatch: bound ${bound.currency} vs transaction ${transaction.currency}`,\n };\n }\n if (typeof bound.min === 'number' && transaction.amount < bound.min) {\n return {\n ok: false,\n reason: `amount ${transaction.amount} below min ${bound.min}`,\n };\n }\n if (typeof bound.max === 'number' && transaction.amount > bound.max) {\n return {\n ok: false,\n reason: `amount ${transaction.amount} above max ${bound.max}`,\n };\n }\n return { ok: true };\n}\n\nfunction domainsMatch(allow: string, actual: string): boolean {\n const a = normalizeDomain(allow);\n const b = normalizeDomain(actual);\n return a === b || b.endsWith(`.${a}`);\n}\n\nfunction normalizeDomain(value: string): string {\n try {\n const withScheme = /^https?:\\/\\//.test(value) ? value : `https://${value}`;\n return new URL(withScheme).hostname.toLowerCase();\n } catch {\n return value.toLowerCase();\n }\n}\n\nfunction describeParty(party: { id?: string; name?: string; website?: string }): string {\n if (party.id) return `id:${party.id}`;\n if (party.website) return party.website;\n if (party.name) return party.name;\n return '(unnamed)';\n}\n","/**\n * Cross-protocol agent identity binding.\n *\n * Every commerce layer claims an agent identity differently:\n * - VI L3 kid (SD-JWT header)\n * - AP2 agent_id (mandate payload)\n * - ACP Authorization: Bearer token (merchant-issued pre-shared)\n * - MPP Credential `source` field (DID or chain-native key)\n * - x402 client wallet address\n * - RFC 9421 kid (Agent Pay / TAP / Web Bot Auth)\n *\n * This module maps any such claim to a single AstraSync agent via a\n * caller-supplied resolver (typically delegates to the counterparty service),\n * then flags whether multiple claims on the same request resolve to different\n * agents (a trust signal for PDLSS).\n *\n * This is AstraSync whitespace — no vendor owns multi-protocol identity\n * unification.\n */\n\nexport interface IdentityClaim {\n /** Originating protocol label: 'vi' | 'ap2' | 'acp' | 'mpp' | 'x402' | 'agentpay' | 'tap' | 'webbotauth' */\n protocol: string;\n /** Claim field name, e.g. 'kid', 'agent_id', 'source', 'bearer'. */\n field: string;\n /** Claim value as presented on the wire. */\n value: string;\n}\n\nexport interface IdentityBindingResult {\n claims: IdentityClaim[];\n mappedAstraSyncAgentId?: string;\n /**\n * True when two or more claims resolve to different AstraSync agents.\n * Surfaced as a trust signal rather than an auto-deny — legitimate flows\n * (e.g. delegate payments) can legitimately carry multiple identities.\n */\n mismatchAcrossLayers: boolean;\n /** Per-claim resolution result for audit / debugging. */\n resolutions: Array<{ claim: IdentityClaim; agentId: string | null }>;\n}\n\nexport type IdentityResolver = (claim: IdentityClaim) => Promise<string | null>;\n\nexport async function bindIdentity(\n claims: IdentityClaim[],\n resolver: IdentityResolver\n): Promise<IdentityBindingResult> {\n const resolutions: Array<{ claim: IdentityClaim; agentId: string | null }> = [];\n for (const claim of claims) {\n if (!claim.value) {\n resolutions.push({ claim, agentId: null });\n continue;\n }\n const agentId = await resolver(claim);\n resolutions.push({ claim, agentId });\n }\n\n const resolvedIds = resolutions\n .map((r) => r.agentId)\n .filter((id): id is string => typeof id === 'string' && id.length > 0);\n\n const unique = Array.from(new Set(resolvedIds));\n const mismatchAcrossLayers = unique.length > 1;\n const mappedAstraSyncAgentId = unique.length === 1 ? unique[0] : undefined;\n\n return {\n claims,\n mappedAstraSyncAgentId,\n mismatchAcrossLayers,\n resolutions,\n };\n}\n\n/**\n * Helper constructors — keep protocol/field strings consistent across the\n * codebase and make tests readable.\n */\nexport const claim = {\n viKid: (value: string): IdentityClaim => ({ protocol: 'vi', field: 'kid', value }),\n ap2AgentId: (value: string): IdentityClaim => ({ protocol: 'ap2', field: 'agent_id', value }),\n acpBearer: (value: string): IdentityClaim => ({ protocol: 'acp', field: 'bearer', value }),\n mppSource: (value: string): IdentityClaim => ({ protocol: 'mpp', field: 'source', value }),\n x402Wallet: (value: string): IdentityClaim => ({ protocol: 'x402', field: 'wallet', value }),\n agentPayKid: (value: string): IdentityClaim => ({ protocol: 'agentpay', field: 'kid', value }),\n tapKid: (value: string): IdentityClaim => ({ protocol: 'tap', field: 'kid', value }),\n webBotAuthKid: (value: string): IdentityClaim => ({\n protocol: 'webbotauth',\n field: 'kid',\n value,\n }),\n};\n","/**\n * AP2 (Agent Payments Protocol) mandate extraction.\n *\n * Google-led, launched 3 April 2026 with 60+ partners (Mastercard, PayPal,\n * Coinbase, AmEx, Revolut, UnionPay, ...). AP2 ships three mandate types as\n * SD-JWTs in series:\n * - intent_mandate — user declares intent (amount, merchant category, etc.)\n * - cart_mandate — user approves a cart (specific items, totals)\n * - payment_mandate — authorizes the actual payment rail\n *\n * Mandates are cross-referenced via ids; each is an SD-JWT over ES256 (or\n * equivalent). We decode via @sd-jwt/core and extract the AP2-specific\n * shape — verification lives in ap2-verify.ts.\n */\n\nimport { decodeSdJwtSync } from '@sd-jwt/core';\nimport { createHash } from 'node:crypto';\nimport type { AP2MandateType } from './purpose-mapping';\n\nexport type { AP2MandateType };\n\nexport interface AP2PaymentDetailsTotal {\n amount?: { value?: string | number; currency?: string };\n label?: string;\n}\n\nexport interface AP2IntentMandateClaims {\n type: 'intent_mandate';\n agent_id?: string;\n user_id?: string;\n merchant_category?: string;\n allowedMerchantDomains?: string[];\n paymentMethods?: string[];\n expires?: string;\n payment_details_total?: AP2PaymentDetailsTotal;\n raw: Record<string, unknown>;\n}\n\nexport interface AP2CartMandateClaims {\n type: 'cart_mandate';\n agent_id?: string;\n intent_mandate_id?: string;\n merchant_id?: string;\n line_items?: Array<{\n id?: string;\n quantity?: number;\n price?: { value?: string | number; currency?: string };\n }>;\n payment_details_total?: AP2PaymentDetailsTotal;\n expires?: string;\n raw: Record<string, unknown>;\n}\n\nexport interface AP2PaymentMandateClaims {\n type: 'payment_mandate';\n agent_id?: string;\n cart_mandate_id?: string;\n payment_method?: string;\n payment_details_total?: AP2PaymentDetailsTotal;\n credential_provider?: string;\n raw: Record<string, unknown>;\n}\n\nexport type AP2MandateClaims =\n | AP2IntentMandateClaims\n | AP2CartMandateClaims\n | AP2PaymentMandateClaims;\n\nexport interface AP2MandateTriple {\n intent?: AP2IntentMandateClaims;\n cart?: AP2CartMandateClaims;\n payment?: AP2PaymentMandateClaims;\n rawLayers: { intentJwt?: string; cartJwt?: string; paymentJwt?: string };\n}\n\n/**\n * Extract a single AP2 mandate from a compact SD-JWT.\n * Returns null if the SD-JWT is malformed or lacks a recognized type field.\n */\nexport function extractAP2Mandate(sdJwtCompact: string): AP2MandateClaims | null {\n if (!sdJwtCompact || typeof sdJwtCompact !== 'string') return null;\n\n let decoded;\n try {\n decoded = decodeSdJwtSync(sdJwtCompact, sha256Sync);\n } catch {\n return null;\n }\n\n const payload = (decoded.jwt?.payload ?? {}) as Record<string, unknown>;\n const disclosures = decoded.disclosures ?? [];\n const claims = applyDisclosures(\n payload,\n disclosures as unknown as Array<{ key?: string; value?: unknown }>\n );\n\n const type = coerceMandateType(claims.type ?? claims.mandate_type ?? claims.mandateType);\n if (!type) return null;\n\n if (type === 'intent_mandate') return buildIntent(claims);\n if (type === 'cart_mandate') return buildCart(claims);\n return buildPayment(claims);\n}\n\nexport interface AP2MandateTripleInput {\n intent?: string;\n cart?: string;\n payment?: string;\n}\n\n/**\n * Extract an intent / cart / payment triple, returning whichever are present.\n * Does NOT enforce cross-reference consistency — that's ap2-verify.ts's job.\n */\nexport function extractAP2Mandates(input: AP2MandateTripleInput): AP2MandateTriple {\n const intent = input.intent\n ? (extractAP2Mandate(input.intent) as AP2IntentMandateClaims | null)\n : null;\n const cart = input.cart ? (extractAP2Mandate(input.cart) as AP2CartMandateClaims | null) : null;\n const payment = input.payment\n ? (extractAP2Mandate(input.payment) as AP2PaymentMandateClaims | null)\n : null;\n return {\n intent: intent ?? undefined,\n cart: cart ?? undefined,\n payment: payment ?? undefined,\n rawLayers: {\n intentJwt: input.intent,\n cartJwt: input.cart,\n paymentJwt: input.payment,\n },\n };\n}\n\nfunction buildIntent(claims: Record<string, unknown>): AP2IntentMandateClaims {\n return {\n type: 'intent_mandate',\n agent_id: coerceString(claims.agent_id ?? claims.agentId),\n user_id: coerceString(claims.user_id ?? claims.userId ?? claims.sub),\n merchant_category: coerceString(claims.merchant_category ?? claims.merchantCategory),\n allowedMerchantDomains: toStringArray(\n claims.allowed_merchant_domains ?? claims.allowedMerchantDomains\n ),\n paymentMethods: toStringArray(claims.payment_methods ?? claims.paymentMethods),\n expires: coerceString(claims.expires ?? claims.exp),\n payment_details_total: toPaymentDetails(claims.payment_details_total ?? claims.total),\n raw: claims,\n };\n}\n\nfunction buildCart(claims: Record<string, unknown>): AP2CartMandateClaims {\n return {\n type: 'cart_mandate',\n agent_id: coerceString(claims.agent_id ?? claims.agentId),\n intent_mandate_id: coerceString(claims.intent_mandate_id ?? claims.intentMandateId),\n merchant_id: coerceString(claims.merchant_id ?? claims.merchantId),\n line_items: toLineItems(claims.line_items ?? claims.lineItems),\n payment_details_total: toPaymentDetails(claims.payment_details_total ?? claims.total),\n expires: coerceString(claims.expires ?? claims.exp),\n raw: claims,\n };\n}\n\nfunction buildPayment(claims: Record<string, unknown>): AP2PaymentMandateClaims {\n return {\n type: 'payment_mandate',\n agent_id: coerceString(claims.agent_id ?? claims.agentId),\n cart_mandate_id: coerceString(claims.cart_mandate_id ?? claims.cartMandateId),\n payment_method: coerceString(claims.payment_method ?? claims.paymentMethod),\n payment_details_total: toPaymentDetails(claims.payment_details_total ?? claims.total),\n credential_provider: coerceString(claims.credential_provider ?? claims.credentialProvider),\n raw: claims,\n };\n}\n\nfunction toPaymentDetails(v: unknown): AP2PaymentDetailsTotal | undefined {\n if (!v || typeof v !== 'object') return undefined;\n const r = v as Record<string, unknown>;\n const amount = r.amount as Record<string, unknown> | undefined;\n return {\n amount: amount\n ? {\n value: coerceStringOrNumber(amount.value),\n currency: coerceString(amount.currency),\n }\n : undefined,\n label: coerceString(r.label),\n };\n}\n\nfunction toLineItems(v: unknown): AP2CartMandateClaims['line_items'] {\n if (!Array.isArray(v)) return undefined;\n const items: NonNullable<AP2CartMandateClaims['line_items']> = [];\n for (const item of v) {\n if (!item || typeof item !== 'object') continue;\n const r = item as Record<string, unknown>;\n const price = r.price as Record<string, unknown> | undefined;\n items.push({\n id: coerceString(r.id),\n quantity: coerceNumber(r.quantity),\n price: price\n ? {\n value: coerceStringOrNumber(price.value),\n currency: coerceString(price.currency),\n }\n : undefined,\n });\n }\n return items.length > 0 ? items : undefined;\n}\n\nfunction toStringArray(v: unknown): string[] | undefined {\n if (!Array.isArray(v)) return undefined;\n const out = v.filter((i): i is string => typeof i === 'string' && i.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\nfunction applyDisclosures(\n payload: Record<string, unknown>,\n disclosures: Array<{ key?: string; value?: unknown }>\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...payload };\n for (const d of disclosures) {\n if (d.key && d.value !== undefined && !(d.key in result)) {\n result[d.key] = d.value;\n }\n }\n return result;\n}\n\nfunction coerceMandateType(v: unknown): AP2MandateType | null {\n if (v === 'intent_mandate' || v === 'cart_mandate' || v === 'payment_mandate') return v;\n return null;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n\nfunction coerceNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string') {\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\nfunction coerceStringOrNumber(v: unknown): string | number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && v.length > 0) return v;\n return undefined;\n}\n\nfunction sha256Sync(data: string | ArrayBuffer): Uint8Array {\n const buf =\n typeof data === 'string' ? Buffer.from(data, 'utf-8') : Buffer.from(new Uint8Array(data));\n const hash = createHash('sha256').update(buf).digest();\n return new Uint8Array(hash.buffer, hash.byteOffset, hash.byteLength);\n}\n","/**\n * AP2 mandate chain verification.\n *\n * Checks the cross-reference consistency of an intent → cart → payment\n * triple. Does NOT verify cryptographic signatures here (that's a call to\n * @sd-jwt/core which needs the agent's / CP's public key; expose via a\n * verifier callback so pipeline can plug in the right resolver).\n *\n * Rules (per AP2 spec v0.1-draft):\n * - cart.intent_mandate_id must equal the intent mandate's canonical id (if present)\n * - payment.cart_mandate_id must equal the cart mandate's canonical id (if present)\n * - agent_id must match across all three layers\n * - payment_method in payment mandate must be in intent.paymentMethods (if declared)\n * - cart totals must not exceed intent totals (if both declared in same currency)\n * - no mandate may be expired (beyond clock skew)\n */\n\nimport type { AP2MandateTriple } from './ap2';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface AP2VerifyInput {\n triple: AP2MandateTriple;\n /**\n * Clock skew tolerance in seconds for expiry checks. Default 60s\n * (tightened from the previous 300s default).\n */\n clockSkewSec?: number;\n now?: () => number;\n /**\n * Optional replay-protection store. Defaults to in-process LRU. When the\n * payment mandate carries an id, this verifier registers it as seen so\n * the same payment mandate replayed within the expiry window is rejected.\n */\n nonceStore?: NonceStore;\n}\n\nexport interface AP2ChainResult {\n ok: boolean;\n checks: {\n intentPresent: boolean;\n cartRefOk: boolean;\n paymentRefOk: boolean;\n agentIdContinuity: boolean;\n paymentMethodAllowed: boolean;\n totalsConsistent: boolean;\n expiryOk: boolean;\n };\n agentId?: string;\n errors: string[];\n}\n\nexport function verifyAP2Chain(input: AP2VerifyInput): AP2ChainResult {\n const { triple } = input;\n const errors: string[] = [];\n const toleranceSec = input.clockSkewSec ?? 60;\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n const intentPresent = triple.intent !== undefined;\n const cartRefOk = checkCartRef(triple, errors);\n const paymentRefOk = checkPaymentRef(triple, errors);\n const { ok: agentIdContinuity, agentId } = checkAgentContinuity(triple, errors);\n const paymentMethodAllowed = checkPaymentMethod(triple, errors);\n const totalsConsistent = checkTotals(triple, errors);\n const expiryOk = checkExpiries(triple, toleranceSec, input.now, errors);\n\n // Audit F-A1-05: replay protection. Register the payment mandate id (or\n // cart mandate id as fallback) so the same triple replayed within the\n // expiry window is rejected. Window matches the tolerance.\n let replayOk = true;\n const replayId = triple.payment?.raw?.id ?? triple.cart?.raw?.id;\n if (typeof replayId === 'string' && replayId.length > 0) {\n const now = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const expiresAt = (now + toleranceSec) * 1000;\n if (nonceStore.seen(`ap2:${replayId}`, expiresAt)) {\n errors.push(`AP2 chain replay — mandate ${replayId} already seen within tolerance window`);\n replayOk = false;\n }\n }\n\n const ok =\n cartRefOk &&\n paymentRefOk &&\n agentIdContinuity &&\n paymentMethodAllowed &&\n totalsConsistent &&\n expiryOk &&\n replayOk;\n\n return {\n ok,\n checks: {\n intentPresent,\n cartRefOk,\n paymentRefOk,\n agentIdContinuity,\n paymentMethodAllowed,\n totalsConsistent,\n expiryOk,\n },\n agentId,\n errors,\n };\n}\n\nfunction checkCartRef(triple: AP2MandateTriple, errors: string[]): boolean {\n const cart = triple.cart;\n if (!cart) return true;\n if (!cart.intent_mandate_id) return true;\n const intentId = triple.intent?.raw?.id as string | undefined;\n if (intentId && cart.intent_mandate_id !== intentId) {\n errors.push(\n `cart.intent_mandate_id (${cart.intent_mandate_id}) does not match intent.id (${intentId})`\n );\n return false;\n }\n return true;\n}\n\nfunction checkPaymentRef(triple: AP2MandateTriple, errors: string[]): boolean {\n const payment = triple.payment;\n if (!payment) return true;\n if (!payment.cart_mandate_id) return true;\n const cartId = triple.cart?.raw?.id as string | undefined;\n if (cartId && payment.cart_mandate_id !== cartId) {\n errors.push(\n `payment.cart_mandate_id (${payment.cart_mandate_id}) does not match cart.id (${cartId})`\n );\n return false;\n }\n return true;\n}\n\nfunction checkAgentContinuity(\n triple: AP2MandateTriple,\n errors: string[]\n): { ok: boolean; agentId?: string } {\n // Audit F-A1-03: previously returned ok: true when ids.length === 0,\n // letting agent_id-stripped triples pass. Now: at least one of the three\n // mandates must declare an agent_id. (If only some declare it, the unique\n // check still enforces consistency.)\n const ids = [triple.intent?.agent_id, triple.cart?.agent_id, triple.payment?.agent_id].filter(\n (id): id is string => typeof id === 'string' && id.length > 0\n );\n if (ids.length === 0) {\n errors.push('agent_id missing across all three mandates (intent/cart/payment)');\n return { ok: false };\n }\n const unique = new Set(ids);\n if (unique.size > 1) {\n errors.push(`agent_id mismatch across mandates: ${Array.from(unique).join(', ')}`);\n return { ok: false, agentId: undefined };\n }\n return { ok: true, agentId: ids[0] };\n}\n\nfunction checkPaymentMethod(triple: AP2MandateTriple, errors: string[]): boolean {\n const allowed = triple.intent?.paymentMethods;\n if (!allowed || allowed.length === 0) return true;\n // Audit F-A1-03: previously returned ok: true when payment_method missing,\n // letting strip-the-field attacks bypass the intent's paymentMethods\n // allowlist. Now: when payment mandate IS PRESENT, it MUST carry a\n // payment_method that the intent's allowlist authorises. Cart-only\n // flows (no payment mandate yet) are legitimate per AP2 spec — those\n // are exercised when the payment mandate is later signed; the\n // allowlist check fires at THAT point.\n if (!triple.payment) return true;\n const paymentMethod = triple.payment.payment_method;\n if (!paymentMethod) {\n errors.push(\n `payment.payment_method missing but intent declares allowlist [${allowed.join(', ')}]`\n );\n return false;\n }\n if (!allowed.includes(paymentMethod)) {\n errors.push(\n `payment_method \"${paymentMethod}\" not in intent.paymentMethods [${allowed.join(', ')}]`\n );\n return false;\n }\n return true;\n}\n\nfunction checkTotals(triple: AP2MandateTriple, errors: string[]): boolean {\n const intentTotal = toNumericAmount(triple.intent?.payment_details_total);\n const cartTotal = toNumericAmount(triple.cart?.payment_details_total);\n const paymentTotal = toNumericAmount(triple.payment?.payment_details_total);\n\n if (intentTotal && cartTotal && intentTotal.currency === cartTotal.currency) {\n if (cartTotal.value > intentTotal.value) {\n errors.push(\n `cart total ${cartTotal.value} ${cartTotal.currency} exceeds intent cap ${intentTotal.value}`\n );\n return false;\n }\n }\n if (cartTotal && paymentTotal && cartTotal.currency === paymentTotal.currency) {\n if (paymentTotal.value > cartTotal.value) {\n errors.push(\n `payment total ${paymentTotal.value} ${paymentTotal.currency} exceeds cart total ${cartTotal.value}`\n );\n return false;\n }\n }\n return true;\n}\n\nfunction checkExpiries(\n triple: AP2MandateTriple,\n toleranceSec: number,\n nowFn: (() => number) | undefined,\n errors: string[]\n): boolean {\n const now = nowFn ? nowFn() : Math.floor(Date.now() / 1000);\n let ok = true;\n\n // Audit F-A1-03: previously iterated only intent + cart; payment was\n // omitted, so expired payment mandates passed verification. Now includes\n // all three layers. AP2PaymentMandateClaims doesn't have a typed\n // `expires` field today (only intent/cart do); read from `raw.expires`\n // for payment as a defensive measure.\n const layers: Array<readonly [string, string | undefined]> = [\n ['intent', triple.intent?.expires],\n ['cart', triple.cart?.expires],\n [\n 'payment',\n typeof triple.payment?.raw?.expires === 'string'\n ? (triple.payment.raw.expires as string)\n : typeof triple.payment?.raw?.exp === 'string'\n ? (triple.payment.raw.exp as string)\n : undefined,\n ],\n ];\n\n for (const [name, expires] of layers) {\n if (!expires) continue;\n const parsed = parseExpiry(expires);\n if (parsed === null) {\n errors.push(`${name}.expires unparseable`);\n ok = false;\n continue;\n }\n if (now > parsed + toleranceSec) {\n errors.push(`${name} mandate expired at ${expires}`);\n ok = false;\n }\n }\n return ok;\n}\n\nfunction toNumericAmount(\n total: import('./ap2').AP2PaymentDetailsTotal | undefined\n): { value: number; currency: string } | null {\n if (!total?.amount?.value || !total.amount.currency) return null;\n const n =\n typeof total.amount.value === 'string' ? Number(total.amount.value) : total.amount.value;\n if (!Number.isFinite(n)) return null;\n return { value: n, currency: total.amount.currency };\n}\n\nfunction parseExpiry(value: string): number | null {\n const asInt = Number(value);\n if (Number.isFinite(asInt) && asInt > 0) {\n return asInt >= 1e12 ? Math.floor(asInt / 1000) : Math.floor(asInt);\n }\n const parsedDate = Date.parse(value);\n if (Number.isFinite(parsedDate)) return Math.floor(parsedDate / 1000);\n return null;\n}\n","/**\n * ACP detached-JSON-signature verifier.\n *\n * ACP (Agentic Commerce Protocol, OpenAI + Stripe) uses detached JSON\n * signatures over request bodies. The public signature algorithm is NOT\n * specified in open docs as of April 2026 (docs.stripe.com/agentic-commerce/*\n * is Private Preview). We implement Ed25519 and ES256 candidates against\n * whichever public key the caller supplies, and report algorithm-unsupported\n * as a trust signal rather than a hard fail so policy can weight it.\n *\n * Timestamp freshness (>300s default) IS a hard fail — prevents replay.\n *\n * Bearer-token → AstraSync agent binding is delegated to caller-supplied\n * resolver (typically the counterparty service).\n */\n\nimport type { JWK } from 'jose';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport type ACPSignatureAlgorithm = 'ed25519' | 'es256' | 'unsupported';\n\nexport interface ACPVerifyInput {\n /** Raw request body over which the signature was computed. */\n rawBody: string;\n /** Value of the Signature header. Expected to be base64 (either standard or url). */\n signatureHeader?: string;\n /** Value of the Timestamp header (unix seconds as string, or ISO 8601). */\n timestampHeader?: string;\n /** Candidate public keys to try. First matching algorithm wins. */\n candidateKeys: Array<{ jwk: JWK; alg?: ACPSignatureAlgorithm | string }>;\n /** Clock skew tolerance in seconds (default 60, tightened from 300). */\n clockSkewSec?: number;\n /** Injectable now for tests. */\n now?: () => number;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface ACPVerifyResult {\n ok: boolean;\n algorithm?: ACPSignatureAlgorithm;\n error?: string;\n /** True when timestamp is outside tolerance. */\n timestampStale?: boolean;\n}\n\nexport async function verifyACPSignature(input: ACPVerifyInput): Promise<ACPVerifyResult> {\n if (!input.signatureHeader) {\n return { ok: false, error: 'missing Signature header' };\n }\n\n const tolerance = input.clockSkewSec ?? 60;\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n const freshness = checkTimestamp(input.timestampHeader, tolerance, input.now);\n if (!freshness.ok) {\n return { ok: false, error: freshness.error, timestampStale: true };\n }\n\n // Audit F-A1-05: replay protection. Header comment claimed \"Timestamp\n // freshness IS a hard fail — prevents replay\" but implementation didn't\n // enforce it. Key on (signature header, timestamp) so the same signature\n // submitted twice within tolerance is rejected.\n const nowSec = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const expiresAtMs = (nowSec + tolerance) * 1000;\n const replayKey = `acp:${input.signatureHeader}:${input.timestampHeader ?? ''}`;\n if (nonceStore.seen(replayKey, expiresAtMs)) {\n return {\n ok: false,\n error: 'ACP signature replay — already seen within tolerance window',\n };\n }\n\n const signatureBytes = decodeBase64(input.signatureHeader);\n if (!signatureBytes) {\n return { ok: false, error: 'signature header is not valid base64' };\n }\n\n const bodyBytes = new TextEncoder().encode(input.rawBody);\n const { subtle } = await getSubtle();\n\n for (const candidate of input.candidateKeys) {\n const declaredAlg = normalizeAlgorithm(candidate.alg);\n const algsToTry: ACPSignatureAlgorithm[] =\n declaredAlg && declaredAlg !== 'unsupported' ? [declaredAlg] : ['ed25519', 'es256'];\n\n for (const alg of algsToTry) {\n try {\n const verified = await tryVerify(subtle, candidate.jwk, signatureBytes, bodyBytes, alg);\n if (verified) return { ok: true, algorithm: alg };\n } catch {\n // swallow per-candidate errors; try next algorithm/candidate\n }\n }\n }\n\n return {\n ok: false,\n algorithm: 'unsupported',\n error: 'no candidate key verified the signature under Ed25519 or ES256',\n };\n}\n\nasync function tryVerify(\n subtle: SubtleCrypto,\n jwk: JWK,\n signature: Uint8Array,\n body: Uint8Array,\n alg: ACPSignatureAlgorithm\n): Promise<boolean> {\n if (alg === 'ed25519') {\n if (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519') return false;\n const key = await subtle.importKey('jwk', jwk as JsonWebKey, { name: 'Ed25519' }, false, [\n 'verify',\n ]);\n return await subtle.verify({ name: 'Ed25519' }, key, toBuf(signature), toBuf(body));\n }\n if (alg === 'es256') {\n if (jwk.kty !== 'EC' || jwk.crv !== 'P-256') return false;\n const key = await subtle.importKey(\n 'jwk',\n jwk as JsonWebKey,\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['verify']\n );\n return await subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n key,\n toBuf(signature),\n toBuf(body)\n );\n }\n return false;\n}\n\nfunction toBuf(bytes: Uint8Array): ArrayBuffer {\n const out = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(out).set(bytes);\n return out;\n}\n\nfunction checkTimestamp(\n headerValue: string | undefined,\n toleranceSec: number,\n nowFn?: () => number\n): { ok: true } | { ok: false; error: string } {\n if (!headerValue) return { ok: false, error: 'missing Timestamp header' };\n const ts = parseTimestamp(headerValue);\n if (ts === null) return { ok: false, error: 'unparseable Timestamp header' };\n const now = nowFn ? nowFn() : Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > toleranceSec) {\n return { ok: false, error: `timestamp outside ${toleranceSec}s tolerance` };\n }\n return { ok: true };\n}\n\nfunction parseTimestamp(value: string): number | null {\n const asInt = Number(value);\n if (Number.isFinite(asInt) && asInt > 0) {\n // Treat >= 1e12 as milliseconds; otherwise seconds.\n return asInt >= 1e12 ? Math.floor(asInt / 1000) : Math.floor(asInt);\n }\n const parsedDate = Date.parse(value);\n if (Number.isFinite(parsedDate)) return Math.floor(parsedDate / 1000);\n return null;\n}\n\nfunction normalizeAlgorithm(alg: string | undefined): ACPSignatureAlgorithm | undefined {\n if (!alg) return undefined;\n const lowered = alg.toLowerCase();\n if (lowered === 'ed25519' || lowered === 'eddsa') return 'ed25519';\n if (lowered === 'es256' || lowered.startsWith('ecdsa-p256')) return 'es256';\n return 'unsupported';\n}\n\nfunction decodeBase64(value: string): Uint8Array | null {\n try {\n // Accept either standard base64 or url-safe; jose and node both accept both via Buffer.\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const pad = normalized.length % 4 === 0 ? '' : '='.repeat(4 - (normalized.length % 4));\n return new Uint8Array(Buffer.from(normalized + pad, 'base64'));\n } catch {\n return null;\n }\n}\n\nasync function getSubtle(): Promise<{ subtle: SubtleCrypto }> {\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n return { subtle: globalThis.crypto.subtle };\n }\n const nodeCrypto = await import('node:crypto');\n return { subtle: nodeCrypto.webcrypto.subtle as SubtleCrypto };\n}\n","/**\n * MPP (Machine Payments Protocol) extractor.\n *\n * Wraps mppx (wevm) — pinned to 0.5.13, wrapped behind this adapter so\n * upgrades localise here. MPP launched March 18 2026 (Stripe + Tempo +\n * Paradigm), IETF draft-ryan-httpauth-payment-01.\n *\n * Flow:\n * Client → GET /resource\n * Server → 402 + WWW-Authenticate: Payment id=..., realm=..., method=tempo|stripe|...\n * Client → GET /resource with Authorization: Payment <base64url-json credential>\n * Server → 200 + Payment-Receipt: <base64url-json receipt>\n *\n * What we extract:\n * - Challenge: id, realm, method, intent, request{amount,currency,...}, expires, digest\n * - Credential: challenge + source (DID/chain-key) + payload (method-specific)\n * - Receipt: challengeId, method, reference (tx hash / pi_... ID), settlement\n * - Multi-method 402 offers (may be multiple WWW-Authenticate headers)\n *\n * What we do NOT verify here (pass-through):\n * - HMAC challenge binding (requires merchant's MPP_SECRET_KEY)\n * - Payment proof cryptography (Tempo tx sig, Stripe SPT, Lightning preimage)\n * — each requires upstream connectivity\n *\n * Verification (expiry + BodyDigest + source extraction) in mpp-verify.ts.\n */\n\nimport { Challenge, Credential, Receipt } from 'mppx';\n\nexport interface MPPChallengeSummary {\n id: string;\n realm: string;\n method: string;\n intent: string;\n /** Method-specific request data (amount, currency, recipient, etc.) */\n request: Record<string, unknown>;\n expires?: string;\n digest?: string;\n description?: string;\n opaque?: Record<string, string>;\n}\n\nexport interface MPPCredentialSummary {\n challenge: MPPChallengeSummary;\n /** DID or chain-native key identifying the payer. */\n source?: string;\n /** Method-specific payment proof (Tempo tx, SPT, Lightning preimage, etc.). */\n payload: unknown;\n}\n\nexport interface MPPReceiptSummary {\n method?: string;\n reference?: string;\n externalId?: string;\n status?: string;\n timestamp?: string;\n raw: Record<string, unknown>;\n}\n\nexport type MPPKind = 'challenge' | 'credential' | 'receipt' | 'error' | 'unknown';\n\nexport interface MPPRequestContext {\n kind: MPPKind;\n /** For 402 responses: one or more challenge offers. */\n challenges?: MPPChallengeSummary[];\n /** For requests with Authorization: Payment header. */\n credential?: MPPCredentialSummary;\n /** For 200 responses with Payment-Receipt header. */\n receipt?: MPPReceiptSummary;\n /** For problem+json error responses. */\n error?: { type?: string; title?: string; detail?: string };\n /** Detected payment methods offered (for multi-method 402). */\n offeredMethods?: string[];\n /** Raw body captured for BodyDigest verification in mpp-verify.ts. */\n rawBody?: string;\n}\n\nexport interface MPPRequestLike {\n method: string;\n url: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: string;\n}\n\nexport interface MPPResponseLike {\n status: number;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: string;\n}\n\n/**\n * Extract MPP context from an agent → merchant request.\n * Looks for `Authorization: Payment <credential>` header.\n */\nexport function extractMPPFromRequest(request: MPPRequestLike): MPPRequestContext | null {\n const auth = readHeader(request.headers, 'authorization');\n if (!auth || !/^\\s*Payment\\s+/i.test(auth)) return null;\n\n try {\n const credential = Credential.deserialize(auth);\n return {\n kind: 'credential',\n credential: {\n challenge: summarizeChallenge(credential.challenge),\n source: credential.source,\n payload: credential.payload,\n },\n rawBody: request.rawBody,\n };\n } catch {\n return { kind: 'error', error: { type: 'invalid-credential-encoding' } };\n }\n}\n\n/**\n * Extract MPP context from a merchant → agent response.\n * Handles 402 (challenge offers), 200 (receipt), 4xx (problem+json errors).\n */\nexport function extractMPPFromResponse(response: MPPResponseLike): MPPRequestContext | null {\n if (response.status === 402) {\n const challenges = collectChallenges(response);\n if (challenges.length === 0) return null;\n const methods = Array.from(new Set(challenges.map((c) => c.method)));\n return {\n kind: 'challenge',\n challenges,\n offeredMethods: methods,\n };\n }\n\n const receiptHeader = readHeader(response.headers, 'payment-receipt');\n if (receiptHeader) {\n try {\n const parsed = Receipt.deserialize(receiptHeader);\n const r = parsed as unknown as Record<string, unknown>;\n return {\n kind: 'receipt',\n receipt: {\n method: coerceString(r.method),\n reference: coerceString(r.reference),\n externalId: coerceString(r.externalId ?? r.external_id),\n status: coerceString(r.status),\n timestamp: coerceString(r.timestamp),\n raw: r,\n },\n };\n } catch {\n return { kind: 'error', error: { type: 'invalid-receipt-encoding' } };\n }\n }\n\n const contentType = readHeader(response.headers, 'content-type');\n if (contentType && /application\\/problem\\+json/i.test(contentType)) {\n const body =\n typeof response.body === 'object' && response.body !== null\n ? (response.body as Record<string, unknown>)\n : {};\n return {\n kind: 'error',\n error: {\n type: coerceString(body.type),\n title: coerceString(body.title),\n detail: coerceString(body.detail),\n },\n };\n }\n\n return null;\n}\n\n/**\n * Extract from either a request OR a response, auto-detecting which has MPP\n * artifacts. Convenience for pipeline callers.\n */\nexport function extractMPPContext(\n message:\n | { request: MPPRequestLike }\n | { response: MPPResponseLike }\n | (MPPRequestLike & Partial<MPPResponseLike>)\n): MPPRequestContext | null {\n if ('request' in message) return extractMPPFromRequest(message.request);\n if ('response' in message) return extractMPPFromResponse(message.response);\n if (typeof (message as MPPResponseLike).status === 'number') {\n return extractMPPFromResponse(message as MPPResponseLike);\n }\n return extractMPPFromRequest(message as MPPRequestLike);\n}\n\nfunction collectChallenges(response: MPPResponseLike): MPPChallengeSummary[] {\n const wwwAuth = readHeader(response.headers, 'www-authenticate');\n if (!wwwAuth) return [];\n const headers = new Headers();\n headers.set('www-authenticate', wwwAuth);\n\n const out: MPPChallengeSummary[] = [];\n try {\n const list = Challenge.fromHeadersList(headers);\n for (const ch of list) {\n out.push(summarizeChallenge(ch as unknown as Challenge.Challenge));\n }\n } catch {\n // fall through with empty list\n }\n return out;\n}\n\nfunction summarizeChallenge(\n ch: Challenge.Challenge | Record<string, unknown>\n): MPPChallengeSummary {\n const raw = ch as Record<string, unknown>;\n return {\n id: coerceString(raw.id) ?? '',\n realm: coerceString(raw.realm) ?? '',\n method: coerceString(raw.method) ?? '',\n intent: coerceString(raw.intent) ?? '',\n request: (raw.request as Record<string, unknown>) ?? {},\n expires: coerceString(raw.expires),\n digest: coerceString(raw.digest),\n description: coerceString(raw.description),\n opaque: raw.opaque as Record<string, string> | undefined,\n };\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined>,\n name: string\n): string | undefined {\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw.join(', ');\n }\n }\n return undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * MPP verification — expiry + optional BodyDigest + source extraction.\n *\n * We do NOT verify the challenge's HMAC binding (needs merchant's secret)\n * or the cryptographic payment proof (per-method, requires upstream\n * connectivity). Those are the merchant's / settlement layer's job.\n *\n * Our job: structural correctness, expiry policy, tamper detection via\n * optional BodyDigest, and identity extraction for PDLSS binding.\n */\n\nimport { BodyDigest } from 'mppx';\nimport type { MPPRequestContext } from './mpp';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface MPPVerifyInput {\n context: MPPRequestContext;\n /** Raw request body to validate BodyDigest against, if the challenge declares one. */\n rawBody?: string;\n /** Seconds of clock-skew tolerance on challenge.expires. Default 60. */\n clockSkewSec?: number;\n /** Injectable for deterministic tests. */\n now?: () => number;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface MPPVerifyResult {\n ok: boolean;\n expiryOk: boolean;\n bodyDigestOk: boolean | null;\n source?: string;\n method?: string;\n error?: string;\n}\n\nexport function verifyMPP(input: MPPVerifyInput): MPPVerifyResult {\n const { context } = input;\n const tolerance = input.clockSkewSec ?? 60;\n const nowSec = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n // Extract the challenge under test — for credential flow, from inside the\n // wrapped challenge; for bare challenge flow, from context.challenges[0].\n const challenge = context.credential?.challenge ?? (context.challenges && context.challenges[0]);\n const source = context.credential?.source;\n const method = challenge?.method;\n\n let expiryOk = true;\n if (challenge?.expires) {\n const parsedExpiry = Date.parse(challenge.expires);\n if (!Number.isFinite(parsedExpiry)) {\n return {\n ok: false,\n expiryOk: false,\n bodyDigestOk: null,\n source,\n method,\n error: 'unparseable challenge.expires',\n };\n }\n const expiresSec = Math.floor(parsedExpiry / 1000);\n if (nowSec > expiresSec + tolerance) {\n expiryOk = false;\n }\n }\n\n // Audit F-A1-04: previously when rawBody was present but the challenge\n // omitted `digest`, bodyDigestOk stayed `null` and was treated as OK.\n // Attacker could strip the digest field from the challenge and tamper\n // with body. Now: when rawBody is present, digest is REQUIRED.\n let bodyDigestOk: boolean | null = null;\n if (input.rawBody !== undefined) {\n if (!challenge?.digest) {\n bodyDigestOk = false;\n } else {\n try {\n if (!/^sha-256=/.test(challenge.digest)) {\n bodyDigestOk = false;\n } else {\n bodyDigestOk = BodyDigest.verify(challenge.digest as `sha-256=${string}`, input.rawBody);\n }\n } catch {\n bodyDigestOk = false;\n }\n }\n }\n\n // Audit F-A1-05: replay protection. Use challenge nonce + digest as\n // replay key when available; fall back to digest alone. Window matches\n // the expiry tolerance.\n let replayOk = true;\n if (challenge?.digest && expiryOk) {\n const replayKey = `mpp:${challenge.digest}:${(challenge as { nonce?: string }).nonce ?? ''}`;\n const expiresAt = (nowSec + tolerance) * 1000;\n if (nonceStore.seen(replayKey, expiresAt)) {\n replayOk = false;\n }\n }\n\n const ok = expiryOk && (bodyDigestOk === null || bodyDigestOk === true) && replayOk;\n const errors: string[] = [];\n if (!expiryOk) errors.push('challenge expired');\n if (bodyDigestOk === false) {\n errors.push(\n input.rawBody !== undefined && !challenge?.digest\n ? 'body digest required when rawBody present'\n : 'body digest mismatch'\n );\n }\n if (!replayOk) errors.push('MPP challenge replay — already seen within tolerance window');\n\n return {\n ok,\n expiryOk,\n bodyDigestOk,\n source,\n method,\n error: errors.length > 0 ? errors.join('; ') : undefined,\n };\n}\n","/**\n * x402 (Coinbase / Linux Foundation x402 Foundation) extractor.\n *\n * Wraps @x402/core's schema parsers. x402 Foundation launched April 2 2026\n * with v2 adding network-agnostic identifiers + multiple facilitators +\n * Bazaar discovery. MPP (Machine Payments Protocol) is the IETF-formalised\n * superset of x402; this module normalizes x402 output to MPP-shape so\n * downstream pipeline code is uniform.\n *\n * Where x402 lives on the wire:\n * - 402 response body (v2) OR `X-PAYMENT-REQUIRED` header (v1) — PaymentRequired\n * - Request body (v2) OR `X-PAYMENT` header (v1, base64) — PaymentPayload\n */\n\nimport {\n validatePaymentRequired,\n validatePaymentPayload,\n type PaymentRequired,\n type PaymentPayload,\n type PaymentRequirements,\n} from '@x402/core/schemas';\nimport { safeBase64Decode } from '@x402/core/utils';\n\nexport type X402Kind = 'required' | 'payload' | 'error' | 'unknown';\n\nexport interface X402RequirementsSummary {\n scheme: string;\n network: string;\n asset: string;\n /** Normalized to string for v1/v2 compat — v1 uses maxAmountRequired, v2 uses amount. */\n amount: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n resource?: string;\n description?: string;\n}\n\nexport interface X402RequestContext {\n kind: X402Kind;\n version: 1 | 2 | null;\n /** For 402 responses: the PaymentRequired body. */\n paymentRequired?: {\n resource: string;\n accepts: X402RequirementsSummary[];\n extensions?: Record<string, unknown>;\n error?: string;\n };\n /** For request body (v2) or X-PAYMENT header (v1 base64): the PaymentPayload. */\n paymentPayload?: {\n scheme: string;\n network: string;\n /** Free-form per-scheme payload (e.g. EIP-3009 authorization, Solana tx). */\n payload: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n };\n error?: { type: string; detail?: string };\n /** Whether this was parsed from a header (v1 back-compat) or body (v2). */\n source: 'header' | 'body' | null;\n}\n\nexport interface X402RequestLike {\n method?: string;\n url?: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\nexport interface X402ResponseLike {\n status?: number;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\n/**\n * Extract x402 PaymentPayload from an agent → merchant request.\n * Checks v2 body (if it parses as PaymentPayload) and v1 X-PAYMENT header.\n */\nexport function extractX402FromRequest(request: X402RequestLike): X402RequestContext | null {\n const headerValue = readHeader(request.headers, 'x-payment');\n\n // v2 body path first\n if (request.body && typeof request.body === 'object') {\n const parsed = tryParsePayload(request.body);\n if (parsed) return buildPayloadContext(parsed, 'body');\n }\n\n // v1 header path\n if (headerValue) {\n try {\n const decoded = safeBase64Decode(headerValue);\n if (decoded) {\n const json = JSON.parse(decoded);\n const parsed = tryParsePayload(json);\n if (parsed) return buildPayloadContext(parsed, 'header');\n }\n } catch {\n return {\n kind: 'error',\n version: 1,\n source: 'header',\n error: { type: 'invalid-x402-payload' },\n };\n }\n }\n\n return null;\n}\n\n/**\n * Extract x402 PaymentRequired from a merchant → agent 402 response.\n */\nexport function extractX402FromResponse(response: X402ResponseLike): X402RequestContext | null {\n if (response.status !== 402) return null;\n\n // v2 body path\n if (response.body && typeof response.body === 'object') {\n const parsed = tryParseRequired(response.body);\n if (parsed) return buildRequiredContext(parsed, 'body');\n }\n\n // v1 header path\n const headerValue = readHeader(response.headers, 'x-payment-required');\n if (headerValue) {\n try {\n const decoded = safeBase64Decode(headerValue);\n if (decoded) {\n const json = JSON.parse(decoded);\n const parsed = tryParseRequired(json);\n if (parsed) return buildRequiredContext(parsed, 'header');\n }\n } catch {\n return {\n kind: 'error',\n version: 1,\n source: 'header',\n error: { type: 'invalid-x402-required' },\n };\n }\n }\n\n return null;\n}\n\nexport function extractX402Context(\n message:\n | { request: X402RequestLike }\n | { response: X402ResponseLike }\n | (X402RequestLike & Partial<X402ResponseLike>)\n): X402RequestContext | null {\n if ('request' in message) return extractX402FromRequest(message.request);\n if ('response' in message) return extractX402FromResponse(message.response);\n if (typeof (message as X402ResponseLike).status === 'number') {\n return extractX402FromResponse(message as X402ResponseLike);\n }\n return extractX402FromRequest(message as X402RequestLike);\n}\n\nfunction tryParseRequired(data: unknown): PaymentRequired | null {\n try {\n return validatePaymentRequired(data);\n } catch {\n return null;\n }\n}\n\nfunction tryParsePayload(data: unknown): PaymentPayload | null {\n try {\n return validatePaymentPayload(data);\n } catch {\n return null;\n }\n}\n\nfunction buildRequiredContext(\n parsed: PaymentRequired,\n source: 'header' | 'body'\n): X402RequestContext {\n const asRecord = parsed as unknown as Record<string, unknown>;\n const version = coerceVersion(asRecord.x402Version);\n const accepts = (asRecord.accepts as PaymentRequirements[] | undefined) ?? [];\n return {\n kind: 'required',\n version,\n source,\n paymentRequired: {\n resource: resolveResource(asRecord.resource),\n accepts: accepts.map(summarizeRequirement),\n extensions: asRecord.extensions as Record<string, unknown> | undefined,\n error: typeof asRecord.error === 'string' ? asRecord.error : undefined,\n },\n };\n}\n\nfunction buildPayloadContext(\n parsed: PaymentPayload,\n source: 'header' | 'body'\n): X402RequestContext {\n const asRecord = parsed as unknown as Record<string, unknown>;\n const version = coerceVersion(asRecord.x402Version);\n const accepted = asRecord.accepted as PaymentRequirements | undefined;\n const payload = (asRecord.payload as Record<string, unknown>) ?? {};\n return {\n kind: 'payload',\n version,\n source,\n paymentPayload: {\n scheme: accepted?.scheme ?? (typeof asRecord.scheme === 'string' ? asRecord.scheme : ''),\n network: accepted?.network ?? (typeof asRecord.network === 'string' ? asRecord.network : ''),\n payload,\n extensions: asRecord.extensions as Record<string, unknown> | undefined,\n },\n };\n}\n\nfunction summarizeRequirement(req: PaymentRequirements): X402RequirementsSummary {\n const r = req as unknown as Record<string, unknown>;\n const amount = (r.amount ?? r.maxAmountRequired ?? '0') as string;\n return {\n scheme: (r.scheme as string) ?? '',\n network: (r.network as string) ?? '',\n asset: (r.asset as string) ?? '',\n amount: String(amount),\n payTo: (r.payTo as string) ?? '',\n maxTimeoutSeconds: typeof r.maxTimeoutSeconds === 'number' ? r.maxTimeoutSeconds : undefined,\n resource: typeof r.resource === 'string' ? r.resource : undefined,\n description: typeof r.description === 'string' ? r.description : undefined,\n };\n}\n\nfunction resolveResource(v: unknown): string {\n if (typeof v === 'string') return v;\n if (v && typeof v === 'object' && 'url' in v && typeof (v as { url: unknown }).url === 'string') {\n return (v as { url: string }).url;\n }\n return '';\n}\n\nfunction coerceVersion(v: unknown): 1 | 2 | null {\n if (v === 1 || v === 2) return v;\n return null;\n}\n\nfunction readHeader(\n headers: Record<string, string | string[] | undefined> | undefined,\n name: string\n): string | undefined {\n if (!headers) return undefined;\n for (const key of Object.keys(headers)) {\n if (key.toLowerCase() === name) {\n const raw = headers[key];\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) return raw[0];\n }\n }\n return undefined;\n}\n","/**\n * VI (Verifiable Intent) 3-layer SD-JWT chain verification.\n *\n * VI chains: L1 (credential provider → wallet) → L2 (user → agent) → L3\n * (agent → merchant). L3 itself can split into L3a (payment mandate) + L3b\n * (checkout mandate) cross-referenced via transaction_id, with L3b carrying\n * a checkout_hash (VI constraint type 8) that must match SHA-256 of the L2\n * checkout disclosure.\n *\n * Signature primitives are delegated to @sd-jwt/core (via our extractor);\n * cnf.jwk chain-walking + cross-references + checkout_hash binding is\n * AstraSync-specific composition logic — that's the whitespace here.\n *\n * This module does NOT re-verify selective-disclosure hashes (the extractor\n * already applied them via @sd-jwt/core). It DOES verify:\n * - cnf.jwk in L1 payload points to L2's signing key (thumbprint match)\n * - cnf.jwk in L2 payload points to L3's signing key\n * - L3a.transaction_id === L3b.transaction_id (when both present)\n * - L3b.checkout_hash === SHA-256(L2 canonical checkout disclosure) — type 8\n * - mandate-level `exp` is not in the past (beyond clock skew)\n *\n * Cryptographic signature verification on each layer uses the verifier\n * callback the caller supplies (e.g. resolves via @sd-jwt/core with the\n * right JWK from the L1 issuer's JWKS).\n */\n\nimport { createHash, webcrypto } from 'node:crypto';\nimport type { JWK } from 'jose';\nimport { defaultNonceStore, type NonceStore } from './nonce-store';\n\nexport interface VILayer {\n /** Compact SD-JWT / JWS for this layer. */\n compact: string;\n /** Decoded JWT payload (already disclosure-merged). */\n payload: Record<string, unknown>;\n /** Decoded JWT header. */\n header: Record<string, unknown>;\n}\n\nexport interface VIVerifyInput {\n /**\n * Layers in chain order. L1 is REQUIRED by default —\n * without L1 there is no chain root and L2 can be verified against any\n * attacker-supplied key. Callers who have resolved L2's signing key by\n * a trusted out-of-band mechanism (wallet binding, prior protocol step)\n * MUST set `allowUnboundChain: true` AND supply `expectedL2Key`.\n */\n layers: {\n l1?: VILayer;\n l2: VILayer;\n l3a?: VILayer;\n l3b?: VILayer;\n };\n /**\n * Verifier callback invoked per layer. Should return true iff the layer's\n * JWS signature verifies against the resolved public key (for L2 this is\n * L1's cnf.jwk; for L3 this is L2's cnf.jwk; for L1 this is the issuer's\n * JWKS per `iss` claim).\n */\n verifySignature: (layer: VILayer, expectedKey: JWK | null) => Promise<boolean>;\n /**\n * Clock skew tolerance in seconds for expiry checks. Default 60s\n * (tightened from the previous 300s default).\n */\n clockSkewSec?: number;\n now?: () => number;\n /**\n * Explicit opt-in to verify a chain with L1 omitted.\n * Defaults to false. When true, `expectedL2Key` MUST also be supplied\n * (used as the expected signing key for L2 verification).\n */\n allowUnboundChain?: boolean;\n /** Required when allowUnboundChain === true. */\n expectedL2Key?: JWK;\n /** Optional replay-protection store. Defaults to in-process LRU. */\n nonceStore?: NonceStore;\n}\n\nexport interface VIVerifyResult {\n ok: boolean;\n checks: {\n l1SigOk: boolean | null;\n l2SigOk: boolean;\n l3aSigOk: boolean | null;\n l3bSigOk: boolean | null;\n l1BindsL2: boolean;\n l2BindsL3: boolean;\n l3aL3bTxnIdMatch: boolean | null;\n checkoutHashOk: boolean | null;\n expiryOk: boolean;\n };\n errors: string[];\n}\n\nexport async function verifyVIChain(input: VIVerifyInput): Promise<VIVerifyResult> {\n const errors: string[] = [];\n const tolerance = input.clockSkewSec ?? 60;\n const now = input.now ? input.now() : Math.floor(Date.now() / 1000);\n const { l1, l2, l3a, l3b } = input.layers;\n const nonceStore = input.nonceStore ?? defaultNonceStore;\n\n // Audit F-A1-02: L1 is required unless caller explicitly opts into an\n // unbound chain AND supplies the expected L2 signing key. Otherwise L2\n // would be verified against null, which most verifier callbacks\n // interpret as \"use the JWK in the JWS header\" — accepting any\n // attacker-supplied key.\n if (!l1) {\n if (!input.allowUnboundChain) {\n errors.push(\n 'L1 missing — chain root unbound (set allowUnboundChain + expectedL2Key to override)'\n );\n } else if (!input.expectedL2Key) {\n errors.push('allowUnboundChain set but expectedL2Key missing');\n }\n }\n\n // Signature verification ---------------------------------\n const l1SigOk = l1 ? await input.verifySignature(l1, null) : null;\n if (l1 && !l1SigOk) errors.push('L1 signature invalid');\n\n const l1Cnf = extractCnfJwk(l1?.payload);\n // Use L1's cnf.jwk when L1 present; otherwise (opt-in unbound chain) use\n // the caller-supplied expectedL2Key. Never null — F-A1-02.\n const l2ExpectedKey: JWK | null = l1Cnf ?? input.expectedL2Key ?? null;\n const l2SigOk = await input.verifySignature(l2, l2ExpectedKey);\n if (!l2SigOk) errors.push('L2 signature invalid');\n\n // Audit F-A1-05: replay protection on L2 signature. Use the compact JWS\n // as the nonce key; the signature is unique per request. Window matches\n // tolerance (denied replays past the window are already rejected by\n // expiry check, so we don't need to retain entries longer).\n if (l2SigOk) {\n const replayKey = `vi:l2:${l2.compact}`;\n const expiresAt = now * 1000 + tolerance * 1000;\n if (nonceStore.seen(replayKey, expiresAt)) {\n errors.push('L2 signature replay — already seen within tolerance window');\n }\n }\n\n const l2Cnf = extractCnfJwk(l2.payload);\n const l3aSigOk = l3a ? await input.verifySignature(l3a, l2Cnf ?? null) : null;\n if (l3a && !l3aSigOk) errors.push('L3a signature invalid');\n const l3bSigOk = l3b ? await input.verifySignature(l3b, l2Cnf ?? null) : null;\n if (l3b && !l3bSigOk) errors.push('L3b signature invalid');\n\n // cnf.jwk binding ----------------------------------------\n let l1BindsL2 = true;\n if (l1Cnf) {\n const l2KeyFromHeader = await jwkForLayer(l2);\n l1BindsL2 = l2KeyFromHeader ? await thumbprintsMatch(l1Cnf, l2KeyFromHeader) : false;\n if (!l1BindsL2) errors.push('L1.cnf.jwk does not bind L2 signing key');\n }\n\n let l2BindsL3 = true;\n if (l2Cnf && (l3a || l3b)) {\n const l3Layer = l3a ?? l3b!;\n const l3KeyFromHeader = await jwkForLayer(l3Layer);\n l2BindsL3 = l3KeyFromHeader ? await thumbprintsMatch(l2Cnf, l3KeyFromHeader) : false;\n if (!l2BindsL3) errors.push('L2.cnf.jwk does not bind L3 signing key');\n }\n\n // L3a/L3b cross-reference --------------------------------\n let l3aL3bTxnIdMatch: boolean | null = null;\n if (l3a && l3b) {\n const a = coerceString(l3a.payload.transaction_id ?? l3a.payload.transactionId);\n const b = coerceString(l3b.payload.transaction_id ?? l3b.payload.transactionId);\n if (a && b) {\n l3aL3bTxnIdMatch = a === b;\n if (!l3aL3bTxnIdMatch) {\n errors.push(`L3a.transaction_id (${a}) does not match L3b.transaction_id (${b})`);\n }\n }\n }\n\n // checkout_hash (VI constraint type 8) -------------------\n let checkoutHashOk: boolean | null = null;\n if (l3b) {\n const declaredHash = coerceString(\n l3b.payload.checkout_hash ??\n l3b.payload.conditional_transaction_id ??\n (l3b.payload.payment_reference as Record<string, unknown> | undefined)?.checkout_hash\n );\n if (declaredHash) {\n const computed = computeCheckoutHashFromL2(l2);\n checkoutHashOk = computed ? declaredHash === computed : false;\n if (!checkoutHashOk) {\n errors.push('L3b.checkout_hash does not match SHA-256 of L2 checkout disclosure');\n }\n }\n }\n\n // Expiry policy ------------------------------------------\n const expiryOk = checkExpiryAcross([l1, l2, l3a, l3b], tolerance, now, errors);\n\n // Audit F-A1-02 + F-A1-05: ok also requires the chain-root + replay\n // checks above to have passed (errors array captures both). Previously\n // `ok` was derived purely from individual check booleans, so the L1-\n // required errors and replay-detected errors didn't gate it.\n const noUnboundChainOrReplayErrors = !errors.some(\n (e) =>\n e.startsWith('L1 missing') ||\n e.startsWith('allowUnboundChain set') ||\n e.startsWith('L2 signature replay')\n );\n\n const ok =\n l1SigOk !== false &&\n l2SigOk &&\n l3aSigOk !== false &&\n l3bSigOk !== false &&\n l1BindsL2 &&\n l2BindsL3 &&\n l3aL3bTxnIdMatch !== false &&\n checkoutHashOk !== false &&\n expiryOk &&\n noUnboundChainOrReplayErrors;\n\n return {\n ok,\n checks: {\n l1SigOk,\n l2SigOk,\n l3aSigOk,\n l3bSigOk,\n l1BindsL2,\n l2BindsL3,\n l3aL3bTxnIdMatch,\n checkoutHashOk,\n expiryOk,\n },\n errors,\n };\n}\n\nfunction extractCnfJwk(payload: Record<string, unknown> | undefined): JWK | null {\n if (!payload) return null;\n const cnf = payload.cnf as Record<string, unknown> | undefined;\n if (!cnf) return null;\n const jwk = cnf.jwk as JWK | undefined;\n return jwk ?? null;\n}\n\nasync function jwkForLayer(layer: VILayer): Promise<JWK | null> {\n // Prefer explicit cnf.jwk in the header, then payload; fallback to null.\n const fromHeader = extractCnfJwk(layer.header);\n if (fromHeader) return fromHeader;\n const fromPayload = extractCnfJwk(layer.payload);\n return fromPayload;\n}\n\nasync function thumbprintsMatch(a: JWK, b: JWK): Promise<boolean> {\n try {\n const ta = await jwkThumbprint(a);\n const tb = await jwkThumbprint(b);\n return ta === tb;\n } catch {\n return false;\n }\n}\n\n// RFC 7638 thumbprint: SHA-256 over the canonical JSON of required JWK members.\nasync function jwkThumbprint(jwk: JWK): Promise<string> {\n const canonical = canonicalJwk(jwk);\n const bytes = new TextEncoder().encode(JSON.stringify(canonical));\n const subtle = webcrypto.subtle as SubtleCrypto;\n const buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n const source = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(source).set(bytes);\n subtle.digest('SHA-256', source).then(resolve).catch(reject);\n });\n return Buffer.from(new Uint8Array(buffer)).toString('base64url').replace(/=+$/, '');\n}\n\nfunction canonicalJwk(jwk: JWK): Record<string, string> {\n // Per RFC 7638: members must appear in lexicographic order; only required\n // fields per kty are included.\n if (jwk.kty === 'EC') {\n return { crv: jwk.crv ?? '', kty: 'EC', x: jwk.x ?? '', y: jwk.y ?? '' };\n }\n if (jwk.kty === 'OKP') {\n return { crv: jwk.crv ?? '', kty: 'OKP', x: jwk.x ?? '' };\n }\n if (jwk.kty === 'RSA') {\n return { e: jwk.e ?? '', kty: 'RSA', n: jwk.n ?? '' };\n }\n return { kty: jwk.kty ?? '' };\n}\n\nfunction computeCheckoutHashFromL2(l2: VILayer): string | null {\n const checkoutDisclosure = (l2.payload.checkout ?? l2.payload.checkout_mandate) as unknown;\n if (!checkoutDisclosure) return null;\n const canonical = canonicalStringify(checkoutDisclosure);\n const hash = createHash('sha256').update(canonical).digest('base64url').replace(/=+$/, '');\n return hash;\n}\n\nfunction canonicalStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return '[' + value.map(canonicalStringify).join(',') + ']';\n const entries = Object.entries(value as Record<string, unknown>).sort(([a], [b]) =>\n a < b ? -1 : a > b ? 1 : 0\n );\n return (\n '{' + entries.map(([k, v]) => JSON.stringify(k) + ':' + canonicalStringify(v)).join(',') + '}'\n );\n}\n\nfunction checkExpiryAcross(\n layers: Array<VILayer | undefined>,\n toleranceSec: number,\n nowSec: number,\n errors: string[]\n): boolean {\n let ok = true;\n const names = ['L1', 'L2', 'L3a', 'L3b'];\n layers.forEach((layer, idx) => {\n if (!layer) return;\n const exp = toUnixSeconds(layer.payload.exp ?? layer.payload.expires);\n if (exp === undefined) return;\n if (nowSec > exp + toleranceSec) {\n errors.push(`${names[idx]} mandate expired at ${exp}`);\n ok = false;\n }\n });\n return ok;\n}\n\nfunction toUnixSeconds(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string') {\n const asInt = Number(v);\n if (Number.isFinite(asInt) && asInt > 0) {\n return asInt >= 1e12 ? Math.floor(asInt / 1000) : Math.floor(asInt);\n }\n const parsed = Date.parse(v);\n if (Number.isFinite(parsed)) return Math.floor(parsed / 1000);\n }\n return undefined;\n}\n\nfunction coerceString(v: unknown): string | undefined {\n return typeof v === 'string' && v.length > 0 ? v : undefined;\n}\n","/**\n * Commerce pipeline orchestrator.\n *\n * Ties together extractors + verifiers + identity binding + constraint\n * evaluation + trust signals into a single CommerceContext result.\n *\n * This is AstraSync whitespace: the orchestration over the library-backed\n * primitives. The backend verify-access service is the sole per-request\n * caller — the edge adapters forward raw artifacts to verify-access and\n * never call this module directly. The admin transport playground also\n * calls it ad-hoc.\n *\n * Policy:\n * - Hard-deny (ok=false) on bad signatures, expired mandates, constraint\n * failures, identity cannot be bound.\n * - Trust signal (ok remains policy-driven) on ACP algorithm unsupported,\n * Stripe webhook HMAC fail, payment-token type unknown, cross-layer\n * identity mismatch.\n */\n\nimport type { ACPRequestContext } from './acp';\nimport { verifyACPSignature, type ACPVerifyResult } from './acp-verify';\nimport type { AP2MandateTriple } from './ap2';\nimport { verifyAP2Chain, type AP2ChainResult } from './ap2-verify';\nimport {\n evaluateVIConstraints,\n evaluatePaymentMethodAllowlist,\n evaluateSpendingLimit,\n type ConstraintEvalResult,\n type TransactionContext,\n} from './constraint-eval';\nimport { bindIdentity, type IdentityClaim, type IdentityResolver } from './identity-binding';\nimport { verifyMPP, type MPPVerifyResult } from './mpp-verify';\nimport type { MPPRequestContext } from './mpp';\nimport {\n mapACPRequestToPurpose,\n mapMPPRequestToPurpose,\n mapRFC9421TagToPurpose,\n mapUCPRequestToPurpose,\n mapVIMandateToPurpose,\n mapX402RequestToPurpose,\n type CommercePurpose,\n} from './purpose-mapping';\nimport {\n verifyRFC9421,\n type RFC9421VerifyResult,\n type RFC9421VerifyRequest,\n} from './rfc9421-verify';\nimport { verifyStripeWebhook, type VerifyStripeWebhookResult } from './stripe-webhook';\nimport {\n extractACPTransactionValue,\n extractMPPTransactionValue,\n extractUCPTransactionValue,\n extractVITransactionValue,\n extractX402TransactionValue,\n type TransactionValueContext,\n} from './transaction-value';\nimport type { UCPCheckoutContext } from './ucp';\nimport { verifyVIChain, type VIVerifyInput, type VIVerifyResult } from './vi-verify';\nimport type { VIExtractedClaims } from './vi';\nimport type { X402RequestContext } from './x402';\n\nexport type CommerceProtocol = 'vi' | 'ap2' | 'ucp' | 'acp' | 'agentpay' | 'tap' | 'mpp' | 'x402';\n\nexport interface CommercePipelineInput {\n protocol: CommerceProtocol;\n vi?: { claims: VIExtractedClaims; verifyInput?: VIVerifyInput };\n ap2?: { triple: AP2MandateTriple };\n ucp?: UCPCheckoutContext;\n acp?: {\n context: ACPRequestContext;\n verifyInput?: Parameters<typeof verifyACPSignature>[0];\n };\n rfc9421?: {\n request: RFC9421VerifyRequest;\n tag?: 'browse' | 'purchase' | string;\n verifyOptions: Parameters<typeof verifyRFC9421>[1];\n };\n mpp?: { context: MPPRequestContext; rawBody?: string };\n x402?: X402RequestContext;\n stripeWebhook?: { payload: string; signatureHeader: string; secret: string };\n transaction?: TransactionContext;\n registeredConstraints?: {\n allowedPaymentMethods?: string[];\n spendingLimit?: { amount?: number; currency?: string };\n };\n identityResolver?: IdentityResolver;\n clockSkewSec?: number;\n now?: () => number;\n}\n\nexport interface CommerceSignatureStack {\n vi?: VIVerifyResult;\n ap2?: AP2ChainResult;\n acp?: ACPVerifyResult;\n rfc9421?: RFC9421VerifyResult;\n mpp?: MPPVerifyResult;\n stripeWebhook?: VerifyStripeWebhookResult;\n}\n\nexport interface CommerceContext {\n protocol: CommerceProtocol;\n purpose: CommercePurpose | null;\n transactionValue?: TransactionValueContext;\n signatures: CommerceSignatureStack;\n identity?: {\n claims: IdentityClaim[];\n mappedAstraSyncAgentId?: string;\n mismatchAcrossLayers: boolean;\n };\n paymentToken?: {\n present: boolean;\n type: 'stripe-spt' | 'acp-vt' | 'tempo-tx' | 'other' | null;\n };\n mppMethodsOffered?: string[];\n constraints?: ConstraintEvalResult;\n receipt?: {\n method?: string;\n reference?: string;\n status?: string;\n timestamp?: string;\n };\n trustSignals: string[];\n timings: { extractMs: number; verifyMs: number; evalMs: number };\n /** False when any hard-deny rule fires. */\n ok: boolean;\n}\n\nexport async function runCommercePipeline(input: CommercePipelineInput): Promise<CommerceContext> {\n const trustSignals: string[] = [];\n const signatures: CommerceSignatureStack = {};\n const timings = { extractMs: 0, verifyMs: 0, evalMs: 0 };\n\n const extractStart = performance.now();\n const purpose = resolvePurpose(input);\n const transactionValue = resolveTransactionValue(input);\n const identityClaims = collectIdentityClaims(input);\n const paymentToken = resolvePaymentToken(input);\n timings.extractMs = Math.round(performance.now() - extractStart);\n\n const verifyStart = performance.now();\n let hardDeny = false;\n\n if (input.vi?.verifyInput) {\n signatures.vi = await verifyVIChain(input.vi.verifyInput);\n if (!signatures.vi.ok) hardDeny = true;\n }\n\n if (input.ap2) {\n signatures.ap2 = verifyAP2Chain({\n triple: input.ap2.triple,\n clockSkewSec: input.clockSkewSec,\n now: input.now,\n });\n if (!signatures.ap2.ok) hardDeny = true;\n }\n\n if (input.acp?.verifyInput) {\n signatures.acp = await verifyACPSignature(input.acp.verifyInput);\n if (!signatures.acp.ok && signatures.acp.timestampStale) hardDeny = true;\n if (signatures.acp.algorithm === 'unsupported') {\n trustSignals.push('acp-signature-algorithm-unsupported');\n } else if (!signatures.acp.ok) {\n hardDeny = true;\n }\n }\n\n if (input.rfc9421) {\n signatures.rfc9421 = await verifyRFC9421(input.rfc9421.request, input.rfc9421.verifyOptions);\n if (!signatures.rfc9421.ok) hardDeny = true;\n }\n\n if (input.mpp) {\n signatures.mpp = verifyMPP({\n context: input.mpp.context,\n rawBody: input.mpp.rawBody,\n clockSkewSec: input.clockSkewSec,\n now: input.now,\n });\n if (!signatures.mpp.ok) hardDeny = true;\n if (input.mpp.context.credential?.source) {\n trustSignals.push(`mpp-source-${shortSource(input.mpp.context.credential.source)}`);\n }\n }\n\n if (input.stripeWebhook) {\n signatures.stripeWebhook = verifyStripeWebhook(\n input.stripeWebhook.payload,\n input.stripeWebhook.signatureHeader,\n input.stripeWebhook.secret,\n { now: input.now ? () => input.now!() : undefined }\n );\n if (!signatures.stripeWebhook.ok) {\n trustSignals.push('stripe-webhook-hmac-failed');\n }\n }\n timings.verifyMs = Math.round(performance.now() - verifyStart);\n\n let identity: CommerceContext['identity'];\n if (input.identityResolver && identityClaims.length > 0) {\n const bound = await bindIdentity(identityClaims, input.identityResolver);\n identity = {\n claims: identityClaims,\n mappedAstraSyncAgentId: bound.mappedAstraSyncAgentId,\n mismatchAcrossLayers: bound.mismatchAcrossLayers,\n };\n if (bound.mismatchAcrossLayers) trustSignals.push('identity-mismatch-across-layers');\n } else if (identityClaims.length > 0) {\n identity = {\n claims: identityClaims,\n mappedAstraSyncAgentId: undefined,\n mismatchAcrossLayers: false,\n };\n }\n\n const evalStart = performance.now();\n const constraints = runConstraintEval(input);\n if (constraints && !constraints.ok) hardDeny = true;\n timings.evalMs = Math.round(performance.now() - evalStart);\n\n if (paymentToken?.type === 'stripe-spt') trustSignals.push('stripe-spt-present');\n if (paymentToken?.type === 'acp-vt') trustSignals.push('acp-vault-token-present');\n if (paymentToken?.type === 'tempo-tx') trustSignals.push('tempo-transaction-present');\n\n const mppReceipt = input.mpp?.context.receipt;\n\n return {\n protocol: input.protocol,\n purpose,\n transactionValue,\n signatures,\n identity,\n paymentToken,\n mppMethodsOffered: input.mpp?.context.offeredMethods,\n constraints,\n receipt: mppReceipt\n ? {\n method: mppReceipt.method,\n reference: mppReceipt.reference,\n status: mppReceipt.status,\n timestamp: mppReceipt.timestamp,\n }\n : undefined,\n trustSignals,\n timings,\n ok: !hardDeny,\n };\n}\n\nfunction resolvePurpose(input: CommercePipelineInput): CommercePurpose | null {\n if (input.vi?.claims.mandateType) {\n return mapVIMandateToPurpose(input.vi.claims.mandateType);\n }\n if (input.ap2?.triple.payment) return 'commerce.payment.execute';\n if (input.ap2?.triple.cart) return 'commerce.checkout.confirm';\n if (input.ap2?.triple.intent) return 'commerce.delegation.intent';\n if (input.ucp?.endpoint) {\n const [method, path] = input.ucp.endpoint.split(' ');\n return mapUCPRequestToPurpose(method ?? 'POST', path ?? '/');\n }\n if (input.acp?.context.endpoint) {\n // Extractor classifies as 'checkout_sessions.create|update|complete|cancel'\n // or 'delegate_payment'. Route each to the correct purpose.\n switch (input.acp.context.endpoint) {\n case 'checkout_sessions.create':\n return 'commerce.checkout.create';\n case 'checkout_sessions.update':\n return 'commerce.checkout.update';\n case 'checkout_sessions.complete':\n return 'commerce.payment.execute';\n case 'checkout_sessions.cancel':\n return 'commerce.checkout.cancel';\n case 'delegate_payment':\n return 'commerce.delegation.payment';\n default:\n return mapACPRequestToPurpose('POST', '/checkout_sessions');\n }\n }\n if (input.rfc9421?.tag) {\n return mapRFC9421TagToPurpose(\n input.rfc9421.tag === 'browse' || input.rfc9421.tag === 'purchase'\n ? (input.rfc9421.tag as 'browse' | 'purchase')\n : undefined\n );\n }\n if (input.mpp?.context.credential?.challenge || input.mpp?.context.challenges?.[0]) {\n const challenge = input.mpp.context.credential?.challenge ?? input.mpp.context.challenges?.[0];\n const amount = parseFloat(String(challenge?.request?.amount ?? 'NaN'));\n return mapMPPRequestToPurpose(\n challenge?.intent === 'session' ? 'session' : 'charge',\n Number.isFinite(amount) ? amount : undefined\n );\n }\n if (input.x402?.paymentRequired) {\n const amt = input.x402.paymentRequired.accepts[0]?.amount;\n return mapX402RequestToPurpose(Number(amt));\n }\n if (input.x402?.paymentPayload) return 'commerce.payment.execute';\n return null;\n}\n\nfunction resolveTransactionValue(\n input: CommercePipelineInput\n): TransactionValueContext | undefined {\n if (input.vi?.claims) {\n const v = extractVITransactionValue({\n constraints: input.vi.claims.constraints,\n l3aPaymentAmount: (input.vi.claims.constraints.paymentAmount &&\n typeof input.vi.claims.constraints.paymentAmount.max === 'number'\n ? {\n amount: input.vi.claims.constraints.paymentAmount.max,\n currency: input.vi.claims.constraints.paymentAmount.currency,\n }\n : undefined) as { amount?: number; currency?: string } | undefined,\n });\n if (v) return v;\n }\n if (input.ucp?.totals) {\n const v = extractUCPTransactionValue({ totals: input.ucp.totals });\n if (v) return v;\n }\n if (input.acp?.context.totals) {\n const v = extractACPTransactionValue({ totals: input.acp.context.totals });\n if (v) return v;\n }\n if (input.mpp?.context.credential?.challenge) {\n const ch = input.mpp.context.credential.challenge;\n const v = extractMPPTransactionValue({ method: ch.method, request: ch.request });\n if (v) return v;\n }\n if (input.x402?.paymentRequired) {\n const first = input.x402.paymentRequired.accepts[0];\n if (first) {\n const v = extractX402TransactionValue({\n maxAmountRequired: Number(first.amount),\n asset: first.asset,\n });\n if (v) return v;\n }\n }\n return undefined;\n}\n\nfunction collectIdentityClaims(input: CommercePipelineInput): IdentityClaim[] {\n const claims: IdentityClaim[] = [];\n if (input.vi?.claims.kid)\n claims.push({ protocol: 'vi', field: 'kid', value: input.vi.claims.kid });\n if (input.ap2?.triple) {\n const agentId =\n input.ap2.triple.intent?.agent_id ??\n input.ap2.triple.cart?.agent_id ??\n input.ap2.triple.payment?.agent_id;\n if (agentId) claims.push({ protocol: 'ap2', field: 'agent_id', value: agentId });\n }\n if (input.acp?.context.bearer) {\n claims.push({ protocol: 'acp', field: 'bearer', value: input.acp.context.bearer });\n }\n if (input.mpp?.context.credential?.source) {\n claims.push({ protocol: 'mpp', field: 'source', value: input.mpp.context.credential.source });\n }\n if (input.rfc9421) {\n // For RFC 9421 the kid is recorded after verify (result.kid); not collected here.\n }\n return claims;\n}\n\nfunction resolvePaymentToken(input: CommercePipelineInput): CommerceContext['paymentToken'] {\n if (input.acp?.context.paymentToken?.type) {\n return { present: true, type: input.acp.context.paymentToken.type };\n }\n const mppMethod = input.mpp?.context.credential?.challenge?.method;\n if (mppMethod === 'tempo') return { present: true, type: 'tempo-tx' };\n if (mppMethod === 'stripe') return { present: true, type: 'stripe-spt' };\n return undefined;\n}\n\nfunction runConstraintEval(input: CommercePipelineInput): ConstraintEvalResult | undefined {\n const transaction = input.transaction ?? {};\n const results: ConstraintEvalResult['results'] = {};\n const reasons: string[] = [];\n let hasAny = false;\n\n if (input.vi?.claims) {\n const viResult = evaluateVIConstraints({\n constraints: input.vi.claims.constraints,\n transaction,\n });\n for (const [k, v] of Object.entries(viResult.results)) {\n results[k] = v;\n if (!v.ok && v.reason) reasons.push(v.reason);\n }\n if (Object.keys(viResult.results).length > 0) hasAny = true;\n }\n\n const registered = input.registeredConstraints;\n if (registered?.allowedPaymentMethods) {\n const pm = evaluatePaymentMethodAllowlist({\n allowedMethods: registered.allowedPaymentMethods,\n requestedMethod: transaction.paymentMethod,\n });\n results.paymentMethod = pm;\n if (!pm.ok && pm.reason) reasons.push(pm.reason);\n hasAny = true;\n }\n if (registered?.spendingLimit) {\n const sp = evaluateSpendingLimit({\n limit: registered.spendingLimit,\n requested: { amount: transaction.amount, currency: transaction.currency },\n });\n results.spendingLimit = sp;\n if (!sp.ok && sp.reason) reasons.push(sp.reason);\n hasAny = true;\n }\n\n if (!hasAny) return undefined;\n return { ok: reasons.length === 0, results, reasons };\n}\n\nfunction shortSource(source: string): string {\n // Take first 16 chars sans scheme for trust-signal label readability.\n return source.replace(/^did:[a-z0-9]+:/, '').slice(0, 16);\n}\n","/**\n * Pluggable extractor registry for the Trusted Agent Gateway edge\n * adapters and other callers that need a curated extractor set.\n *\n * Built-in extractors (VI, UCP, ACP, RFC 9421, MPP, x402, Stripe webhook)\n * are NOT auto-registered. A caller imports this module, picks the set\n * it wants, and calls registerTransportExtractor() for each.\n *\n * Re-registering by name replaces the prior extractor (idempotent).\n */\n\nexport interface ExtractorRequestLike {\n method?: string;\n url?: string;\n headers?: Record<string, string | string[] | undefined>;\n body?: unknown;\n}\n\nexport interface TransportExtractor<T = unknown> {\n readonly name: string;\n match(request: ExtractorRequestLike): boolean;\n extract(request: ExtractorRequestLike): T | Promise<T> | null;\n}\n\nconst registry = new Map<string, TransportExtractor>();\n\nexport function registerTransportExtractor<T>(extractor: TransportExtractor<T>): void {\n if (!extractor || typeof extractor.name !== 'string' || extractor.name.length === 0) {\n throw new Error('registerTransportExtractor: extractor must have a non-empty name');\n }\n registry.set(extractor.name, extractor as TransportExtractor);\n}\n\nexport function getTransportExtractors(): ReadonlyArray<TransportExtractor> {\n return Array.from(registry.values());\n}\n\nexport function getTransportExtractor(name: string): TransportExtractor | undefined {\n return registry.get(name);\n}\n\nexport function clearTransportExtractors(): void {\n registry.clear();\n}\n\n/**\n * Helper: run all matching extractors against a request and return their\n * extracted contexts keyed by extractor name. Skips extractors whose\n * `match()` returns false.\n */\nexport async function runMatchingExtractors(\n request: ExtractorRequestLike\n): Promise<Record<string, unknown>> {\n const out: Record<string, unknown> = {};\n for (const extractor of registry.values()) {\n if (!extractor.match(request)) continue;\n const result = await extractor.extract(request);\n if (result !== null && result !== undefined) out[extractor.name] = result;\n }\n return out;\n}\n","/**\n * Visa JWKS registry resolver.\n *\n * Default endpoint: https://mcp.visa.com/.well-known/jwks (per Visa TAP spec).\n * Wraps jose.createRemoteJWKSet which handles caching + rotation natively.\n */\n\nimport { createRemoteJWKSet, type JWK } from 'jose';\nimport type { RegistryResolver, ResolveContext } from './types';\n\nconst DEFAULT_VISA_JWKS_URL = 'https://mcp.visa.com/.well-known/jwks';\n\nexport interface VisaRegistryOptions {\n jwksUrl?: string;\n cacheMaxAge?: number;\n cooldownDuration?: number;\n}\n\nexport function createVisaRegistry(options: VisaRegistryOptions = {}): RegistryResolver {\n const url = new URL(options.jwksUrl ?? DEFAULT_VISA_JWKS_URL);\n const jwks = createRemoteJWKSet(url, {\n cacheMaxAge: options.cacheMaxAge,\n cooldownDuration: options.cooldownDuration,\n });\n\n return {\n name: 'visa',\n async resolve(kid: string, context?: ResolveContext): Promise<JWK | null> {\n if (!kid) return null;\n try {\n const key = await jwks({\n kid,\n alg: context?.algorithm ?? 'ES256',\n typ: 'JWT',\n });\n return exportJwkFromKeyLike(key);\n } catch {\n return null;\n }\n },\n };\n}\n\nasync function exportJwkFromKeyLike(keyLike: unknown): Promise<JWK | null> {\n if (!keyLike) return null;\n // jose returns KeyObject or CryptoKey — both export via exportJWK at caller side.\n // Runtime shape check: if it already looks like a JWK, pass through.\n if (typeof keyLike === 'object' && 'kty' in (keyLike as object)) {\n return keyLike as JWK;\n }\n const { exportJWK } = await import('jose');\n try {\n return await exportJWK(keyLike as Parameters<typeof exportJWK>[0]);\n } catch {\n return null;\n }\n}\n","/**\n * Mastercard Agent Registry resolver — STUB.\n *\n * Mastercard Agent Pay is behind partnership (pilots Feb 2026, GA Q2 2026).\n * No public Agent Registry URL or open-source resolver exists as of April\n * 2026. This resolver accepts an optional `registryUrl` and, when absent,\n * returns null with a single one-time console.warn so callers can plumb\n * the flow end-to-end without a live registry.\n *\n * When Mastercard ships a public resolver or when a commercial relationship\n * provides a registry URL, pass it via `MastercardRegistryOptions.registryUrl`.\n * Response shape expected: { keys: JWK[] } (JWKS-style).\n */\n\nimport type { JWK } from 'jose';\nimport type { RegistryResolver } from './types';\n\nexport interface MastercardRegistryOptions {\n /** Partnership-provided registry URL. Without it, the resolver is inert. */\n registryUrl?: string;\n /** Cache TTL in seconds. Default 3600. */\n cacheTtlSec?: number;\n /** Fetch fn override for testing. */\n fetch?: typeof fetch;\n /** Silence the one-time warn (testing only). */\n silent?: boolean;\n}\n\ninterface CachedKey {\n jwk: JWK;\n expiresAt: number;\n}\n\nexport function createMastercardRegistry(\n options: MastercardRegistryOptions = {}\n): RegistryResolver {\n const cache = new Map<string, CachedKey>();\n const ttlSec = options.cacheTtlSec ?? 3600;\n const fetchFn = options.fetch ?? globalThis.fetch;\n let warned = false;\n\n return {\n name: 'mastercard',\n async resolve(kid: string): Promise<JWK | null> {\n if (!kid) return null;\n\n if (!options.registryUrl) {\n if (!warned && !options.silent) {\n warned = true;\n // eslint-disable-next-line no-console\n console.warn(\n '[mastercard-registry] registryUrl not configured — key resolution disabled. ' +\n 'Kid lookups will return null until a partnership registry is supplied.'\n );\n }\n return null;\n }\n\n const cached = cache.get(kid);\n if (cached && cached.expiresAt > Date.now()) return cached.jwk;\n\n try {\n const res = await fetchFn(options.registryUrl);\n if (!res.ok) return null;\n const body = (await res.json()) as { keys?: JWK[] };\n const keys = body.keys ?? [];\n for (const k of keys) {\n if (k.kid === kid) {\n cache.set(kid, { jwk: k, expiresAt: Date.now() + ttlSec * 1000 });\n return k;\n }\n }\n return null;\n } catch {\n return null;\n }\n },\n };\n}\n","/**\n * Web Bot Auth registry resolver.\n *\n * IETF draft-meunier-web-bot-auth-architecture-05 + draft-meunier-http-\n * message-signatures-directory-01. Shared transport substrate under TAP,\n * Agent Pay, and Cloudflare Pay Per Crawl.\n *\n * Fetches a Web Bot Auth signature directory\n * (default: `<origin>/.well-known/http-message-signatures-directory`).\n * Shape per spec is a JWKS with Ed25519 keys.\n *\n * Wraps Cloudflare's `web-bot-auth` npm package where feasible; for raw\n * directory fetch + kid matching we use fetch + JSON since web-bot-auth's\n * higher-level API assumes a full request to verify.\n */\n\nimport type { JWK } from 'jose';\nimport type { RegistryResolver, ResolveContext } from './types';\n\nconst DIRECTORY_PATH = '/.well-known/http-message-signatures-directory';\n\nexport interface WebBotAuthRegistryOptions {\n /**\n * Optional explicit directory URL. When omitted, the resolver derives one\n * from `ResolveContext.origin` (e.g. the request URL's origin at verify time).\n */\n directoryUrl?: string;\n cacheTtlSec?: number;\n fetch?: typeof fetch;\n}\n\ninterface DirectoryCache {\n keys: JWK[];\n expiresAt: number;\n}\n\nexport function createWebBotAuthRegistry(\n options: WebBotAuthRegistryOptions = {}\n): RegistryResolver {\n const cache = new Map<string, DirectoryCache>();\n const ttlSec = options.cacheTtlSec ?? 3600;\n const fetchFn = options.fetch ?? globalThis.fetch;\n\n return {\n name: 'web-bot-auth',\n async resolve(kid: string, context?: ResolveContext): Promise<JWK | null> {\n if (!kid) return null;\n\n const directoryUrl = resolveDirectoryUrl(options.directoryUrl, context?.origin);\n if (!directoryUrl) return null;\n\n const cached = cache.get(directoryUrl);\n const now = Date.now();\n if (cached && cached.expiresAt > now) {\n return findKeyByKid(cached.keys, kid);\n }\n\n try {\n const res = await fetchFn(directoryUrl);\n if (!res.ok) return null;\n const body = (await res.json()) as { keys?: JWK[] };\n const keys = body.keys ?? [];\n cache.set(directoryUrl, { keys, expiresAt: now + ttlSec * 1000 });\n return findKeyByKid(keys, kid);\n } catch {\n return null;\n }\n },\n };\n}\n\nfunction resolveDirectoryUrl(\n explicit: string | undefined,\n origin: string | undefined\n): string | null {\n if (explicit) return explicit;\n if (!origin) return null;\n try {\n const url = new URL(origin);\n return `${url.origin}${DIRECTORY_PATH}`;\n } catch {\n return null;\n }\n}\n\nfunction findKeyByKid(keys: JWK[], kid: string): JWK | null {\n for (const k of keys) {\n if (k.kid === kid) return k;\n }\n return null;\n}\n","/**\n * MCP server-side helpers — companion to `transport/mcp.ts` (which handles the\n * agent-side `_meta.astrasync` block).\n *\n * Surfaces a body-aware policy hook the existing `createMiddleware` couldn't\n * provide — MCP traffic is JSON-RPC over a single endpoint (`/mcp`), so the\n * default route-pattern gating is too coarse: every request looks the same\n * URL-wise, but `initialize` is low-risk handshake while `tools/call` of a\n * payment tool is high-risk. Cohort-3 beta merchants flagged this 🟡 in the\n * v2.9.5 round.\n *\n * What lives here:\n * - `parseMcpJsonRpc(body)` — peels JSON-RPC method + tool name + agent\n * id without committing to a particular MCP\n * server framework.\n * - `mcpToPdlss(parsed)` — canonical mapping JSON-RPC method → PDLSS\n * purpose / action / resource. Doc-stable\n * so audits can correlate.\n * - `mcpDefaultEnforced(parsed)` — whether a method is enforced by default\n * so a single MCP middleware can split\n * `initialize` / `tools/list` (pass-through)\n * from `tools/call` (enforced).\n * - `MCP_VERIFIED_HOP_HEADER` — header convention for the dedupe pattern\n * when an MCP tool calls an inner REST hop.\n * - `serialize/parseVerifiedHop` helpers.\n *\n * The Express MCP adapter is in `adapters/mcp.ts` and consumes these.\n */\n\n// X-Astra-Verified-Hop helpers live in ../verified-hop (shared with the\n// edge gateway's origin-bound emission); re-exported here so existing\n// transport-level imports keep working unchanged.\nexport {\n MCP_VERIFIED_HOP_HEADER,\n MCP_VERIFIED_HOP_MAX_AGE_MS,\n serializeVerifiedHop,\n parseVerifiedHop,\n isVerifiedHopValidFor,\n} from '../verified-hop';\nexport type { VerifiedHopMarker } from '../verified-hop';\n\n/**\n * Output of `parseMcpJsonRpc`. Self-describing so the middleware doesn't have\n * to re-introspect the body to figure out gating.\n */\nexport interface ParsedMcpRequest {\n /** JSON-RPC method (e.g. `tools/call`, `initialize`, `tools/list`). */\n method: string;\n /** Set when method === 'tools/call'; the tool name from `params.name`. */\n toolName?: string;\n /** Initialize-specific protocolVersion handshake info, when present. */\n protocolVersion?: string;\n /**\n * Agent id read from the body, in priority order:\n * 1. `params._meta.astrasync.agentId` (the canonical SDK location, see\n * `transport/mcp.ts → setMcpMeta`)\n * 2. `params.arguments.agent_id` (legacy / hand-written tool callers)\n * Header-supplied id (X-Astra-Id) is read separately by the adapter and\n * compared to this for the mismatch check.\n */\n agentIdFromBody?: string;\n /**\n * Purpose extracted from the MCP body\n * with the symmetric precedence chain. Sourced from `_meta.astrasync.purpose`\n * (canonical SDK location) OR `params.arguments.purpose` (legacy /\n * conventional callers). The discriminator is on `purposeSourceFromBody`.\n * Adapter combines this with the `X-Astra-Purpose` header (header wins)\n * before mapping; final fallback at `mcpToPdlss` is `undefined`.\n */\n purposeFromBody?: string;\n /** Which body location resolved `purposeFromBody`. */\n purposeSourceFromBody?: 'meta' | 'tool_argument';\n /**\n * Action extracted from the MCP body with the same\n * symmetric chain as purpose. Sourced from `_meta.astrasync.action`\n * (canonical) OR `params.arguments.action` (legacy). Adapter combines\n * with the `X-Astra-Action` header (header wins) before mapping; final\n * fallback at `mcpToPdlss` is the transport-layer default\n * (`tools/call:<toolname>` or just `<method>`).\n */\n actionFromBody?: string;\n /** Which body location resolved `actionFromBody`. */\n actionSourceFromBody?: 'meta' | 'tool_argument';\n /** True for handshake methods that must succeed before any tool call. */\n isInitialize: boolean;\n /** True for `tools/call`. */\n isToolCall: boolean;\n /** True for low-risk introspection (`tools/list`, `prompts/list`, etc.). */\n isIntrospection: boolean;\n}\n\n/**\n * Peel the JSON-RPC envelope. Returns `null` if the body isn't a JSON-RPC\n * request (callers can short-circuit with a 400 or treat as untyped traffic).\n *\n * Accepts both single-request and notification shapes. Batch requests are\n * NOT supported here — the verify-access contract is single-agent-per-call;\n * a batch body should be split before policy gating.\n */\nexport function parseMcpJsonRpc(body: unknown): ParsedMcpRequest | null {\n if (!body || typeof body !== 'object' || Array.isArray(body)) return null;\n const obj = body as Record<string, unknown>;\n if (obj.jsonrpc !== '2.0' && obj.jsonrpc !== '1.0') return null;\n const method = typeof obj.method === 'string' ? obj.method : null;\n if (!method) return null;\n const params = obj.params as Record<string, unknown> | undefined;\n\n // Tool-name lookup. MCP `tools/call` puts the tool under `params.name`.\n let toolName: string | undefined;\n if (method === 'tools/call' && params && typeof params.name === 'string') {\n toolName = params.name;\n }\n\n // protocolVersion only on the initialize request.\n let protocolVersion: string | undefined;\n if (method === 'initialize' && params && typeof params.protocolVersion === 'string') {\n protocolVersion = params.protocolVersion;\n }\n\n const meta = params?._meta as Record<string, unknown> | undefined;\n const astrasyncMeta = meta?.astrasync as Record<string, unknown> | undefined;\n const args = params?.arguments as Record<string, unknown> | undefined;\n\n // Agent-id lookup with documented precedence: _meta.astrasync.agentId\n // wins over params.arguments.agent_id. (The argument-shape uses\n // `agent_id` snake_case for legacy conventional callers; meta is the\n // canonical SDK location.)\n let agentIdFromBody: string | undefined;\n if (astrasyncMeta && typeof astrasyncMeta.agentId === 'string') {\n agentIdFromBody = astrasyncMeta.agentId;\n } else if (args && typeof args.agent_id === 'string') {\n agentIdFromBody = args.agent_id;\n }\n\n // Round-13 (R13-1, R13-2) — symmetric body-extraction for purpose +\n // action. Per `feedback_symmetric_fallbacks_for_symmetric_concepts.md`:\n // these two concepts are paired in the MCP middleware, so their\n // fallback chains MUST mirror each other exactly. Drift between them\n // generates the same support-ticket class repeatedly (\"I set X in\n // arguments and it didn't take\" — happened for purpose in round-12\n // post-F19, and was about to happen for action in round-13).\n //\n // Body precedence (applies to both): _meta.astrasync.<key> wins over\n // params.arguments.<key>. The discriminator is exported alongside the\n // value so the adapter can fold it into purposeSource / actionSource\n // for debug logging and adoption tracking.\n const purposeBodyResult = extractFromMcpBody(astrasyncMeta, args, 'purpose');\n const actionBodyResult = extractFromMcpBody(astrasyncMeta, args, 'action');\n\n const isInitialize = method === 'initialize';\n const isToolCall = method === 'tools/call';\n const isIntrospection =\n method === 'tools/list' ||\n method === 'prompts/list' ||\n method === 'resources/list' ||\n method === 'ping' ||\n method === 'notifications/initialized';\n\n return {\n method,\n ...(toolName ? { toolName } : {}),\n ...(protocolVersion ? { protocolVersion } : {}),\n ...(agentIdFromBody ? { agentIdFromBody } : {}),\n ...(purposeBodyResult.value ? { purposeFromBody: purposeBodyResult.value } : {}),\n ...(purposeBodyResult.source ? { purposeSourceFromBody: purposeBodyResult.source } : {}),\n ...(actionBodyResult.value ? { actionFromBody: actionBodyResult.value } : {}),\n ...(actionBodyResult.source ? { actionSourceFromBody: actionBodyResult.source } : {}),\n isInitialize,\n isToolCall,\n isIntrospection,\n };\n}\n\n/**\n * Shared body-extraction helper for the symmetric purpose + action\n * fallback chain. Returns the resolved value AND\n * the source discriminator so adapters can fold it into per-call debug\n * logs (`purpose_source` / `action_source`).\n *\n * Precedence:\n * 1. `params._meta.astrasync.<key>` — canonical SDK location, source: 'meta'\n * 2. `params.arguments.<key>` — legacy / conventional, source: 'tool_argument'\n * 3. neither present — value: undefined, source: undefined\n *\n * The HTTP-header tier (`X-Astra-<concept>`) is the adapter's job; this\n * helper only handles body sources. Adapters combine the two: header\n * wins over body. See `mcpToPdlss` for the final precedence assembly.\n */\nfunction extractFromMcpBody(\n astrasyncMeta: Record<string, unknown> | undefined,\n args: Record<string, unknown> | undefined,\n key: 'purpose' | 'action'\n): { value: string | undefined; source: 'meta' | 'tool_argument' | undefined } {\n if (astrasyncMeta && typeof astrasyncMeta[key] === 'string') {\n return { value: astrasyncMeta[key] as string, source: 'meta' };\n }\n if (args && typeof args[key] === 'string') {\n return { value: args[key] as string, source: 'tool_argument' };\n }\n return { value: undefined, source: undefined };\n}\n\n/**\n * PDLSS mapping for an MCP request. The platform's PDLSS taxonomy is\n * `purpose / action / resource`; for MCP traffic the audit-useful dimensions\n * are the JSON-RPC method and (for `tools/call`) the tool name.\n *\n * v2.5.0 rules:\n * - `resource` defaults to the HTTP request path (e.g. `/mcp`). Per-tool\n * overrides via `toolGates` config let merchants map tools to specific\n * backend resources (e.g. `/api/catalog`).\n * - `purpose` defaults to `undefined` (backend evaluator applies\n * skip-when-undefined). Per-tool overrides via `toolGates` config let\n * merchants declare the semantic purpose each tool fulfils.\n * - `action` comes only from declarations (toolGate config, header, or\n * body). For `tools/call` with none declared it is `undefined` —\n * evaluation is purpose-only, because a raw tool name is a transport\n * token, not a PDLSS action, and sending it as one guarantees an\n * action-policy mismatch. For other JSON-RPC methods the method string\n * is used.\n */\nexport interface McpPdlssMapping {\n purpose: string | undefined;\n /**\n * `undefined` when a `tools/call` request declared no action anywhere —\n * the verify-access call then evaluates purpose-only. Tool names never\n * travel as PDLSS actions.\n */\n action: string | undefined;\n resource: string;\n purposeSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | undefined;\n actionSource: 'header' | 'meta' | 'tool_argument' | 'tool_gate' | 'transport_layer' | undefined;\n}\n\n/**\n * v2.5.0 — PDLSS field derivation for MCP requests.\n *\n * Purpose precedence:\n * - If `toolGate.purpose` is provided, it is authoritative (header/body ignored).\n * - Otherwise: header → body `_meta` → body `arguments` → `undefined`.\n *\n * Resource precedence:\n * - `toolGate.resource` if provided, else `requestPath`.\n *\n * Action precedence (3.1.0 — toolGate override added for\n * symmetry with purpose; 4.1.0 — the bare-tool-name fallback for\n * `tools/call` was removed):\n * - `toolGate.action` authoritative → header → body `_meta` → body\n * `arguments` → then: `undefined` for `tools/call` (purpose-only\n * evaluation — tool names are transport tokens, never PDLSS actions),\n * or the JSON-RPC method string for other methods (transport_layer).\n *\n * @param requestPath The HTTP request path (e.g. '/mcp'). Required.\n * @param toolGate Resolved per-tool config from `toolGates`, if present.\n */\nexport function mcpToPdlss(\n parsed: ParsedMcpRequest,\n requestPath: string,\n headerPurpose?: string,\n headerAction?: string,\n toolGate?: { purpose?: string; action?: string; resource?: string }\n): McpPdlssMapping {\n const resource = toolGate?.resource ?? requestPath;\n\n let purpose: string | undefined;\n let purposeSource: McpPdlssMapping['purposeSource'];\n if (toolGate?.purpose !== undefined) {\n purpose = toolGate.purpose;\n purposeSource = 'tool_gate';\n } else if (headerPurpose) {\n purpose = headerPurpose;\n purposeSource = 'header';\n } else if (parsed.purposeFromBody && parsed.purposeSourceFromBody) {\n purpose = parsed.purposeFromBody;\n purposeSource = parsed.purposeSourceFromBody;\n } else {\n purpose = undefined;\n purposeSource = undefined;\n }\n\n let action: string | undefined;\n let actionSource: McpPdlssMapping['actionSource'];\n if (toolGate?.action !== undefined) {\n action = toolGate.action;\n actionSource = 'tool_gate';\n } else if (headerAction) {\n action = headerAction;\n actionSource = 'header';\n } else if (parsed.actionFromBody && parsed.actionSourceFromBody) {\n action = parsed.actionFromBody;\n actionSource = parsed.actionSourceFromBody;\n } else if (parsed.method === 'tools/call') {\n // 4.1.0 fix: previously the bare tool name travelled as the PDLSS\n // action here, which guaranteed an action-policy deny for merchants\n // using the bare-string toolGate shorthand (tool names are transport\n // tokens, not policy vocabulary). With nothing configured or declared,\n // leave the action undeclared so evaluation is purpose-only.\n action = undefined;\n actionSource = undefined;\n } else {\n action = parsed.toolName ? `${parsed.method}:${parsed.toolName}` : parsed.method;\n actionSource = 'transport_layer';\n }\n\n return { purpose, action, resource, purposeSource, actionSource };\n}\n\n/**\n * Whether a method is enforced (calls verify-access + gates on the server\n * decision) by default. The MCP middleware uses this to split low-risk\n * handshake / introspection traffic (pass-through) from high-risk tool\n * execution (enforced). Per-tool / per-method overrides win over this default.\n *\n * - `initialize` / `notifications/initialized` → false (handshake must work for unregistered probes)\n * - `tools/list` / `prompts/list` / `resources/list` → false (introspection is public-surface)\n * - `ping` → false\n * - `resources/read` → true\n * - `tools/call` → true (default — overridable per-tool)\n * - everything else → true (least-privilege fallback)\n */\nexport function mcpDefaultEnforced(parsed: ParsedMcpRequest): boolean {\n if (parsed.isInitialize || parsed.method === 'notifications/initialized') return false;\n if (parsed.isIntrospection) return false;\n return true;\n}\n","/**\n * AstraSync Universal Verification Gateway — MCP middleware\n *\n * Express-shaped middleware tailored to the JSON-RPC body of an MCP\n * (Model Context Protocol) endpoint. Closes the cohort-3 gaps the default\n * `createMiddleware` couldn't:\n *\n * (a) **Body-aware gating**. All MCP traffic targets the same `/mcp` URL.\n * The default route-pattern matcher can't tell `initialize` (low risk)\n * from `tools/call start_checkout` (high risk). This middleware peels\n * the JSON-RPC body and applies a per-method risk tier.\n *\n * (b) **PDLSS mapping**. Derives purpose, action, and resource from\n * `toolGates` config and request context. See `transport/mcp-server.ts`\n * `mcpToPdlss()` for the exact mapping.\n *\n * (c) **Inner-hop dedupe**. Outbound responses set\n * `X-Astra-Verified-Hop` so a downstream REST endpoint that the tool\n * calls can skip a duplicate verify-access. The receiving REST\n * middleware checks `parseVerifiedHop` and skips when valid.\n *\n * (d) **Header-vs-body identity precedence**. Reads ASTRA-id from\n * `X-Astra-Id` first, body second. If both are present and disagree,\n * returns a structured 400 by default (configurable). Pre-fix,\n * integrators had to re-discover this on their own.\n *\n * Usage:\n *\n * ```typescript\n * import express from 'express';\n * import { createMcpMiddleware } from '@astrasyncai/verification-gateway/mcp';\n *\n * const app = express();\n * app.use(express.json());\n *\n * app.post(\n * '/mcp',\n * createMcpMiddleware({\n * apiBaseUrl: 'https://astrasync.ai/api',\n * apiKey: process.env.ASTRASYNC_API_KEY,\n * // Per-tool gates — `tools/call` is enforced by default; introspection /\n * // handshake pass through. A gated tool needs a PDLSS purpose (and ideally\n * // an action). Set a tool/method to `'observe'` to pass it through\n * // unenforced (still evaluated when `evaluateAlwaysIfCredentialed`).\n * toolGates: {\n * browse_catalog: { purpose: 'shopping', action: 'shopping.search' },\n * start_checkout: { purpose: 'shopping', action: 'shopping.purchase' },\n * health_check: 'observe',\n * },\n * }),\n * yourMcpServerHandler,\n * );\n * ```\n */\n\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport type {\n GatewayConfig,\n VerificationResult,\n EnhancedVerificationResult,\n VerificationRequest,\n} from '../types';\nimport { verify, extractCredentials, recordDecision } from '../verify';\nimport { buildSdkObservedMetadata } from '../metadata-capture';\nimport { requiresHumanApproval, annotateApprovalRequired } from './approval-gate';\nimport { awaitStepUpApproval } from './stepup-poll';\nimport { prefetchWellKnown, getWellKnownUrls } from '../well-known';\nimport {\n parseMcpJsonRpc,\n mcpToPdlss,\n mcpDefaultEnforced,\n serializeVerifiedHop,\n parseVerifiedHop,\n isVerifiedHopValidFor,\n MCP_VERIFIED_HOP_HEADER,\n type ParsedMcpRequest,\n} from '../transport/mcp-server';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n mcpRequest?: ParsedMcpRequest;\n // Declared here as well as in express.ts (identical type — the merged\n // interfaces are compatible) so this module typechecks standalone: the\n // grouped DTS build compiles each entry group as its own program, and\n // mcp.ts must not depend on express.ts being in the same one.\n agentVerification?: VerificationResult;\n }\n }\n}\n\n/**\n * Extended per-tool gate with optional PDLSS purpose + action + resource\n * overrides.\n *\n * When `purpose` is set, it is authoritative for that tool — the agent's\n * `X-Astra-Purpose` header is ignored. This lets the merchant declare what\n * semantic purpose each tool fulfils rather than trusting agent self-declaration.\n *\n * When `action` is set (symmetric with `purpose`), it is\n * authoritative over `X-Astra-Action` / body declarations, letting the\n * merchant pin a dotted-verb action (e.g. `shopping.search`) for a tool\n * whose callers would otherwise leave the action undeclared (purpose-only\n * evaluation — raw tool names never travel as PDLSS actions).\n *\n * When `resource` is set, it overrides the default (`req.path`) for that\n * tool's verify-access call — e.g. mapping `list_products` to `/api/catalog`.\n */\nexport interface ToolGateConfig {\n purpose?: string;\n action?: string;\n resource?: string;\n}\n\n/**\n * A tool/method gate is either a {@link ToolGateConfig} (enforced — calls\n * verify-access and gates on the server decision, using the declared PDLSS\n * purpose/action) or the literal `'observe'` (passed through unenforced;\n * still evaluated when `evaluateAlwaysIfCredentialed` is set). SDK 5.0.0\n * removed the access-level band, so a gate no longer carries a tier — its\n * only decision is enforce vs observe.\n */\nexport type ToolGate = ToolGateConfig | 'observe';\n\nexport interface McpMiddlewareOptions extends GatewayConfig {\n /**\n * Per-tool gating for `tools/call` invocations. Tools not listed are\n * enforced by default (`tools/call` calls verify-access and gates on the\n * server decision).\n *\n * A gated tool declares its PDLSS `purpose` (required: the backend rejects\n * gated calls with no resolvable purpose) and ideally a dotted-verb\n * `action`:\n * ```typescript\n * toolGates: {\n * list_products: { purpose: 'shopping',\n * action: 'shopping.search',\n * resource: '/api/catalog' },\n * start_checkout: { purpose: 'shopping',\n * action: 'shopping.purchase',\n * resource: '/api/checkout/*' },\n * health_check: 'observe', // pass through unenforced\n * }\n * ```\n *\n * Set a tool to `'observe'` to pass it through without enforcement (it is\n * still evaluated for the audit trail when `evaluateAlwaysIfCredentialed`\n * is set). A gated object form with no resolvable purpose fails fast with a\n * `PDLSS_PURPOSE_REQUIRED` 400 (the SDK never sends the raw tool name as\n * the PDLSS action).\n *\n * The action axis for non-tools/call MCP methods (`tools/list`,\n * `resources/list`, `prompts/list`, etc.) is the literal JSON-RPC method\n * name (e.g. `'tools/list'`). Merchants gating MCP traffic by action should\n * declare per-tool gates in `toolGates`, not endpoint-level `allowedActions`\n * — the latter applies to REST-style action values, not MCP method strings.\n */\n toolGates?: Record<string, ToolGate>;\n /**\n * Per-method override. By default introspection / handshake methods\n * (`tools/list`, `initialize`, `ping`, …) pass through and `tools/call` is\n * enforced; declare a method here to enforce it (object form, with a PDLSS\n * purpose) or set it to `'observe'` to pass it through. Matches by exact\n * JSON-RPC method string.\n */\n methodGates?: Record<string, ToolGate>;\n /**\n * What to do when the agent id supplied in the X-Astra-Id header\n * disagrees with the agent id in the JSON-RPC body\n * (`params._meta.astrasync.agentId` or `params.arguments.agent_id`).\n *\n * - `'reject'` (default) — return 400 `AGENT_ID_MISMATCH`. Safest.\n * - `'prefer-header'` — log + verify against the header value. Keeps\n * bodies that were authored before X-Astra-Id was the canonical\n * identity slot working.\n * - `'prefer-body'` — log + verify against the body value. Useful in\n * reverse-proxy setups that strip auth headers.\n */\n onAgentIdMismatch?: 'reject' | 'prefer-header' | 'prefer-body';\n /** Skip verification + dedupe entirely. For testing. */\n skip?: boolean;\n /** Custom denied handler. Defaults to a structured JSON-RPC error response. */\n onDenied?: (result: VerificationResult, req: Request, res: Response) => void;\n /**\n * If `true`, trust an inbound `X-Astra-Verified-Hop` header to skip\n * verify-access when it carries a recent marker for the resolved agent.\n *\n * **DEFAULT FLIPPED TO `false` in SDK 2.4.13.** The marker\n * is plaintext semicolon-delimited with no HMAC, so any client that sets\n * the header (with the right format + fresh timestamp + matching ASTRA-id)\n * skipped verify-access entirely. The per-process verify-access result\n * cache already dedupes legitimate repeat calls — this optimization\n * provided no additional savings, only a bypass surface.\n *\n * Set this to `true` ONLY if you control every upstream MCP hop that sets\n * the header AND you trust the network path between hops (mTLS, internal\n * VPC, etc.). For most installs, leave at the safe default.\n *\n * A future SDK release will either remove this option entirely OR add\n * HMAC signing to the marker.\n */\n trustVerifiedHop?: boolean;\n /** Window for accepting an upstream verified-hop marker. Default 60_000ms. */\n verifiedHopMaxAgeMs?: number;\n /**\n * Automatically record grant/deny decisions for every MCP call. Default\n * `true` — matches the express adapter.\n */\n recordDecisions?: boolean;\n /** Forward runtime challenge (default `true`). */\n enableRuntimeChallenge?: boolean;\n /**\n * Posture when the MCP middleware itself throws an internal error.\n * Default `'open'` for backward compatibility in SDK 2.4.13. Shadow logs\n * record what WOULD be denied with `failOnError: 'closed'` so merchants\n * can grep correlationId for impact analysis during the observation\n * window. Default flips to `'closed'` in a follow-up release.\n */\n failOnError?: 'open' | 'closed';\n}\n\n/**\n * Default MCP denied handler.\n *\n * Mirrors the express adapter — surfaces `failures[]`\n * and `correlationId` on the response so partners can render rich UX and\n * tie a denial to a log line. Also stamps `X-Astra-Gateway-Mode: enforced`\n * so the header reliably distinguishes gate-evaluated denials\n * from gate-skipped pass-throughs.\n */\n/**\n * Shared single-value HTTP header reader. Same shape used for\n * both `X-Astra-Purpose` and `X-Astra-Action` extraction (symmetric\n * fallback chain — see `mcpToPdlss` for the full precedence rule).\n * Returns the first value if the header repeats (Express turns repeated\n * headers into an array); returns undefined when the header is absent.\n */\nfunction readSingleHeader(value: string | string[] | undefined): string | undefined {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value[0];\n return undefined;\n}\n\nfunction dedupeFailures(result: VerificationResult): void {\n if (result.failures && result.failures.length > 1) {\n const seen = new Set<string>();\n result.failures = result.failures.filter((f) => {\n const key = `${f.dimension}|${f.message}|${(f as { guidance?: string }).guidance ?? ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n }\n if (result.denialReasons && result.denialReasons.length > 1) {\n result.denialReasons = [...new Set(result.denialReasons)];\n }\n}\n\nfunction defaultMcpDenied(result: VerificationResult, req: Request, res: Response): void {\n // JSON-RPC error envelope so MCP-aware clients render it correctly.\n const id = (req.body as Record<string, unknown> | undefined)?.id ?? null;\n\n // 4.0.0 BREAKING: the integration's OWN key was rejected — not the agent's\n // fault, not transient. 503 + a dedicated JSON-RPC code so MCP clients can\n // tell \"this server's verification layer is broken\" from their own denial.\n if (result.misconfigured) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.status(503).json({\n jsonrpc: '2.0',\n id,\n error: {\n // -32002 → merchant verification misconfigured (see -32000/-32001 below)\n code: -32002,\n message:\n result.denialReasons?.[0] ?? \"This server's AstraSync integration is misconfigured\",\n data: {\n guidance: result.guidance,\n failures: result.failures,\n correlationId: result.correlationId,\n },\n },\n });\n return;\n }\n\n // Round-18 G4: see express.defaultOnDenied for full rationale on the\n // identity-vs-policy split → 401/403 mapping. Same logic here so MCP\n // clients get HTTP status semantics aligned with REST adapters.\n const status = !result.identityVerified ? 401 : 403;\n\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n\n res.status(status).json({\n jsonrpc: '2.0',\n id,\n error: {\n // JSON-RPC error codes:\n // -32000 → unauthorized (no identity resolved)\n // -32001 → insufficient access (identity OK, policy denied)\n // -32002 → merchant verification misconfigured (handled above)\n code: !result.identityVerified ? -32000 : -32001,\n message: result.denialReasons?.[0] ?? 'Access denied',\n data: {\n guidance: result.guidance,\n // Round-10: aggregated per-dimension detail + correlation handle.\n failures: result.failures,\n correlationId: result.correlationId,\n stepUpApproval: result.stepUpApproval,\n // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /\n // expired / consumed / timeout). Absent when the feature is off.\n ...(result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }),\n },\n },\n });\n}\n\n/**\n * Resolve whether a parsed MCP request is enforced, and the gate config to\n * apply. SDK 5.0.0 removed the access-level band — a gate's only decision is\n * enforce vs observe.\n *\n * Precedence:\n * 1. Non-tools/call without `methodGates` entry → pass through\n * (`discovery_default`). Discovery is open — agents must list tools\n * before invoking them.\n * 2. `methodGates[method]` — per-method override (`'observe'` or a config)\n * 3. `toolGates[toolName]` — per-tool override (tools/call only)\n * 4. `mcpDefaultEnforced` — built-in default (tools/call → enforced)\n *\n * The `source` field is logged for forensics / activity-feed attribution.\n */\nfunction resolveGate(\n parsed: ParsedMcpRequest,\n opts: {\n toolGates?: Record<string, ToolGate>;\n methodGates?: Record<string, ToolGate>;\n }\n): {\n enforce: boolean;\n config?: ToolGateConfig;\n source: 'toolGate' | 'methodGate' | 'tier' | 'discovery_default';\n} {\n if (!parsed.toolName) {\n const methodGate = opts.methodGates?.[parsed.method];\n if (methodGate !== undefined) {\n return methodGate === 'observe'\n ? { enforce: false, source: 'methodGate' }\n : { enforce: true, config: methodGate, source: 'methodGate' };\n }\n // Non-tools/call methods (handshake / introspection) pass through unless a\n // methodGate opts them in — preserves open discovery for unregistered probes.\n return { enforce: false, source: 'discovery_default' };\n }\n const toolGate = opts.toolGates?.[parsed.toolName];\n if (toolGate !== undefined) {\n return toolGate === 'observe'\n ? { enforce: false, source: 'toolGate' }\n : { enforce: true, config: toolGate, source: 'toolGate' };\n }\n // tools/call with no explicit gate → enforced by default.\n return { enforce: mcpDefaultEnforced(parsed), source: 'tier' };\n}\n\n/**\n * Create the MCP middleware. Attach AFTER `express.json()` — the body must\n * already be a parsed object.\n */\nexport function createMcpMiddleware(options: McpMiddlewareOptions): RequestHandler {\n const {\n toolGates,\n methodGates,\n onAgentIdMismatch = 'reject',\n skip = false,\n onDenied = defaultMcpDenied,\n trustVerifiedHop = false,\n verifiedHopMaxAgeMs,\n recordDecisions,\n enableRuntimeChallenge = true,\n failOnError = 'open',\n ...config\n } = options;\n\n // v2.5.0: fire-and-forget pre-fetch of well-known URLs\n if (config.apiBaseUrl) {\n prefetchWellKnown(config.apiBaseUrl).catch(() => {});\n }\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n try {\n if (skip) return next();\n\n const parsed = parseMcpJsonRpc(req.body);\n if (!parsed) {\n // Not a JSON-RPC body. Either the route is misconfigured or the\n // client sent a non-MCP payload. We don't 400 here — let the actual\n // MCP server handler render its own error so the middleware doesn't\n // pre-empt valid framework error shapes.\n if (config.setPassThroughHeader) {\n // Round-10 (#49, O10): `unenforced` describes the GATE state, not\n // the downstream response. Renamed from the ambiguous\n // `pass-through` (which partners read as \"request succeeded\").\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader('X-Astra-Gateway-Reason', 'non-jsonrpc-body');\n }\n return next();\n }\n req.mcpRequest = parsed;\n\n // ── Identity reconciliation (defect d) ─────────────────────────────\n // Header value is the SDK-canonical slot; body slot exists for legacy\n // hand-written tool callers and the MCP `_meta.astrasync.agentId`\n // convention.\n const headerRaw = req.headers['x-astra-id'] ?? req.headers['x-astra-agentid'];\n const headerAstraId =\n typeof headerRaw === 'string'\n ? headerRaw\n : Array.isArray(headerRaw)\n ? headerRaw[0]\n : undefined;\n const bodyAstraId = parsed.agentIdFromBody;\n\n let effectiveAstraId: string | undefined;\n if (headerAstraId && bodyAstraId && headerAstraId !== bodyAstraId) {\n if (onAgentIdMismatch === 'reject') {\n const id = (req.body as Record<string, unknown>)?.id ?? null;\n res.status(400).json({\n jsonrpc: '2.0',\n id,\n error: {\n code: -32602,\n message: 'AGENT_ID_MISMATCH',\n data: {\n detail:\n 'The agent id in the X-Astra-Id header disagrees with params._meta.astrasync.agentId / params.arguments.agent_id. Reconcile before calling the tool — see https://astrasync.ai/docs/mcp-integration#identity-reconciliation.',\n headerAstraId,\n bodyAstraId,\n },\n },\n });\n return;\n }\n effectiveAstraId = onAgentIdMismatch === 'prefer-header' ? headerAstraId : bodyAstraId;\n } else {\n effectiveAstraId = headerAstraId ?? bodyAstraId;\n }\n\n // ── Inner-hop dedupe (defect c) ────────────────────────────────────\n // If a trusted upstream MCP hop already verified this exact ASTRA-id\n // a few ms ago, we accept the marker and skip a redundant verify-access\n // call. Only valid when the header is fresh AND matches the agent id\n // we resolved above.\n if (trustVerifiedHop && effectiveAstraId) {\n const hopRaw = req.headers[MCP_VERIFIED_HOP_HEADER.toLowerCase()];\n const hopValue =\n typeof hopRaw === 'string' ? hopRaw : Array.isArray(hopRaw) ? hopRaw[0] : undefined;\n const marker = parseVerifiedHop(hopValue);\n if (\n isVerifiedHopValidFor(marker, effectiveAstraId, {\n ...(verifiedHopMaxAgeMs !== undefined ? { maxAgeMs: verifiedHopMaxAgeMs } : {}),\n })\n ) {\n // Skip verify-access — pass straight through. Don't re-emit the\n // header since the MCP framework will issue the response (the\n // outer hop already tagged it for any further inner hops).\n return next();\n }\n }\n\n // ── Resolve gating ─────────────────────────────────────────────────\n const gateDecision = resolveGate(parsed, {\n toolGates,\n methodGates,\n });\n\n // ── Build verify-access request ────────────────────────────────────\n // Round-13 (R13-5) — credentials extraction hoisted above the\n // mcp-tier-none short-circuit (mirrors round-12 F9 express adapter\n // restructure). The `evaluateAlwaysIfCredentialed` flag lets the\n // caller turn unenforced tier-none calls into evaluated-not-enforced\n // calls when credentials are present, so the agent verification\n // result populates `req.agentVerification` for tier-aware handler\n // rendering (e.g. anonymous vs verified MCP tool listings).\n const credentials = extractCredentials(\n req.headers as Record<string, string | string[] | undefined>,\n req.query as Record<string, string | undefined>\n );\n // Override the SDK's default credential extraction with the resolved\n // ASTRA-id so the verify-access call sees the post-precedence value\n // (defect d). When neither header nor body supplied an id, the SDK's\n // anonymous-canonical-flow handles it.\n if (effectiveAstraId) credentials.astraId = effectiveAstraId;\n\n // Pass-through short-circuit. Default behaviour: skip verify-access for\n // observe / handshake / introspection (must work for unregistered\n // probes). With `evaluateAlwaysIfCredentialed: true` AND credentials\n // present, fall through to verify-access for the audit trail; the\n // post-verify gate-skipping branch below handles the rendering side.\n // Round-12 F9 parity (closes the round-12 deferral).\n const shouldEnforce = gateDecision.enforce;\n if (!shouldEnforce && (!config.evaluateAlwaysIfCredentialed || !credentials.astraId)) {\n if (config.setPassThroughHeader) {\n // Round-10 (#49, O10): `unenforced` describes the GATE state, not\n // the downstream response.\n res.setHeader('X-Astra-Gateway-Mode', 'unenforced');\n res.setHeader('X-Astra-Gateway-Reason', 'mcp-observe');\n }\n return next();\n }\n\n // Per-tool gate config (purpose + action + resource overrides).\n const gate = gateDecision.config;\n\n const headerPurpose = readSingleHeader(req.headers['x-astra-purpose']);\n const headerAction = readSingleHeader(req.headers['x-astra-action']);\n const pdlss = mcpToPdlss(\n parsed,\n req.path,\n headerPurpose,\n headerAction,\n gate ? { purpose: gate.purpose, action: gate.action, resource: gate.resource } : undefined\n );\n\n // Telemetry: debug log per resolution. Adoption tracking, support\n // triage, and the `default_*` / `transport_layer` decay signals\n // all read this. Both purpose and action emit their source so we\n // can spot which integration path each partner is using.\n if (config.debug) {\n // eslint-disable-next-line no-console\n console.debug('[mcp-middleware] pdlss resolved', {\n purpose_source: pdlss.purposeSource,\n resolved_purpose: pdlss.purpose,\n action_source: pdlss.actionSource,\n resolved_action: pdlss.action,\n });\n }\n\n // 3.2.0 — clear \"purpose required\" error. We only reach here on the\n // ENFORCED path (the `!shouldEnforce` early-return is above). A gated\n // tool call with no resolvable PDLSS purpose (none on the toolGate, no\n // X-Astra-Purpose header, none in the body) would otherwise hit\n // verify-access's generic \"Invalid request data\" → surface to the agent\n // as an opaque `verify_access.api_error`. Fail fast with an actionable\n // message instead (purpose is required post-vocabulary-unification).\n if (!pdlss.purpose) {\n const id = (req.body as Record<string, unknown>)?.id ?? null;\n res.status(400).json({\n jsonrpc: '2.0',\n id,\n error: {\n code: -32602,\n message: 'PDLSS_PURPOSE_REQUIRED',\n data: {\n dimension: 'pdlss.purpose',\n detail:\n 'This tool is access-gated but the call declared no PDLSS purpose. Supply a bare-category purpose via the X-Astra-Purpose header or params._meta.astrasync.purpose, or have the merchant set the tool’s purpose in its toolGate config.',\n resolvedAction: pdlss.action,\n },\n },\n });\n return;\n }\n\n const counterpartyUrl =\n config.counterpartyUrl || `${req.protocol}://${req.get('host')}${req.path}`;\n const shouldRecordDecisions = recordDecisions !== false;\n\n const verificationRequest: VerificationRequest = {\n credentials,\n purpose: pdlss.purpose,\n action: pdlss.action,\n resource: pdlss.resource,\n // Round-12 (F19): mark transport protocol separately from intent.\n // The MCP middleware always sets this to 'mcp'; non-MCP callers\n // leave it unset (server-side default is 'rest').\n invocationProtocol: 'mcp',\n createSession: shouldRecordDecisions,\n counterpartyUrl,\n counterpartyType: config.counterpartyType || 'mcp_server',\n enableRuntimeChallenge,\n callerMetadata: {\n sourceIp: req.ip,\n userAgent: req.headers['user-agent'] as string | undefined,\n host: req.headers.host as string | undefined,\n // Capture EVERY inbound header (parity with the express adapter —\n // MCP-only merchants have no edge to do it upstream) plus the\n // CDN-derived connection block. Local string work, secrets\n // stripped; out of the verify cache key so it doesn't defeat\n // caching.\n observedMetadata: buildSdkObservedMetadata(req.headers),\n },\n };\n let result = await verify(config, verificationRequest);\n\n req.agentVerification = result;\n let sessionId = (result as EnhancedVerificationResult).sessionId;\n\n // 3.6.0 hold-and-poll (opt-in via stepUpMaxWaitMs) — see express.ts for\n // the full rationale. On 'approved' the same request is re-verified\n // once, cache-bypassed, so the backend redeems the single-use approval.\n if (\n config.stepUpMaxWaitMs !== undefined &&\n result.policyAllowed &&\n requiresHumanApproval(result) &&\n result.stepUpApproval?.pollUrl\n ) {\n const outcome = await awaitStepUpApproval(config, result.stepUpApproval);\n res.setHeader('X-Astra-Step-Up', outcome);\n if (outcome === 'approved') {\n result = await verify(config, verificationRequest, { bypassCache: true });\n req.agentVerification = result;\n sessionId = (result as EnhancedVerificationResult).sessionId;\n } else {\n result.stepUpOutcome = outcome;\n }\n }\n\n // v2.3.9 (defect #30): denied verifications short-circuit BEFORE the\n // gate-level comparison. See express.ts for the full rationale —\n // mirroring it here so the MCP path inherits the same belt-and-braces\n // protection against access-level/help-payload conflation.\n // 4.5.0: gate on the SERVER decision only (`policyAllowed`) — anonymous\n // callers allowed by an audit/allow endpoint policy are honestly\n // identity-unverified; see express.ts.\n if (!result.policyAllowed) {\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // F2 direct-path fail-closed: a step-up / requires-approval outcome\n // (policyAllowed:true, allowed-but-escalate) cannot be completed\n // autonomously — deny and surface stepUpApproval polling info.\n if (requiresHumanApproval(result)) {\n annotateApprovalRequired(result);\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'denied', result.denialReasons?.[0]).catch(() => {});\n }\n dedupeFailures(result);\n onDenied(result, req, res);\n return;\n }\n\n // Round-13 (R13-5): evaluation-without-enforcement parity with the\n // express F9 adapter. When the route is `none` but we ran\n // verify-access because `evaluateAlwaysIfCredentialed: true` AND\n // credentials were present, skip the gates and call next() — the\n // result is on `req.agentVerification` for the MCP handler to\n // render tier-aware responses (e.g. anonymous vs verified\n // tool-listing on the same `/mcp` endpoint).\n if (!shouldEnforce) {\n if (config.setPassThroughHeader) {\n res.setHeader('X-Astra-Gateway-Mode', 'enforced');\n res.setHeader('X-Astra-Gateway-Reason', 'evaluated-not-enforced');\n }\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n return next();\n }\n\n // The access decision is the server's (identityVerified / policyAllowed,\n // denied above) — resting on a verified ID + runtime challenge + PDLSS\n // match + trust score. The per-tool gate only decides WHETHER a tool is\n // enforced at all (`shouldEnforce`, above); there is no client-side tier\n // veto (the access-level band was removed in SDK 5.0.0).\n\n // ── Tag the outbound response with X-Astra-Verified-Hop ────────────\n // Inner-hop REST endpoints called by this tool can read the header\n // and skip a duplicate verify-access. We set it on the response so\n // downstream proxies see it; tools that perform fetch() to an inner\n // hop should also forward it themselves (the MCP server framework\n // controls outbound calls — out of scope here).\n if (effectiveAstraId) {\n res.setHeader(\n MCP_VERIFIED_HOP_HEADER,\n serializeVerifiedHop({\n astraId: effectiveAstraId,\n ...(sessionId ? { sessionId } : {}),\n checkedAt: Date.now(),\n })\n );\n }\n\n if (shouldRecordDecisions && sessionId) {\n recordDecision(config, sessionId, 'granted').catch(() => {});\n }\n // v2.3.8 (defect #26): relay X-Astra-Unverified-Warning when the\n // server returned an audit-mode advisory.\n const enhancedResult = result as EnhancedVerificationResult;\n if (enhancedResult.warningHeader) {\n res.setHeader(enhancedResult.warningHeader.name, enhancedResult.warningHeader.value);\n }\n next();\n } catch (error) {\n // Audit F-A1-06: shadow-mode logging for fail-closed default migration.\n // Mirror of the express adapter pattern. Default 'open' for backward\n // compat in SDK 2.4.13; shadow logs let merchants grep correlationId\n // for impact analysis before the default flips in a follow-up release.\n const errorClass = error instanceof Error ? error.constructor.name : typeof error;\n const correlationId =\n (req.headers['x-request-id'] as string | undefined) ||\n (req.headers['x-correlation-id'] as string | undefined) ||\n `gen-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n // eslint-disable-next-line no-console\n console.error('[VerificationGateway/MCP] Middleware error:', error);\n // eslint-disable-next-line no-console\n console.warn(\n `[SHADOW] would-have-denied: errorClass=${errorClass} route=${req.method}:${req.path} merchantId=${config.counterpartyId ?? 'unknown'} correlationId=${correlationId}`\n );\n\n if (failOnError === 'closed') {\n const result: VerificationResult = {\n identityVerified: false,\n policyAllowed: false,\n denialReasons: [`MCP middleware internal error: ${errorClass}`],\n failures: [\n {\n dimension: 'middleware.internal_error',\n message: `Middleware threw ${errorClass} — failing closed`,\n },\n ],\n verifiedAt: new Date(),\n correlationId,\n };\n const catchUrls = config.apiBaseUrl\n ? await getWellKnownUrls(config.apiBaseUrl).catch(() => undefined)\n : undefined;\n if (catchUrls) {\n result.guidance = {\n message: `Middleware threw ${errorClass} — failing closed`,\n registrationUrl: catchUrls.registrationUrl,\n documentationUrl: catchUrls.documentationUrl,\n };\n }\n dedupeFailures(result);\n return onDenied(result, req, res);\n }\n\n next();\n }\n };\n}\n\n// Re-export the helpers so consumers can mix-and-match (e.g. read the\n// verified-hop header themselves on a custom inner-hop handler).\nexport {\n parseMcpJsonRpc,\n mcpToPdlss,\n mcpDefaultEnforced,\n serializeVerifiedHop,\n parseVerifiedHop,\n isVerifiedHopValidFor,\n MCP_VERIFIED_HOP_HEADER,\n};\nexport type { ParsedMcpRequest } from '../transport/mcp-server';\n","import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the owner denies the\n * pending registration request. The `reason` field, when present, mirrors the\n * deny note the owner left in the dashboard.\n */\nexport class RegistrationDeniedError extends AstraSyncError {\n public readonly requestId: string;\n public readonly reason?: string;\n\n constructor(requestId: string, reason?: string) {\n super(\n `Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ''}`,\n 403,\n 'REGISTRATION_DENIED'\n );\n this.name = 'RegistrationDeniedError';\n this.requestId = requestId;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the pending request\n * passes its 14-day TTL with no owner decision. The agent must re-submit.\n */\nexport class RegistrationExpiredError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,\n 410,\n 'REGISTRATION_EXPIRED'\n );\n this.name = 'RegistrationExpiredError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the caller's local\n * `timeoutMs` elapses before the owner makes a decision. The request is still\n * live server-side — poll `pollRegistration(requestId)` to resume waiting, or\n * call `waitForApproval` again with a longer timeout.\n */\nexport class RegistrationTimeoutError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,\n 408,\n 'REGISTRATION_TIMEOUT'\n );\n this.name = 'RegistrationTimeoutError';\n this.requestId = requestId;\n }\n}\n","import { sdkFetch } from '../http';\nimport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n AgentRecord,\n} from './types';\nimport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n let raw = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n // Round-10 (O2): tolerate the verify-side convention. `GatewayConfig.apiBaseUrl`\n // is documented as `https://astrasync.ai/api` (with /api), but\n // `AstraSyncConfig.baseUrl` is documented as the bare origin. Partners\n // passing the verify-style URL to the registration client hit a 404\n // because we'd then append `/api/agents/register` → double /api. Strip\n // a trailing `/api` and warn once so the partner can fix the source.\n if (raw.toLowerCase().endsWith('/api')) {\n raw = raw.slice(0, -'/api'.length);\n if (config.baseUrl && !config.silent) {\n // eslint-disable-next-line no-console\n console.warn(\n `[AstraSync] baseUrl '${config.baseUrl}' had a trailing /api — stripped to '${raw}'. ` +\n `Pass the bare origin (e.g. 'https://astrasync.ai' or 'https://staging.astrasync.ai') ` +\n `to AstraSync(). The /api suffix is the verify-gateway (GatewayConfig.apiBaseUrl) convention.`\n );\n }\n }\n this.baseUrl = raw;\n\n // Env fallback is opt-OUT: server-side wrappers (MCP tool handlers,\n // gateway adapters) pass `disableEnvFallback: true` so a no-credentials\n // call from a user-facing flow cannot silently authenticate as the host\n // process's platform-attribution key. CLIs / scripts that legitimately\n // rely on ASTRASYNC_API_KEY keep working under the default.\n this.apiKey = config.disableEnvFallback\n ? config.apiKey\n : config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n // Defense-in-depth: warn when env fallback actually fires under the\n // default (non-strict) config. Surfaces the \"I'm running as platform\"\n // foot-gun before it becomes a security bug. Gated by !silent.\n if (\n !config.apiKey &&\n !config.disableEnvFallback &&\n process.env.ASTRASYNC_API_KEY &&\n !config.silent\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n '[AstraSync] No apiKey passed to constructor; using process.env.ASTRASYNC_API_KEY. ' +\n 'If this code wraps user-facing flows (e.g. MCP tool handlers), pass ' +\n 'disableEnvFallback: true to prevent ambient credentials from impersonating callers. ' +\n 'See https://astrasync.ai/docs/agent-access#disableenvfallback for details.'\n );\n }\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n *\n * The backend response depends on auth context:\n * - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,\n * returns `{ status: 'active', agent }`.\n * - **API-key only** (no signature): 202 pending, returns\n * `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The\n * owner is notified by email and a dashboard alert is emitted; the agent\n * becomes active only after the owner approves.\n *\n * Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the\n * request until it resolves, then return the live agent record. The promise\n * rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or\n * `RegistrationTimeoutError` on the corresponding terminal states.\n *\n * @example Non-blocking (default — best for serverless / scheduled agents):\n * ```typescript\n * const result = await sdk.register({ name, pdlss });\n * if (result.status === 'pending_approval') {\n * storeRequestId(result.requestId);\n * return; // function exits; resume later via pollRegistration()\n * }\n * ```\n *\n * @example Blocking (best for long-running services + CLI):\n * ```typescript\n * const agent = await sdk.register({\n * name, pdlss, waitForApproval: true, timeoutMs: 600_000,\n * onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),\n * });\n * ```\n */\n async register(\n options: RegisterOptions & WaitForApprovalOptions\n ): Promise<RegisterResult | AgentRecord> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n const { status, body: raw } = await this.requestWithStatus<\n RegistrationResponse | PendingRegistrationResponse\n >('POST', '/api/agents/register', body);\n\n if (status === 201) {\n const activeBody = raw as RegistrationResponse;\n const active: RegisterResult = {\n status: 'active',\n agent: activeBody.data.agent,\n // Round-12 (F16): pass backend advisories through verbatim.\n // Pre-fix the SDK whitelisted five fields and silently dropped\n // `warnings`, which left partners with no signal that\n // `no_callback_endpoint` (or future advisories) had fired.\n ...(activeBody.warnings && { warnings: activeBody.warnings }),\n };\n return active;\n }\n\n // 202 Accepted — owner approval required.\n const pendingBody = raw as PendingRegistrationResponse;\n const pending: RegisterResult = {\n status: 'pending_approval',\n requestId: pendingBody.requestId,\n expiresAt: pendingBody.expiresAt,\n pollUrl: pendingBody.pollUrl,\n message: pendingBody.message,\n // Round-12 (F16): same pass-through on the pending path.\n ...(pendingBody.warnings && { warnings: pendingBody.warnings }),\n };\n\n if (!options.waitForApproval) return pending;\n\n return this.waitForApproval(pendingBody.requestId, options);\n }\n\n /**\n * Poll the current state of a pending-approval registration request.\n *\n * Useful for caller-driven polling when `waitForApproval: false` (the\n * default). The endpoint is unauthenticated — pass the `requestId` that\n * was returned from the 202 response.\n *\n * @returns `state: 'pending'` while awaiting; `'approved'` carries the\n * minted agent in `agent`; `'denied'` may carry the owner's\n * `reason`; `'expired'` is terminal after 14 days.\n */\n async pollRegistration(requestId: string): Promise<PollRegistrationResult> {\n const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;\n const res = await sdkFetch(url, { headers: { Accept: 'application/json' } });\n if (!res.ok) {\n const errBody = (await res.json().catch(() => ({}))) as ApiErrorResponse;\n throw new AstraSyncError(\n errBody.error || `pollRegistration failed: ${res.status}`,\n res.status,\n errBody.code\n );\n }\n return (await res.json()) as PollRegistrationResult;\n }\n\n /**\n * Block until a pending registration request resolves to a terminal state.\n * Resolves to the live `AgentRecord` on approval; rejects with the matching\n * Registration*Error on deny/expire/timeout. Usually called via\n * `register({ waitForApproval: true })`, but exposed for callers that want\n * to fire-and-forget the initial register call and resume waiting later\n * (e.g. after restoring a stored `requestId` on cold start).\n */\n async waitForApproval(\n requestId: string,\n options: WaitForApprovalOptions = {}\n ): Promise<AgentRecord> {\n const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;\n const pollIntervalMs = options.pollIntervalMs ?? 5_000;\n const start = Date.now();\n const deadline = start + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await this.pollRegistration(requestId);\n const ageMs = Date.now() - start;\n options.onPending?.({ requestId, ageMs });\n\n if (result.state === 'approved') {\n if (!result.agent) {\n throw new AstraSyncError(\n `Registration ${requestId} reported approved but no agent payload returned.`,\n 500\n );\n }\n return result.agent;\n }\n if (result.state === 'denied') {\n throw new RegistrationDeniedError(requestId, result.reason);\n }\n if (result.state === 'expired') {\n throw new RegistrationExpiredError(requestId);\n }\n await sleep(pollIntervalMs);\n }\n throw new RegistrationTimeoutError(requestId);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await sdkFetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const { body: parsed } = await this.requestWithStatus<T>(method, endpoint, body);\n return parsed;\n }\n\n /**\n * Variant of {@link request} that also returns the HTTP status code, so\n * callers can branch on 201 vs 202 (or other success codes) without losing\n * type information about the response body.\n */\n private async requestWithStatus<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await sdkFetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return { status: res.status, body: (await res.json()) as T };\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await sdkFetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n","/**\n * Guidance envelope for credentials-required cases.\n *\n * A single shared source of truth so partners writing their own wrappers\n * (custom MCP servers, Express middleware around registration, gateway\n * adapters) consume a single source of truth instead of re-implementing the\n * five-step boilerplate.\n *\n * The envelope is what an agent (or wrapping MCP client) sees when it calls\n * `register_agent` with no AstraSync credentials. It tells the calling agent\n * (a) what failed (`status: 'credentials_required'`), (b) the keyless\n * registration ACTION endpoint (`registrationUrl` — POST-able, not the human\n * dashboard), (c) where the relevant docs are (`documentationUrl`), and (d) the\n * ordered next-actions (`steps`).\n */\n\nexport interface GuidanceEnvelope {\n /**\n * Single-literal today. Expand to a union (e.g.\n * `'credentials_required' | 'kyd_required' | …`) when a second guidance\n * status emerges. Don't pre-emptively widen — the literal pins the shape.\n */\n status: 'credentials_required';\n message: string;\n guidance: {\n message: string;\n registrationUrl: string;\n documentationUrl: string;\n steps: string[];\n };\n}\n\nexport interface BuildGuidanceParams {\n /**\n * Bare origin of the AstraSync deployment the caller should register at,\n * e.g. `https://astrasync.ai` or `https://staging.astrasync.ai`. No\n * trailing slash, no `/api` suffix — registrationUrl and documentationUrl\n * are templated relative to this origin.\n */\n origin: string;\n /**\n * Overrides the top-level `message` (the short summary the agent sees).\n * Defaults to the error message from the SDK's `AuthenticationError`\n * when present, else a generic \"credentials required\" line.\n */\n message?: string;\n /**\n * Overrides the documentation path. Defaults to `/docs/agent-access`.\n */\n documentationPath?: string;\n}\n\n/**\n * Build the credentials-required guidance envelope.\n *\n * This is the canonical builder — MCP wrappers (`agent-registration.ts`),\n * Express middleware in custom integrations, and any other partner-side\n * wrapper that needs to surface \"you need to register\" should call this\n * rather than reconstructing the shape inline. Inline reconstruction\n * historically led to drift between wrappers; this consolidates it.\n *\n * @example\n * ```ts\n * import { buildGuidance } from '@astrasyncai/verification-gateway';\n *\n * try {\n * const sdk = new AstraSync({ apiKey: callerApiKey, disableEnvFallback: true });\n * // ...\n * } catch (err) {\n * if (err instanceof AuthenticationError) {\n * return buildGuidance({ origin: 'https://astrasync.ai', message: err.message });\n * }\n * throw err;\n * }\n * ```\n */\nexport function buildGuidance(params: BuildGuidanceParams): GuidanceEnvelope {\n const origin = params.origin.replace(/\\/+$/, '');\n const docsPath = params.documentationPath ?? '/docs/agent-access';\n const message = params.message ?? 'AstraSync registration requires credentials.';\n\n return {\n status: 'credentials_required',\n message,\n guidance: {\n message:\n \"Register either with an agent-scoped API key (the recommended credentialed path) OR, if you hold no credentials, via the owner's email using request_registration. Never send a password or private key over the wire.\",\n // 3.0.0: registrationUrl is the agent-actionable KEYLESS endpoint, not the\n // human dashboard `/agents/register` (an auth-walled page an agent can't\n // use). documentationUrl carries the machine-readable contract.\n registrationUrl: `${origin}/api/agents/request-registration`,\n documentationUrl: `${origin}${docsPath.startsWith('/') ? docsPath : `/${docsPath}`}`,\n steps: [\n 'Credentialed path (recommended): have your human mint an agent-scoped API key at Settings → API Keys, then re-call register_agent with apiKey set. An agent holding its own scoped kya_ key is fine and intended.',\n \"No-credentials path: call request_registration({ name, ownerEmail, ... }) with the human owner's email — the only bootstrap credential. No API key is involved.\",\n 'Include as much metadata as you can in the registration — especially model ({ modelName, modelProvider }) and framework ({ frameworkName, frameworkVersion }). Declared platform/model metadata directly improves your trust score and attributes your traffic correctly.',\n 'The owner approves via an emailed link (first time, they create an account and complete a quick verification).',\n 'Use poll_registration({ requestId }) once the owner confirms approval to retrieve the astraId.',\n 'Never transmit a password or private key over the MCP wire — those are never required.',\n ],\n },\n };\n}\n","/**\n * Agent-Side SDK Module\n *\n * Tools for AI agents to present credentials, handle challenges,\n * and interact with the AstraSync verification protocol.\n */\n\nexport { AgentClient } from './client';\nexport { ChallengeHandler } from './challenge-handler';\nexport { formatPDLSSForTransport, parsePDLSSFromTransport } from './pdlss-formatter';\nexport type { PDLSSConfig, TransportPDLSS } from './pdlss-formatter';\nexport { recordDecision } from './decision-client';\nexport { AstraSyncSdkError, OwnershipMismatchError } from './errors';\n","/**\n * Agent-side SDK errors.\n */\n\nexport class AstraSyncSdkError extends Error {\n readonly code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = 'AstraSyncSdkError';\n this.code = code;\n }\n}\n\n/**\n * Thrown when the API key used to initialise AgentClient is not owned by\n * the same account that registered the configured ASTRA-id. Blocks the\n * client from doing anything under a mismatched identity.\n */\nexport class OwnershipMismatchError extends AstraSyncSdkError {\n readonly astraId: string;\n\n constructor(astraId: string) {\n super(\n 'ownership_mismatch',\n `The configured API key does not own agent ${astraId}. Refusing to initialise.`\n );\n this.name = 'OwnershipMismatchError';\n this.astraId = astraId;\n }\n}\n","/**\n * AgentClient — Credential Presentation\n *\n * Agent-side SDK for automatically injecting AstraSync credentials\n * into outgoing requests across all supported protocols.\n */\n\nimport { sdkFetch } from '../http';\nimport type { AstraSyncCredentials, ProtocolTransport } from '../types';\nimport { setHttpHeaders } from '../transport/http';\nimport { setA2AMetadata } from '../transport/a2a';\nimport { setMcpMeta } from '../transport/mcp';\nimport { applyCredentials } from '../transport';\nimport { OwnershipMismatchError } from './errors';\n\ninterface AgentClientConfig {\n agentId: string;\n verifyUrl?: string;\n challengeUrl?: string;\n pdlss?: AstraSyncCredentials['pdlss'];\n /** Base URL for AstraSync API (used for ownership check). Defaults to https://astrasync.ai/api */\n apiBaseUrl?: string;\n /** API key used to authenticate ownership check + other authenticated calls. */\n apiKey?: string;\n}\n\ninterface FetchOptions extends RequestInit {\n purpose?: string;\n action?: string;\n}\n\nexport class AgentClient {\n private credentials: AstraSyncCredentials;\n private apiBaseUrl: string;\n private apiKey: string | undefined;\n\n constructor(config: AgentClientConfig) {\n this.credentials = {\n agentId: config.agentId,\n verifyUrl: config.verifyUrl ?? 'https://astrasync.ai/api/agents/verify-access',\n challengeUrl: config.challengeUrl,\n pdlss: config.pdlss,\n };\n this.apiBaseUrl = config.apiBaseUrl ?? 'https://astrasync.ai/api';\n this.apiKey = config.apiKey;\n }\n\n /**\n * Async factory that validates the API key's account owns the configured\n * ASTRA-id before returning a usable client. Refuses to initialise on\n * mismatch so a stolen ASTRA-id cannot be paired with a valid (different)\n * API key.\n *\n * Set env `ASTRASYNC_SKIP_OWNERSHIP_CHECK=true` to bypass — intended for\n * test environments only.\n */\n static async create(config: AgentClientConfig): Promise<AgentClient> {\n const client = new AgentClient(config);\n\n const skip =\n typeof process !== 'undefined' && process.env?.ASTRASYNC_SKIP_OWNERSHIP_CHECK === 'true';\n if (skip) return client;\n\n if (!config.apiKey) {\n // Without an API key we cannot bind ownership. Surface this as the\n // same refusal so misconfigured clients fail loudly.\n throw new OwnershipMismatchError(config.agentId);\n }\n\n const owned = await client.verifyOwnership();\n if (!owned) throw new OwnershipMismatchError(config.agentId);\n return client;\n }\n\n /**\n * Calls GET /api/agents/:astraId/ownership with the configured API key.\n * Returns true only when the backend confirms this API key's account\n * owns the configured agent.\n */\n private async verifyOwnership(): Promise<boolean> {\n if (!this.apiKey) return false;\n const url = `${this.apiBaseUrl.replace(/\\/+$/, '')}/api/agents/${encodeURIComponent(\n this.credentials.agentId\n )}/ownership`;\n const resp = await sdkFetch(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n });\n if (!resp.ok) return false;\n const body = (await resp.json().catch(() => null)) as {\n success?: boolean;\n data?: { owned?: boolean };\n } | null;\n return Boolean(body?.data?.owned);\n }\n\n /**\n * Make an HTTP request with AstraSync headers automatically injected.\n */\n async fetch(url: string, options?: FetchOptions): Promise<Response> {\n const { purpose, action, ...fetchOptions } = options ?? {};\n\n // Build credentials with optional overrides\n const creds: AstraSyncCredentials = { ...this.credentials };\n if (purpose) {\n creds.pdlss = {\n ...creds.pdlss,\n purpose: { category: purpose, action },\n };\n }\n\n // Inject AstraSync headers\n const existingHeaders: Record<string, string> = {};\n if (fetchOptions.headers) {\n if (fetchOptions.headers instanceof Headers) {\n fetchOptions.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n } else if (Array.isArray(fetchOptions.headers)) {\n for (const [key, value] of fetchOptions.headers) {\n existingHeaders[key] = value;\n }\n } else {\n Object.assign(existingHeaders, fetchOptions.headers);\n }\n }\n\n const enrichedHeaders = setHttpHeaders(existingHeaders, creds);\n\n return sdkFetch(url, {\n ...fetchOptions,\n headers: enrichedHeaders,\n });\n }\n\n /**\n * Prepare A2A task metadata with AstraSync credentials.\n */\n prepareA2AMetadata(\n task: Record<string, unknown>,\n overrides?: { purpose?: string; action?: string }\n ): Record<string, unknown> {\n const creds = this.buildCredentials(overrides);\n return setA2AMetadata(task, creds);\n }\n\n /**\n * Prepare MCP params with AstraSync _meta.\n */\n prepareMcpMeta(\n params: Record<string, unknown>,\n overrides?: { purpose?: string; action?: string }\n ): Record<string, unknown> {\n const creds = this.buildCredentials(overrides);\n return setMcpMeta(params, creds);\n }\n\n /**\n * Generic: apply credentials to any protocol.\n */\n applyCredentials(\n protocol: ProtocolTransport,\n target: Record<string, unknown>,\n overrides?: { purpose?: string; action?: string }\n ): Record<string, unknown> {\n const creds = this.buildCredentials(overrides);\n return applyCredentials(protocol, target, creds);\n }\n\n private buildCredentials(overrides?: {\n purpose?: string;\n action?: string;\n }): AstraSyncCredentials {\n if (!overrides?.purpose) return this.credentials;\n\n return {\n ...this.credentials,\n pdlss: {\n ...this.credentials.pdlss,\n purpose: { category: overrides.purpose, action: overrides.action },\n },\n };\n }\n}\n","/**\n * ChallengeHandler — Agent-Side Runtime Challenge Responder\n *\n * Handles incoming runtime challenges from AstraSync's verification service.\n * Agents register pending counterparties before initiating contact,\n * then this handler validates and responds to challenges.\n */\n\ninterface ChallengePayload {\n challengeId: string;\n type: string;\n counterpartyId?: string | null;\n counterpartyUrl?: string | null;\n question?: string;\n issuedAt: string;\n expiresAt: string;\n}\n\ninterface ChallengeResponse {\n status: number;\n body: {\n challengeId: string;\n acknowledged: boolean;\n pendingCounterparties: string[];\n respondedAt: string;\n error?: string;\n };\n}\n\ninterface ChallengeHandlerConfig {\n agentId: string;\n}\n\nexport class ChallengeHandler {\n private agentId: string;\n private pendingCounterparties: Set<string> = new Set();\n\n constructor(config: ChallengeHandlerConfig) {\n this.agentId = config.agentId;\n }\n\n /**\n * Register a counterparty as pending (before initiating contact).\n */\n registerPending(counterpartyId: string): void {\n this.pendingCounterparties.add(counterpartyId);\n }\n\n /**\n * Remove a counterparty from pending list (after interaction complete).\n */\n removePending(counterpartyId: string): void {\n this.pendingCounterparties.delete(counterpartyId);\n }\n\n /**\n * Get current pending counterparties list.\n */\n getPendingList(): string[] {\n return [...this.pendingCounterparties];\n }\n\n /**\n * Express middleware for the challenge endpoint.\n * Mount at: app.post('/astrasync/challenge', handler.expressMiddleware())\n */\n expressMiddleware(): (\n req: { body: unknown },\n res: { status: (code: number) => { json: (body: unknown) => void } }\n ) => void {\n return (req, res) => {\n const result = this.handleChallenge(req.body);\n res.status(result.status).json(result.body);\n };\n }\n\n /**\n * Generic handler (framework-agnostic).\n * Returns { status, body } for the caller to send.\n */\n handleChallenge(body: unknown): ChallengeResponse {\n // Validate payload shape\n if (!body || typeof body !== 'object') {\n return {\n status: 400,\n body: {\n challengeId: '',\n acknowledged: false,\n pendingCounterparties: [],\n respondedAt: new Date().toISOString(),\n error: 'Invalid challenge payload',\n },\n };\n }\n\n const payload = body as ChallengePayload;\n\n if (!payload.challengeId || !payload.issuedAt || !payload.expiresAt) {\n return {\n status: 400,\n body: {\n challengeId: payload.challengeId ?? '',\n acknowledged: false,\n pendingCounterparties: [],\n respondedAt: new Date().toISOString(),\n error: 'Missing required challenge fields',\n },\n };\n }\n\n // Check if challenge has expired\n const now = new Date();\n const expiresAt = new Date(payload.expiresAt);\n if (now > expiresAt) {\n return {\n status: 410,\n body: {\n challengeId: payload.challengeId,\n acknowledged: false,\n pendingCounterparties: [],\n respondedAt: now.toISOString(),\n error: 'Challenge has expired',\n },\n };\n }\n\n // Build the pending counterparties list. When the agent has pre-registered\n // counterparties via registerPending(), use that whitelist. Otherwise,\n // auto-include the incoming counterpartyId/counterpartyUrl from the\n // challenge payload so the default behaviour is correct without requiring\n // agents to call registerPending() before every interaction.\n const explicitList = this.getPendingList();\n const pendingCounterparties =\n explicitList.length > 0\n ? explicitList\n : [payload.counterpartyId, payload.counterpartyUrl].filter(\n (v): v is string => typeof v === 'string' && v.length > 0\n );\n\n return {\n status: 200,\n body: {\n challengeId: payload.challengeId,\n acknowledged: true,\n pendingCounterparties,\n respondedAt: now.toISOString(),\n },\n };\n }\n}\n","/**\n * PDLSS Formatter — Transport Format Conversion\n *\n * Converts between full PDLSS boundaries and compact transport format\n * used in HTTP headers, A2A metadata, and MCP _meta blocks.\n */\n\nimport type { AstraSyncCredentials } from '../types';\n\n/**\n * Full PDLSS configuration (as returned by the backend).\n */\nexport interface PDLSSConfig {\n purpose?: {\n categories?: string[];\n allowedActions?: string[];\n deniedActions?: string[];\n };\n duration?: {\n maxSessionDuration?: number;\n ttl?: number;\n allowedDays?: number[];\n allowedHours?: { start: number; end: number };\n };\n limits?: {\n autonomousThreshold?: number;\n approvalThreshold?: number;\n currency?: string;\n };\n scope?: {\n jurisdictions?: string[];\n resources?: string[];\n resourceTypes?: string[];\n };\n selfInstantiation?: {\n allowed: boolean;\n maxDepth?: number;\n maxSubAgents?: number;\n };\n}\n\n/**\n * Compact transport format (embedded in headers/metadata).\n */\nexport type TransportPDLSS = NonNullable<AstraSyncCredentials['pdlss']>;\n\n/**\n * Convert full PDLSS boundaries into compact transport format.\n * Used by AgentClient when building credential headers/metadata.\n */\nexport function formatPDLSSForTransport(pdlss: PDLSSConfig): TransportPDLSS {\n const transport: TransportPDLSS = {};\n\n // Purpose: pick the primary category and first allowed action\n if (pdlss.purpose?.categories?.length) {\n transport.purpose = {\n category: pdlss.purpose.categories[0],\n action: pdlss.purpose.allowedActions?.[0],\n };\n }\n\n // Duration: use the shorter of maxSessionDuration and ttl\n if (pdlss.duration) {\n const candidates: number[] = [];\n if (pdlss.duration.maxSessionDuration) candidates.push(pdlss.duration.maxSessionDuration);\n if (pdlss.duration.ttl) candidates.push(pdlss.duration.ttl);\n if (candidates.length > 0) {\n transport.duration = { maxSessionDuration: Math.min(...candidates) };\n }\n }\n\n // Scope: use the primary jurisdiction\n if (pdlss.scope?.jurisdictions?.length) {\n transport.scope = { jurisdiction: pdlss.scope.jurisdictions[0] };\n }\n\n return transport;\n}\n\n/**\n * Parse transport format back into full PDLSS config.\n * Used by counterparty-side when receiving credentials.\n */\nexport function parsePDLSSFromTransport(transport: TransportPDLSS): PDLSSConfig {\n const pdlss: PDLSSConfig = {};\n\n if (transport.purpose) {\n pdlss.purpose = {\n categories: [transport.purpose.category],\n allowedActions: transport.purpose.action ? [transport.purpose.action] : undefined,\n };\n }\n\n if (transport.duration) {\n pdlss.duration = {\n maxSessionDuration: transport.duration.maxSessionDuration,\n };\n }\n\n if (transport.scope) {\n pdlss.scope = {\n jurisdictions: transport.scope.jurisdiction ? [transport.scope.jurisdiction] : undefined,\n };\n }\n\n return pdlss;\n}\n","/**\n * Decision Client — Counterparty-Side Decision Recording\n *\n * Helper for counterparties to record their grant/deny decisions\n * back to AstraSync after receiving a verification result.\n */\n\nimport { sdkFetch } from '../http';\nimport type { GatewayConfig } from '../types';\n\ninterface RecordDecisionParams {\n sessionId: string;\n decision: 'granted' | 'denied';\n reason?: string;\n tokenIssued?: boolean;\n auditId?: string;\n}\n\ninterface RecordDecisionResult {\n recorded: boolean;\n blockchainTxHash?: string;\n}\n\n/**\n * Record a counterparty's grant/deny decision for a verification session.\n * POST to /agents/verify-access/:sessionId/decision\n */\nexport async function recordDecision(\n config: GatewayConfig,\n params: RecordDecisionParams\n): Promise<RecordDecisionResult> {\n const { sessionId, ...body } = params;\n const baseUrl = config.apiBaseUrl.replace(/\\/$/, '');\n const url = `${baseUrl}/agents/verify-access/${encodeURIComponent(sessionId)}/decision`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (config.apiKey) {\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n }\n\n if (config.customHeaders) {\n Object.assign(headers, config.customHeaders);\n }\n\n const response = await sdkFetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(\n `Failed to record decision for session ${sessionId}: ${response.status} ${errorText}`\n );\n }\n\n const result = await response.json();\n\n return {\n recorded: result.recorded ?? true,\n blockchainTxHash: result.blockchainTxHash,\n };\n}\n","/**\n * HTTP-client RUNTIME signatures — a display-only vocabulary, disjoint from\n * the platform-agent vendor vocabulary in `platform-signatures.ts`.\n *\n * A UA of `node` or `python-requests` identifies the HTTP STACK, never the\n * operator: OpenAI Codex, Claude Code, Perplexity's tooling, and our own SDK\n * all fetch through Node — labeling any of them a vendor from the runtime\n * alone would be fabrication. What we CAN say honestly is \"undeclared\n * automation on the Node.js runtime\", which beats \"unknown\" in every surface.\n *\n * HARD RULE: this module must NEVER be consulted by `edge-core/classify.ts`,\n * `detectPlatformFingerprint`, or any tiering / orphan-provisioning path.\n * Runtime matches carry no identity: promoting them to the `identified` tier\n * would flip anonymous-bot traffic to 1:1 beacons and auto-provision orphan\n * agents literally named \"node\". Display and clustering layers only.\n */\n\nexport interface RuntimeSignature {\n /** Stable runtime key — namespace disjoint from `PlatformAgentVendor`. */\n runtime: string;\n /** Human-readable label, e.g. \"Node.js runtime\". */\n displayName: string;\n uaPatterns: RegExp[];\n}\n\n/** First match wins — order more-specific tokens before generic ones. */\nexport const RUNTIME_SIGNATURES: ReadonlyArray<RuntimeSignature> = [\n {\n runtime: 'browser-automation',\n displayName: 'Browser automation',\n uaPatterns: [/headless/i, /phantomjs/i, /selenium/i, /playwright/i, /puppeteer/i],\n },\n {\n runtime: 'nodejs',\n displayName: 'Node.js runtime',\n // `node` exactly is the global-fetch default UA; the token forms cover\n // the common Node HTTP libraries.\n uaPatterns: [/^node$/i, /^undici/i, /node-fetch/i, /^axios/i, /^got\\b/i, /needle/i],\n },\n {\n runtime: 'python',\n displayName: 'Python runtime',\n uaPatterns: [/python-requests/i, /python-urllib/i, /^python\\b/i, /httpx/i, /aiohttp/i],\n },\n { runtime: 'go', displayName: 'Go runtime', uaPatterns: [/go-http-client/i] },\n {\n runtime: 'java',\n displayName: 'Java runtime',\n uaPatterns: [/^java\\//i, /okhttp/i, /apache-httpclient/i],\n },\n { runtime: 'curl', displayName: 'curl', uaPatterns: [/^curl\\//i] },\n { runtime: 'wget', displayName: 'wget', uaPatterns: [/^wget\\//i] },\n { runtime: 'ruby', displayName: 'Ruby runtime', uaPatterns: [/^ruby\\b/i, /faraday/i] },\n {\n runtime: 'php',\n displayName: 'PHP runtime',\n uaPatterns: [/^php\\b/i, /guzzlehttp/i, /^symfony/i],\n },\n { runtime: 'dotnet', displayName: '.NET runtime', uaPatterns: [/^dotnet/i, /httpclient/i] },\n { runtime: 'dart', displayName: 'Dart runtime', uaPatterns: [/^dart/i] },\n];\n\n/**\n * Detect the HTTP-client runtime from a User-Agent. Returns the displayName\n * (e.g. \"Node.js runtime\") or undefined when the UA doesn't look like a bare\n * runtime/library client.\n */\nexport function detectRuntime(userAgent: string | undefined | null): string | undefined {\n if (!userAgent) return undefined;\n const ua = userAgent.trim();\n for (const sig of RUNTIME_SIGNATURES) {\n if (sig.uaPatterns.some((p) => p.test(ua))) return sig.displayName;\n }\n return undefined;\n}\n"],"mappings":"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","names":["has","result","cache","inflight","headerValue","result","createMiddleware","matchRoute","findRouteConfig","DEFAULT_ROUTES_REFRESH_MS","createMiddleware","readHeader","coerceString","stripQuery","extractSessionId","readHeader","coerceString","coerceString","coerceNumber","claim","decodeSdJwtSync","createHash","sha256Sync","applyDisclosures","coerceMandateType","coerceString","coerceNumber","headerValue","readHeader","coerceString","headerValue","readHeader","createHash","coerceString","createHash","toUnixSeconds","cache","cache","dedupeFailures","sleep","recordDecision","recordDecision"]}
|