@astrasyncai/adapter-lambda 1.1.0 → 1.2.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/dist/index.js CHANGED
@@ -452,7 +452,9 @@ function buildVerificationRequest(options, request, classification, includeArtif
452
452
  astraPurpose: getHeader(request, "x-astra-purpose"),
453
453
  astraAction: getHeader(request, "x-astra-action")
454
454
  });
455
+ const attemptId = getHeader(request, "x-astra-attempt-id");
455
456
  return {
457
+ ...attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId },
456
458
  credentials: (0, import_verify3.extractCredentials)(headers, {}),
457
459
  purpose: pdlss.purpose,
458
460
  action: pdlss.action,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cf.ts","../src/config.ts","../src/classify.ts","../src/detect.ts","../src/pipeline.ts","../src/events.ts","../src/messaging.ts","../src/enforce.ts","../src/handler.ts"],"sourcesContent":["/**\n * @astrasyncai/adapter-lambda — Commerce Shield edge adapter (spec §7.4,\n * backlog §33.5 #1).\n *\n * Library surface: `createEdgeHandler(options)` builds a Lambda@Edge\n * origin-request handler. The deployable single-file bundle lives at\n * `dist/lambda/index.js` (see `src/lambda-entry.ts` + `infra/`).\n */\n\nexport { createEdgeHandler, type EdgeHandler } from './handler';\nexport { classify, resolvePolicy } from './classify';\nexport { detectCommerce, type DetectedCommerce } from './detect';\nexport { runTier } from './pipeline';\nexport { applyOutcome, ASAT_HEADERS } from './enforce';\nexport { buildDenyBody, buildManualReviewBody } from './messaging';\nexport { emitBeacon, withBudget, sampled } from './events';\nexport { resolveApiKey, loadEdgeConfig, _resetConfigCaches } from './config';\nexport {\n getRequest,\n getHeader,\n flattenHeaders,\n decodeBody,\n requestUrl,\n setHeader,\n stripHeadersByPrefix,\n jsonResponse,\n} from './cf';\nexport type {\n EdgeAdapterOptions,\n Classification,\n TrafficTier,\n TierOutcome,\n EdgeDecision,\n EffectivePolicy,\n} from './types';\n","/**\n * CloudFront origin-request event helpers. The Lambda@Edge event shape puts\n * headers in `{ key, value }[]` arrays keyed by LOWERCASED header name, and\n * (with IncludeBody) the body arrives base64-encoded with an\n * `inputTruncated` flag when it exceeded CloudFront's ~1MB exposure cap.\n */\n\nimport type {\n CloudFrontRequest,\n CloudFrontRequestEvent,\n CloudFrontHeaders,\n CloudFrontResultResponse,\n} from 'aws-lambda';\nimport {\n sanitizeHeaders,\n type ObservedMetadata,\n} from '@astrasyncai/verification-gateway/metadata-capture';\n\nexport function getRequest(event: CloudFrontRequestEvent): CloudFrontRequest {\n return event.Records[0].cf.request;\n}\n\n/** First value of a header (lowercase name), or undefined. */\nexport function getHeader(request: CloudFrontRequest, name: string): string | undefined {\n return request.headers[name.toLowerCase()]?.[0]?.value;\n}\n\n/**\n * Flatten CloudFront headers into the `Record<string, string | string[]>`\n * shape the SDK extractors and verify-access artifacts expect.\n */\nexport function flattenHeaders(headers: CloudFrontHeaders): Record<string, string | string[]> {\n const out: Record<string, string | string[]> = {};\n for (const [name, entries] of Object.entries(headers)) {\n if (!entries?.length) continue;\n out[name] = entries.length === 1 ? entries[0].value : entries.map((e) => e.value);\n }\n return out;\n}\n\nexport interface DecodedBody {\n /** UTF-8 body text, undefined when there is no body. */\n text?: string;\n /** True when CloudFront truncated the body before handing it to the trigger. */\n truncated: boolean;\n}\n\nexport function decodeBody(request: CloudFrontRequest): DecodedBody {\n const body = request.body;\n if (!body?.data) return { truncated: false };\n const text =\n body.encoding === 'base64' ? Buffer.from(body.data, 'base64').toString('utf8') : body.data;\n return { text, truncated: body.inputTruncated === true };\n}\n\n/**\n * Workstream D — connection-layer signals the edge can see but the SDK cannot.\n * CloudFront injects the `CloudFront-Viewer-*` header family (IP, ASN, country,\n * TLS version/cipher, HTTP version, device class) when the OriginRequestPolicy\n * whitelists them (see infra/template.yaml). Absent values are simply omitted —\n * a partial connection block is fine.\n */\nexport function collectConnectionMetadata(request: CloudFrontRequest): Record<string, string> {\n const out: Record<string, string> = {};\n const put = (key: string, headerName: string, transform?: (v: string) => string) => {\n const v = getHeader(request, headerName);\n if (v) out[key] = transform ? transform(v) : v;\n };\n // `cloudfront-viewer-address` is `ip:port` (IPv6 keeps its brackets); take the\n // address portion the same way the beacon/pipeline already do.\n const addr = getHeader(request, 'cloudfront-viewer-address');\n if (addr) out.ip = addr.replace(/:\\d+$/, '');\n put('country', 'cloudfront-viewer-country');\n put('countryName', 'cloudfront-viewer-country-name');\n put('region', 'cloudfront-viewer-country-region');\n put('city', 'cloudfront-viewer-city');\n put('asn', 'cloudfront-viewer-asn');\n put('tlsVersion', 'cloudfront-viewer-tls');\n put('httpVersion', 'cloudfront-viewer-http-version');\n // Device-class booleans → a single compact device string.\n const devices: string[] = [];\n for (const [label, header] of [\n ['desktop', 'cloudfront-is-desktop-viewer'],\n ['mobile', 'cloudfront-is-mobile-viewer'],\n ['tablet', 'cloudfront-is-tablet-viewer'],\n ['smarttv', 'cloudfront-is-smarttv-viewer'],\n ] as const) {\n if (getHeader(request, header) === 'true') devices.push(label);\n }\n if (devices.length) out.device = devices.join(',');\n return out;\n}\n\n/**\n * Workstream D — the FULL sanitised metadata capture for one request: every\n * inbound header (secrets stripped, credential headers reduced to a safe format\n * prefix) plus the connection-layer block. The edge is the richest capture\n * point — the header arrays are already in memory — and this is pure string\n * work, so it adds no page latency. Forwarded on both the verify-access call\n * and the beacon.\n */\nexport function buildObservedMetadata(request: CloudFrontRequest): ObservedMetadata {\n const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(\n flattenHeaders(request.headers)\n );\n const connection = collectConnectionMetadata(request);\n return {\n headers,\n ...(apiKeyFormat && { apiKeyFormat }),\n ...(platformHeaders && { platformHeaders }),\n ...(Object.keys(connection).length > 0 && { connection }),\n };\n}\n\n/**\n * Workstream D — normalize the origin-bound `Host` header.\n *\n * To receive the `CloudFront-Viewer-*` connection headers (IP/ASN/TLS/country)\n * we must move off the managed `AllViewerExceptHostHeader` origin-request policy\n * onto one that whitelists those headers — but every such policy ALSO forwards\n * the viewer `Host`, which would break vhost / PaaS origin routing that expects\n * the origin's own hostname. So the Lambda takes ownership of the Host rewrite:\n * stash the public (viewer) host into `X-Forwarded-Host` for downstream use and\n * detection, then set `Host` to the origin's domain (available on the event as\n * `request.origin.custom.domainName`). No-ops when the origin domain is absent\n * (synthetic test events) or already matches — so it is safe on every path,\n * including static-asset pass-through.\n */\nexport function normalizeOriginHost(request: CloudFrontRequest): void {\n const originDomain =\n request.origin?.custom?.domainName ?? request.origin?.s3?.domainName ?? undefined;\n if (!originDomain) return;\n const currentHost = getHeader(request, 'host');\n if (!currentHost || currentHost === originDomain) return;\n if (!getHeader(request, 'x-forwarded-host')) {\n setHeader(request, 'X-Forwarded-Host', currentHost);\n }\n setHeader(request, 'Host', originDomain);\n}\n\n/** Full request URL as the origin will see it (scheme fixed to https). */\nexport function requestUrl(request: CloudFrontRequest, host: string): string {\n const qs = request.querystring ? `?${request.querystring}` : '';\n return `https://${host}${request.uri}${qs}`;\n}\n\n/**\n * Set a header on the origin-bound request (overwrites all prior values).\n */\nexport function setHeader(request: CloudFrontRequest, name: string, value: string): void {\n request.headers[name.toLowerCase()] = [{ key: name, value }];\n}\n\n/**\n * Strip every inbound header matching a prefix (lowercase compare). Used to\n * drop spoofed `x-astrasync-*` trust headers before the shell injects its\n * own — in BOTH modes, so a caller can never smuggle trust past the origin.\n */\nexport function stripHeadersByPrefix(request: CloudFrontRequest, prefix: string): void {\n const p = prefix.toLowerCase();\n for (const name of Object.keys(request.headers)) {\n if (name.startsWith(p)) delete request.headers[name];\n }\n}\n\nexport function jsonResponse(\n status: number,\n body: unknown,\n extraHeaders?: Record<string, string>\n): CloudFrontResultResponse {\n const headers: CloudFrontResultResponse['headers'] = {\n 'content-type': [{ key: 'Content-Type', value: 'application/json' }],\n };\n for (const [name, value] of Object.entries(extraHeaders ?? {})) {\n headers[name.toLowerCase()] = [{ key: name, value }];\n }\n return {\n status: String(status),\n statusDescription: status === 403 ? 'Forbidden' : status === 202 ? 'Accepted' : 'OK',\n headers,\n body: JSON.stringify(body),\n };\n}\n","/**\n * Runtime configuration for the edge shell.\n *\n * Lambda@Edge forbids environment variables, so configuration is layered:\n * 1. Build-time constants baked into the bundle (apiBaseUrl,\n * counterpartyId, counterpartyUrl, apiKeySecretName) — see\n * `tsup.config.ts` define block and `infra/deploy.sh`.\n * 2. The merchant API key from AWS Secrets Manager (us-east-1), fetched\n * lazily once per container and cached with a 15-minute TTL so\n * rotation needs no redeploy. Observe mode works fully without it —\n * the beacon endpoint is unauthenticated and verify() degrades\n * keyless — so a Secrets Manager outage can never take the shell down.\n * 3. The dashboard EdgeConfig via the SDK's getEdgeConfig (60s TTL,\n * stale-while-revalidate, enforce→observe degradation after 24h\n * staleness, DEFAULT_EDGE_CONFIG fallback — all in the SDK).\n */\n\nimport {\n getEdgeConfig,\n DEFAULT_EDGE_CONFIG,\n type EdgeConfig,\n} from '@astrasyncai/verification-gateway/edge-config';\nimport type { EdgeAdapterOptions } from './types';\n\nconst SECRET_TTL_MS = 15 * 60 * 1000;\n\ninterface SecretCacheEntry {\n value: string | undefined;\n fetchedAt: number;\n}\n\nconst secretCache = new Map<string, SecretCacheEntry>();\n\nasync function defaultFetchSecret(secretName: string): Promise<string | undefined> {\n // Lazy import so tests (and the library build) never touch the AWS SDK\n // unless a secret name is actually configured.\n const { SecretsManagerClient, GetSecretValueCommand } =\n await import('@aws-sdk/client-secrets-manager');\n // Lambda@Edge replicates globally but secrets live in us-east-1 (the\n // Lambda@Edge home region).\n const client = new SecretsManagerClient({ region: 'us-east-1' });\n const result = await client.send(new GetSecretValueCommand({ SecretId: secretName }));\n return result.SecretString ?? undefined;\n}\n\n/**\n * Resolve the merchant API key. Never throws — a missing/unreachable secret\n * degrades to keyless operation (observe mode is fully functional without\n * it; enforce mode without a key cannot fetch a config that enforces, so it\n * degrades to observe by construction).\n */\nexport async function resolveApiKey(options: EdgeAdapterOptions): Promise<string | undefined> {\n if (options.apiKey) return options.apiKey;\n const secretName = options.apiKeySecretName;\n if (!secretName) return undefined;\n\n const cached = secretCache.get(secretName);\n if (cached && Date.now() - cached.fetchedAt < SECRET_TTL_MS) return cached.value;\n\n try {\n const fetcher = options.fetchSecret ?? defaultFetchSecret;\n const value = await fetcher(secretName);\n secretCache.set(secretName, { value, fetchedAt: Date.now() });\n return value;\n } catch (err) {\n options.log?.('warn', 'Secrets Manager fetch failed — continuing keyless', {\n secretName,\n error: err instanceof Error ? err.message : String(err),\n });\n // Serve a stale value if we ever had one; otherwise keyless.\n return cached?.value;\n }\n}\n\n/**\n * Load the effective EdgeConfig. Delegates caching/fallback/degradation to\n * the SDK; adds the compile-time fallback override and never throws.\n */\nexport async function loadEdgeConfig(\n options: EdgeAdapterOptions,\n apiKey: string | undefined\n): Promise<EdgeConfig> {\n try {\n return await getEdgeConfig({ apiBaseUrl: options.apiBaseUrl, apiKey }, options.counterpartyId, {\n ttlMs: options.configTtlMs,\n });\n } catch {\n return options.fallbackConfig ?? DEFAULT_EDGE_CONFIG;\n }\n}\n\n/** Reset module caches — tests only. */\nexport function _resetConfigCaches(): void {\n secretCache.clear();\n}\n","/**\n * Three-tier traffic classification (§33.5 #1: verified /\n * identified-but-unregistered / anonymous) plus the two non-tiers the shell\n * touches as little as possible: `human` (zero network calls, zero logging)\n * and `skipped` (static assets / excluded paths).\n *\n * Cheapest checks first — the human path must add microseconds, not\n * milliseconds. Platform signatures come from the SDK so the edge and the\n * backend's verify-access anonymous handler classify identically.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { detectPlatformFingerprint } from '@astrasyncai/verification-gateway/platform-signatures';\nimport { matchEdgePathRule, type EdgeConfig } from '@astrasyncai/verification-gateway/edge-config';\nimport { sanitizeHeaders } from '@astrasyncai/verification-gateway/metadata-capture';\nimport { getHeader, decodeBody, flattenHeaders } from './cf';\nimport { detectCommerce } from './detect';\nimport type { Classification, EffectivePolicy } from './types';\n\n/** Extensions the shell 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/** 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 * 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 decode, no header sniffing\n * beyond UA) — that is the zero-friction setting.\n */\nexport function classify(\n request: CloudFrontRequest,\n host: string,\n depth: 'classify' | 'authenticate' | 'authorize'\n): Classification {\n const userAgent = getHeader(request, 'user-agent') ?? '';\n const flat = flattenHeaders(request.headers);\n\n // 1. Native AstraSync credentials.\n const credentials = extractCredentials(flat, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { tier: 'verified', protocol: 'x-astra' };\n }\n\n // Workstream D — the key-format prefix + platform-signal headers are stronger,\n // less-spoofable platform signals than the UA. Compute once (cheap string\n // work) and feed every fingerprint call below.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(flat);\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(request, host, decodeBody(request));\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 (!getHeader(request, 'sec-fetch-mode') && !getHeader(request, 'accept-language')) {\n return { tier: 'anonymous-bot', evidence: { userAgent, spoofedBrowser: true } };\n }\n\n // 5. Human traffic — the shell 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 };\n","/**\n * Crypto-free commerce-protocol detection (§7.4.2 detection order).\n *\n * The edge only SNIFFS — header shapes, compact-JWT patterns, body field\n * names — and packages what it saw as raw `CommerceArtifactsPayload` for\n * verify-access, whose Step 0.5 pipeline does the authoritative parsing and\n * cryptographic verification server-side. Nothing here imports jose/sd-jwt/\n * signature libraries: detection must stay cheap enough to run on every\n * non-human request, and verification must happen exactly once, in the\n * canonical sink, where it is recorded.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport type { CommerceArtifactsPayload } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, requestUrl, type DecodedBody } from './cf';\n\nexport interface DetectedCommerce {\n /** Detection-order label: rfc9421-agent-pay | rfc9421-tap | rfc9421-web-bot-auth | vi-sd-jwt | ap2 | acp | ucp | mpp | x402 */\n protocol: string;\n artifacts: CommerceArtifactsPayload;\n /** Light detection detail for beacons/audit — never secrets or full credentials. */\n evidence: Record<string, unknown>;\n}\n\n/** Compact SD-JWT: JWT + `~`-separated disclosures. */\nconst SD_JWT_PATTERN = /^eyJ[\\w-]+\\.[\\w-]*\\.[\\w-]+~/;\n\n/** Decode a JWT header segment without verifying anything. */\nfunction sniffJwtHeader(compact: string): Record<string, unknown> | undefined {\n try {\n const seg = compact.split('.')[0];\n return JSON.parse(Buffer.from(seg, 'base64url').toString('utf8')) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonBody(body: DecodedBody): Record<string, unknown> | undefined {\n if (!body.text) return undefined;\n try {\n const parsed: unknown = JSON.parse(body.text);\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * §7.4.2 order (after the X-Astra native check, which classify.ts owns):\n * SD-JWT/VI → RFC 9421 (Agent Pay / TAP / Web Bot Auth by kid namespace or\n * Signature-Agent) → ACP HMAC → UCP session → AP2 body triple → MPP → x402.\n * Returns undefined when nothing commerce-shaped is on the wire.\n *\n * When the body was truncated by CloudFront (`inputTruncated`), body-bound\n * artifacts still forward what arrived but carry a `bodyTruncated` evidence\n * flag — the backend downgrades those signatures rather than hard-failing.\n */\nexport function detectCommerce(\n request: CloudFrontRequest,\n host: string,\n body: DecodedBody\n): DetectedCommerce | undefined {\n const url = requestUrl(request, host);\n const method = request.method;\n const headers = flattenHeaders(request.headers);\n const jsonBody = parseJsonBody(body);\n const truncated = body.truncated ? { bodyTruncated: true } : {};\n\n // --- VI / SD-JWT credential in a header ------------------------------\n const authHeader = getHeader(request, 'authorization');\n const bearer = authHeader?.replace(/^Bearer\\s+/i, '');\n const mandateHeader =\n getHeader(request, 'x-payment-mandate') ?? getHeader(request, 'payment-mandate');\n const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));\n if (sdJwtCandidate) {\n const typ = sniffJwtHeader(sdJwtCandidate)?.typ;\n return {\n protocol: 'vi-sd-jwt',\n artifacts: { viSdJwt: sdJwtCandidate },\n evidence: { typ, ...truncated },\n };\n }\n\n // --- RFC 9421 (Agent Pay / TAP / Web Bot Auth) ------------------------\n const signature = getHeader(request, 'signature');\n const signatureInput = getHeader(request, 'signature-input');\n if (signature && signatureInput) {\n const signatureAgent = getHeader(request, 'signature-agent');\n const registryHint = getHeader(request, 'x-agent-registry');\n const lowerInput = signatureInput.toLowerCase();\n const protocol = signatureAgent\n ? 'rfc9421-web-bot-auth'\n : registryHint?.toLowerCase().includes('visa') || lowerInput.includes('visa')\n ? 'rfc9421-tap'\n : registryHint?.toLowerCase().includes('mastercard') || lowerInput.includes('mastercard')\n ? 'rfc9421-agent-pay'\n : 'rfc9421';\n return {\n protocol,\n artifacts: {\n rfc9421: { headers, method, url, ...(body.text && { body: body.text }) },\n },\n evidence: {\n ...(signatureAgent && { signatureAgent }),\n ...(registryHint && { registryHint }),\n keyid: signatureInput.match(/keyid=\"([^\"]+)\"/)?.[1],\n ...truncated,\n },\n };\n }\n\n // --- ACP (HMAC-signed webhook/checkout: signature WITHOUT signature-input)\n const acpTimestamp = getHeader(request, 'timestamp');\n if (signature && !signatureInput && (acpTimestamp || getHeader(request, 'idempotency-key'))) {\n return {\n protocol: 'acp',\n artifacts: {\n acpRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated },\n };\n }\n\n // --- UCP checkout session ---------------------------------------------\n if (/\\/checkout[-_]sessions(\\/|$)/.test(request.uri)) {\n return {\n protocol: 'ucp',\n artifacts: { ucpRequest: { method, url, ...(jsonBody && { body: jsonBody }) } },\n evidence: { path: request.uri, ...truncated },\n };\n }\n\n // --- AP2 mandate triple in the body -----------------------------------\n if (jsonBody) {\n const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;\n const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;\n const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;\n if (typeof intent === 'string' || typeof cart === 'string' || typeof payment === 'string') {\n return {\n protocol: 'ap2',\n artifacts: {\n ap2Mandates: {\n ...(typeof intent === 'string' && { intent }),\n ...(typeof cart === 'string' && { cart }),\n ...(typeof payment === 'string' && { payment }),\n },\n },\n evidence: {\n mandatesPresent: [\n typeof intent === 'string' && 'intent',\n typeof cart === 'string' && 'cart',\n typeof payment === 'string' && 'payment',\n ].filter(Boolean),\n ...truncated,\n },\n };\n }\n }\n\n // --- MPP (`Authorization: Payment <credential>`) -----------------------\n if (authHeader && /^Payment\\s+/i.test(authHeader)) {\n return {\n protocol: 'mpp',\n artifacts: {\n mppRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: truncated,\n };\n }\n\n // --- x402 (X-PAYMENT header) ------------------------------------------\n if (getHeader(request, 'x-payment')) {\n return {\n protocol: 'x402',\n artifacts: {\n x402Request: { method, url, headers, ...(jsonBody && { body: jsonBody }) },\n },\n evidence: truncated,\n };\n }\n\n return undefined;\n}\n","/**\n * Depth-controlled verification per tier. The edge never verifies\n * credentials itself — it forwards what it detected to verify-access, the\n * canonical sole verification sink (backend Step 0.5 runs the commerce\n * pipeline, records events, provisions orphans, persists sessions). What\n * the depth setting controls is how much the edge LOOKS and how much it\n * FORWARDS:\n *\n * classify — what is it? UA tiers only. Zero verify-access calls;\n * beacons only.\n * authenticate — who is it? + protocol detection. X-Astra agents get a\n * verify-access identity check; commerce/platform traffic\n * is beaconed with protocol + evidence (no signature\n * verification anywhere).\n * authorize — are they allowed? + artifact forwarding. X-Astra verify\n * calls carry commerceArtifacts; identified traffic gets an\n * anonymous verify-access call with artifacts +\n * callerMetadata so the backend cryptographically proves\n * and policy-evaluates once.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { verify, extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { resolveHttpPdlss } from '@astrasyncai/verification-gateway/http-pdlss';\nimport type { GatewayConfig, VerificationRequest } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, buildObservedMetadata } from './cf';\nimport { withBudget, emitBeacon, sampled } from './events';\nimport type { Classification, EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\nfunction baseOutcome(classification: Classification): TierOutcome {\n return {\n tier: classification.tier,\n decision: 'allow',\n reasons: [],\n protocol: classification.protocol,\n };\n}\n\nfunction buildVerificationRequest(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n includeArtifacts: boolean\n): VerificationRequest {\n const headers = flattenHeaders(request.headers);\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n // verify-access REQUIRES a purpose. Resolve via the shared §4.6 chain:\n // the agent's X-Astra-Purpose/-Action declarations, else the pinned\n // method table (GET → data/data.read etc.) — a transport verb never\n // travels as a PDLSS action.\n const pdlss = resolveHttpPdlss({\n method: request.method,\n astraPurpose: getHeader(request, 'x-astra-purpose'),\n astraAction: getHeader(request, 'x-astra-action'),\n });\n return {\n credentials: extractCredentials(headers, {}),\n purpose: pdlss.purpose,\n action: pdlss.action,\n resource: request.uri,\n createSession: true,\n counterpartyType: 'website',\n counterpartyUrl: options.counterpartyUrl,\n callerMetadata: {\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n referer: getHeader(request, 'referer'),\n host: getHeader(request, 'host'),\n // Workstream D — the full sanitised header + connection capture. The\n // backend stores it fire-and-forget (zero decision latency) and uses the\n // key-format / platform headers for attribution.\n observedMetadata: buildObservedMetadata(request),\n },\n ...(includeArtifacts &&\n classification.artifacts && { commerceArtifacts: classification.artifacts }),\n };\n}\n\nfunction outcomeFromVerifyResult(\n classification: Classification,\n result: Awaited<ReturnType<typeof verify>>\n): TierOutcome {\n const outcome = baseOutcome(classification);\n outcome.sessionId = (result as { sessionId?: string }).sessionId;\n outcome.correlationId = result.correlationId;\n outcome.guidance = result.guidance;\n\n if (result.requiresStepUp || result.stepUpApproval) {\n outcome.decision = 'manual_review';\n outcome.reasons = ['step-up approval required'];\n outcome.stepUp = {\n pollUrl: (result.stepUpApproval as { pollUrl?: string } | undefined)?.pollUrl,\n expiresAt: (result.stepUpApproval as { expiresAt?: string } | undefined)?.expiresAt,\n };\n return outcome;\n }\n\n if (!result.identityVerified || !result.policyAllowed) {\n outcome.decision = 'deny';\n outcome.reasons = result.denialReasons?.length\n ? result.denialReasons\n : [!result.identityVerified ? 'identity not verified' : 'denied by access policy'];\n return outcome;\n }\n\n outcome.asat = {\n trustScore: result.agent?.trustScore,\n agentId: result.agent?.astraId,\n developerId: result.developer?.astradId,\n accessLevel: result.accessLevel,\n };\n return outcome;\n}\n\n/**\n * Run the tier-appropriate verification/telemetry for one classified\n * request. NEVER throws; on any failure returns an `allow` outcome with the\n * failure recorded in `reasons` (infra failures fail open — a presented\n * credential the BACKEND rejected is a deny, but an unreachable backend is\n * not a rejection).\n */\nexport async function runTier(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n policy: EffectivePolicy,\n apiKey: string | undefined,\n sampling: { anonymousBeaconRate: number }\n): Promise<TierOutcome> {\n const budgets = options.budgets ?? {};\n const beaconMs = budgets.beaconMs ?? 300;\n const verifyMs =\n policy.mode === 'enforce'\n ? (budgets.verifyEnforceMs ?? 3000)\n : (budgets.verifyObserveMs ?? 1500);\n\n const gatewayConfig: GatewayConfig = {\n apiBaseUrl: options.apiBaseUrl,\n ...(apiKey && { apiKey }),\n counterpartyId: options.counterpartyId,\n // The shell handles its own error semantics; init self-probes don't\n // belong in a per-request edge function.\n disableInitChecks: true,\n } as GatewayConfig;\n\n try {\n switch (classification.tier) {\n case 'verified': {\n // classify depth = zero API calls, even for credentialed agents.\n if (policy.depth === 'classify') {\n return baseOutcome(classification);\n }\n const result = await withBudget(\n verify(\n gatewayConfig,\n buildVerificationRequest(options, request, classification, policy.depth === 'authorize')\n ),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n\n case 'identified': {\n if (policy.depth === 'authorize' && classification.artifacts) {\n // Anonymous verify-access call WITH artifacts: the backend runs\n // the commerce pipeline, records unverified events, and\n // provisions orphan platform agents — one sink, recorded once.\n const result = await withBudget(\n verify(gatewayConfig, buildVerificationRequest(options, request, classification, true)),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n // classify/credentials depth (or no artifacts): lightweight beacon.\n await emitBeacon(options, request, classification, beaconMs);\n const outcome = baseOutcome(classification);\n if (policy.mode === 'enforce' && policy.depth !== 'classify') {\n // Unregistered agent on an enforced path: deny with guidance.\n outcome.decision = 'deny';\n outcome.reasons = ['agent is not registered with AstraSync'];\n }\n return outcome;\n }\n\n case 'anonymous-bot': {\n if (sampled(sampling.anonymousBeaconRate, options.random)) {\n await emitBeacon(\n options,\n request,\n { ...classification, protocol: classification.protocol ?? 'ua-heuristic' },\n beaconMs\n );\n }\n // Anonymous bots pass through even in enforce mode — enforce gates\n // AGENT traffic; generic bot management stays the CDN/WAF's job\n // (mixed-traffic classification §5.1.7 is the enforce-mode\n // prerequisite tracked as §33.5 #9).\n return baseOutcome(classification);\n }\n\n default:\n return baseOutcome(classification);\n }\n } catch (err) {\n const outcome = baseOutcome(classification);\n outcome.reasons = [\n `edge pipeline error — fail-open: ${err instanceof Error ? err.message : String(err)}`,\n ];\n return outcome;\n }\n}\n","/**\n * Time-budgeted event emission.\n *\n * Lambda@Edge has no `waitUntil` — anything not awaited before the handler\n * returns may never run (the container freezes). So every network call is\n * awaited under an explicit budget and DROPPED on timeout: latency to the\n * customer's traffic is bounded, and a slow AstraSync API costs telemetry,\n * never page loads.\n */\n\nimport { reportUnregisteredAttempt } from '@astrasyncai/verification-gateway/verify';\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { getHeader, buildObservedMetadata } from './cf';\nimport type { Classification, EdgeAdapterOptions } 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\n * (CSRF-exempt on the backend); the backend fingerprints the UA and\n * find-or-provisions orphan platform agents server-side.\n */\nexport async function emitBeacon(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n budgetMs: number\n): Promise<void> {\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n await withBudget(\n reportUnregisteredAttempt(\n { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },\n {\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: 'website',\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n requestPath: request.uri,\n requestMethod: request.method,\n // 3.9.0 evidence fields (backend persists them into eventData).\n protocol: classification.protocol,\n evidence: classification.evidence,\n // Workstream D — full sanitised header + connection capture for the\n // unregistered caller (fire-and-forget, so free).\n observedMetadata: buildObservedMetadata(request),\n }\n ),\n budgetMs\n );\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 * §7.4.6 — protocol-specific machine-readable messaging for enforce-mode\n * responses. Agents (not humans) consume these bodies: stable error codes,\n * the failure list, and registration guidance with real URLs.\n */\n\nimport type { TierOutcome } from './types';\n\nconst PROTOCOL_MESSAGES: Record<string, string> = {\n 'vi-sd-jwt':\n 'This request presented Visa Intelligent Commerce credentials, but the agent is not verified with AstraSync. Register the agent to pair your VI credentials with a verified identity and mandate.',\n 'rfc9421-agent-pay':\n 'This request carried a Mastercard Agent Pay signature, but the agent is not verified with AstraSync. Register the agent to pair Agent Pay credentials with a verified identity and mandate.',\n 'rfc9421-tap':\n 'This request carried a Visa TAP signature, but the agent is not verified with AstraSync. Register the agent to pair TAP credentials with a verified identity and mandate.',\n 'rfc9421-web-bot-auth':\n 'This request carried a Web Bot Auth signature, but the agent is not verified with AstraSync. Register the agent to link your signed-agent identity to a verified principal.',\n rfc9421:\n 'This request carried an RFC 9421 HTTP message signature, but the agent is not verified with AstraSync. Register the agent to link the signing identity to a verified principal.',\n acp: 'This request used the Agentic Commerce Protocol, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ucp: 'This request used a UCP checkout session, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ap2: 'This request presented AP2 mandates, but the agent is not verified with AstraSync. Register the agent to pair your mandates with a verified identity.',\n mpp: 'This request presented MPP payment credentials, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n x402: 'This request used x402 payment headers, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n 'platform-ua':\n 'This traffic was identified as a platform AI agent without AstraSync credentials. Register the agent to access this property with a verified identity.',\n 'x-astra':\n 'The presented AstraSync credentials failed verification or were denied by this property’s access policy.',\n};\n\nexport interface DenyBody {\n success: false;\n error: {\n code: 'UNAUTHORIZED' | 'INSUFFICIENT_ACCESS';\n message: string;\n protocol?: string;\n failures: string[];\n correlationId?: string;\n guidance: {\n message?: string;\n registrationUrl?: string;\n documentationUrl?: string;\n };\n };\n}\n\nexport function buildDenyBody(outcome: TierOutcome, apiBaseUrl: string): DenyBody {\n const origin = apiBaseUrl.replace(/\\/api\\/?$/, '');\n const protocolMessage =\n (outcome.protocol && PROTOCOL_MESSAGES[outcome.protocol]) ??\n 'This request could not be verified by AstraSync.';\n return {\n success: false,\n error: {\n // UNAUTHORIZED = identity failed (register/re-authenticate helps);\n // INSUFFICIENT_ACCESS = identity fine, policy denied (fix the mandate).\n code: outcome.tier === 'verified' ? 'INSUFFICIENT_ACCESS' : 'UNAUTHORIZED',\n message: protocolMessage,\n ...(outcome.protocol && { protocol: outcome.protocol }),\n failures: outcome.reasons,\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n guidance: {\n // `||` not `??`: verify() fills these with EMPTY STRINGS when the\n // well-known cache is cold — empty means \"use the fallback\".\n message:\n outcome.guidance?.message ||\n 'Register this agent with AstraSync to receive verifiable credentials.',\n registrationUrl: outcome.guidance?.registrationUrl || `${origin}/register`,\n documentationUrl: outcome.guidance?.documentationUrl || `${origin}/docs/edge-adapter`,\n },\n },\n };\n}\n\nexport interface ManualReviewBody {\n success: false;\n status: 'manual_review';\n message: string;\n stepUpApproval?: { pollUrl?: string; expiresAt?: string };\n correlationId?: string;\n}\n\nexport function buildManualReviewBody(outcome: TierOutcome): ManualReviewBody {\n return {\n success: false,\n status: 'manual_review',\n message:\n 'This action requires human approval. Poll the step-up approval endpoint and retry once approved.',\n ...(outcome.stepUp && { stepUpApproval: outcome.stepUp }),\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n };\n}\n","/**\n * Decision → CloudFront result wiring (§7.4 enforcement, §7.4.7 ASAT\n * headers). Executed in BOTH modes so observe mode records exactly what\n * enforce mode would have done — but only enforce mode is allowed to return\n * anything other than the origin-bound request.\n */\n\nimport type { CloudFrontRequest, CloudFrontRequestResult } from 'aws-lambda';\nimport { jsonResponse, setHeader, stripHeadersByPrefix } from './cf';\nimport { buildDenyBody, buildManualReviewBody } from './messaging';\nimport type { EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\n/** §7.4.7 ASAT trust-attestation headers injected on allowed requests. */\nexport const ASAT_HEADERS = {\n trustScore: 'X-AstraSync-Trust-Score',\n agentId: 'X-AstraSync-Agent-Id',\n developerId: 'X-AstraSync-Developer-Id',\n permissions: 'X-AstraSync-Permissions',\n observedDecision: 'X-AstraSync-Observed-Decision',\n} as const;\n\n/**\n * Apply the outcome. Always strips inbound spoofed `x-astrasync-*` headers\n * first (both modes — trust headers must only ever originate here).\n *\n * Observe mode: returns the request untouched apart from header hygiene and\n * an `X-AstraSync-Observed-Decision` stamp for origin-side log correlation.\n *\n * Enforce mode: ALLOW → request + ASAT headers; DENY → 403 machine-readable\n * body; MANUAL_REVIEW → 202 with step-up poll info.\n */\nexport function applyOutcome(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n outcome: TierOutcome,\n policy: EffectivePolicy\n): CloudFrontRequestResult {\n stripHeadersByPrefix(request, 'x-astrasync-');\n\n if (policy.mode !== 'enforce') {\n // Shadow stamp: what enforce WOULD have done, visible in origin logs.\n if (outcome.decision !== 'allow') {\n setHeader(request, ASAT_HEADERS.observedDecision, outcome.decision);\n }\n injectAsat(request, outcome);\n return request;\n }\n\n switch (outcome.decision) {\n case 'deny':\n return jsonResponse(403, buildDenyBody(outcome, options.apiBaseUrl));\n case 'manual_review':\n return jsonResponse(202, buildManualReviewBody(outcome), {\n 'Retry-After': '30',\n });\n default:\n injectAsat(request, outcome);\n return request;\n }\n}\n\nfunction injectAsat(request: CloudFrontRequest, outcome: TierOutcome): void {\n if (!outcome.asat) return;\n const { trustScore, agentId, developerId, accessLevel } = outcome.asat;\n if (trustScore !== undefined) {\n setHeader(request, ASAT_HEADERS.trustScore, String(trustScore));\n }\n if (agentId) setHeader(request, ASAT_HEADERS.agentId, agentId);\n if (developerId) setHeader(request, ASAT_HEADERS.developerId, developerId);\n if (accessLevel) setHeader(request, ASAT_HEADERS.permissions, accessLevel);\n}\n","/**\n * Commerce Shield edge shell — Lambda@Edge origin-request handler factory\n * (§7.4 / §33.5 #1).\n *\n * Composition per request:\n * config (cached) → path policy → classify → tier pipeline → apply outcome\n *\n * THE invariant (tested): outside enforce mode the handler ALWAYS returns\n * the origin-bound request — any error, timeout, or misconfiguration\n * results in pass-through. A top-level catch guarantees it even against\n * bugs in the shell itself.\n */\n\nimport type { CloudFrontRequestEvent, CloudFrontRequestResult } from 'aws-lambda';\nimport { getRequest, getHeader, normalizeOriginHost } from './cf';\nimport { resolveApiKey, loadEdgeConfig } from './config';\nimport { classify, resolvePolicy } from './classify';\nimport { runTier } from './pipeline';\nimport { applyOutcome } from './enforce';\nimport type { EdgeAdapterOptions } from './types';\n\nexport type EdgeHandler = (event: CloudFrontRequestEvent) => Promise<CloudFrontRequestResult>;\n\nexport function createEdgeHandler(options: EdgeAdapterOptions): EdgeHandler {\n const log =\n options.log ??\n ((level, message, data) => {\n // Lambda@Edge writes console output to the regional CloudWatch log\n // group of whichever edge location served the request.\n console[level === 'info' ? 'log' : level](`[astrasync-edge] ${message}`, data ?? '');\n });\n\n return async function handler(event) {\n const request = getRequest(event);\n try {\n // Own the Host rewrite (Workstream D): the CloudFront-Viewer-* capture\n // requires an origin-request policy that also forwards the viewer Host,\n // so the shell restores origin-domain Host + X-Forwarded-Host itself.\n // Runs first so EVERY origin-bound return (skip / human / allow) is\n // correctly routed.\n normalizeOriginHost(request);\n\n const apiKey = await resolveApiKey({ ...options, log });\n const config = await loadEdgeConfig(options, apiKey);\n const policy = resolvePolicy(config, request.uri);\n\n // Skipped paths (static assets / skip rules): untouched, zero work.\n if (policy.skip) return request;\n\n const host =\n getHeader(request, 'x-forwarded-host') ??\n getHeader(request, 'host') ??\n new URL(options.counterpartyUrl).host;\n\n const classification = classify(request, host, policy.depth);\n\n // Humans: get out of the way. No calls, no logs, no header changes\n // beyond nothing at all.\n if (classification.tier === 'human') return request;\n\n const outcome = await runTier(\n { ...options, log },\n request,\n classification,\n policy,\n apiKey,\n config.sampling\n );\n\n if (outcome.decision !== 'allow') {\n log(\n 'info',\n policy.mode === 'enforce'\n ? `${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`\n : `[OBSERVE] would have been ${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`,\n { tier: outcome.tier, protocol: outcome.protocol, reasons: outcome.reasons }\n );\n }\n\n return applyOutcome(options, request, outcome, policy);\n } catch (err) {\n // Fail-open, unconditionally: the shell must never take the site down.\n log('error', 'edge handler error — passing request through', {\n error: err instanceof Error ? err.message : String(err),\n });\n return request;\n }\n };\n}\n"],"mappings":"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","names":["import_edge_config","import_metadata_capture","import_verify","import_verify","outcome"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cf.ts","../src/config.ts","../src/classify.ts","../src/detect.ts","../src/pipeline.ts","../src/events.ts","../src/messaging.ts","../src/enforce.ts","../src/handler.ts"],"sourcesContent":["/**\n * @astrasyncai/adapter-lambda — Commerce Shield edge adapter (spec §7.4,\n * backlog §33.5 #1).\n *\n * Library surface: `createEdgeHandler(options)` builds a Lambda@Edge\n * origin-request handler. The deployable single-file bundle lives at\n * `dist/lambda/index.js` (see `src/lambda-entry.ts` + `infra/`).\n */\n\nexport { createEdgeHandler, type EdgeHandler } from './handler';\nexport { classify, resolvePolicy } from './classify';\nexport { detectCommerce, type DetectedCommerce } from './detect';\nexport { runTier } from './pipeline';\nexport { applyOutcome, ASAT_HEADERS } from './enforce';\nexport { buildDenyBody, buildManualReviewBody } from './messaging';\nexport { emitBeacon, withBudget, sampled } from './events';\nexport { resolveApiKey, loadEdgeConfig, _resetConfigCaches } from './config';\nexport {\n getRequest,\n getHeader,\n flattenHeaders,\n decodeBody,\n requestUrl,\n setHeader,\n stripHeadersByPrefix,\n jsonResponse,\n} from './cf';\nexport type {\n EdgeAdapterOptions,\n Classification,\n TrafficTier,\n TierOutcome,\n EdgeDecision,\n EffectivePolicy,\n} from './types';\n","/**\n * CloudFront origin-request event helpers. The Lambda@Edge event shape puts\n * headers in `{ key, value }[]` arrays keyed by LOWERCASED header name, and\n * (with IncludeBody) the body arrives base64-encoded with an\n * `inputTruncated` flag when it exceeded CloudFront's ~1MB exposure cap.\n */\n\nimport type {\n CloudFrontRequest,\n CloudFrontRequestEvent,\n CloudFrontHeaders,\n CloudFrontResultResponse,\n} from 'aws-lambda';\nimport {\n sanitizeHeaders,\n type ObservedMetadata,\n} from '@astrasyncai/verification-gateway/metadata-capture';\n\nexport function getRequest(event: CloudFrontRequestEvent): CloudFrontRequest {\n return event.Records[0].cf.request;\n}\n\n/** First value of a header (lowercase name), or undefined. */\nexport function getHeader(request: CloudFrontRequest, name: string): string | undefined {\n return request.headers[name.toLowerCase()]?.[0]?.value;\n}\n\n/**\n * Flatten CloudFront headers into the `Record<string, string | string[]>`\n * shape the SDK extractors and verify-access artifacts expect.\n */\nexport function flattenHeaders(headers: CloudFrontHeaders): Record<string, string | string[]> {\n const out: Record<string, string | string[]> = {};\n for (const [name, entries] of Object.entries(headers)) {\n if (!entries?.length) continue;\n out[name] = entries.length === 1 ? entries[0].value : entries.map((e) => e.value);\n }\n return out;\n}\n\nexport interface DecodedBody {\n /** UTF-8 body text, undefined when there is no body. */\n text?: string;\n /** True when CloudFront truncated the body before handing it to the trigger. */\n truncated: boolean;\n}\n\nexport function decodeBody(request: CloudFrontRequest): DecodedBody {\n const body = request.body;\n if (!body?.data) return { truncated: false };\n const text =\n body.encoding === 'base64' ? Buffer.from(body.data, 'base64').toString('utf8') : body.data;\n return { text, truncated: body.inputTruncated === true };\n}\n\n/**\n * Workstream D — connection-layer signals the edge can see but the SDK cannot.\n * CloudFront injects the `CloudFront-Viewer-*` header family (IP, ASN, country,\n * TLS version/cipher, HTTP version, device class) when the OriginRequestPolicy\n * whitelists them (see infra/template.yaml). Absent values are simply omitted —\n * a partial connection block is fine.\n */\nexport function collectConnectionMetadata(request: CloudFrontRequest): Record<string, string> {\n const out: Record<string, string> = {};\n const put = (key: string, headerName: string, transform?: (v: string) => string) => {\n const v = getHeader(request, headerName);\n if (v) out[key] = transform ? transform(v) : v;\n };\n // `cloudfront-viewer-address` is `ip:port` (IPv6 keeps its brackets); take the\n // address portion the same way the beacon/pipeline already do.\n const addr = getHeader(request, 'cloudfront-viewer-address');\n if (addr) out.ip = addr.replace(/:\\d+$/, '');\n put('country', 'cloudfront-viewer-country');\n put('countryName', 'cloudfront-viewer-country-name');\n put('region', 'cloudfront-viewer-country-region');\n put('city', 'cloudfront-viewer-city');\n put('asn', 'cloudfront-viewer-asn');\n put('tlsVersion', 'cloudfront-viewer-tls');\n put('httpVersion', 'cloudfront-viewer-http-version');\n // Device-class booleans → a single compact device string.\n const devices: string[] = [];\n for (const [label, header] of [\n ['desktop', 'cloudfront-is-desktop-viewer'],\n ['mobile', 'cloudfront-is-mobile-viewer'],\n ['tablet', 'cloudfront-is-tablet-viewer'],\n ['smarttv', 'cloudfront-is-smarttv-viewer'],\n ] as const) {\n if (getHeader(request, header) === 'true') devices.push(label);\n }\n if (devices.length) out.device = devices.join(',');\n return out;\n}\n\n/**\n * Workstream D — the FULL sanitised metadata capture for one request: every\n * inbound header (secrets stripped, credential headers reduced to a safe format\n * prefix) plus the connection-layer block. The edge is the richest capture\n * point — the header arrays are already in memory — and this is pure string\n * work, so it adds no page latency. Forwarded on both the verify-access call\n * and the beacon.\n */\nexport function buildObservedMetadata(request: CloudFrontRequest): ObservedMetadata {\n const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(\n flattenHeaders(request.headers)\n );\n const connection = collectConnectionMetadata(request);\n return {\n headers,\n ...(apiKeyFormat && { apiKeyFormat }),\n ...(platformHeaders && { platformHeaders }),\n ...(Object.keys(connection).length > 0 && { connection }),\n };\n}\n\n/**\n * Workstream D — normalize the origin-bound `Host` header.\n *\n * To receive the `CloudFront-Viewer-*` connection headers (IP/ASN/TLS/country)\n * we must move off the managed `AllViewerExceptHostHeader` origin-request policy\n * onto one that whitelists those headers — but every such policy ALSO forwards\n * the viewer `Host`, which would break vhost / PaaS origin routing that expects\n * the origin's own hostname. So the Lambda takes ownership of the Host rewrite:\n * stash the public (viewer) host into `X-Forwarded-Host` for downstream use and\n * detection, then set `Host` to the origin's domain (available on the event as\n * `request.origin.custom.domainName`). No-ops when the origin domain is absent\n * (synthetic test events) or already matches — so it is safe on every path,\n * including static-asset pass-through.\n */\nexport function normalizeOriginHost(request: CloudFrontRequest): void {\n const originDomain =\n request.origin?.custom?.domainName ?? request.origin?.s3?.domainName ?? undefined;\n if (!originDomain) return;\n const currentHost = getHeader(request, 'host');\n if (!currentHost || currentHost === originDomain) return;\n if (!getHeader(request, 'x-forwarded-host')) {\n setHeader(request, 'X-Forwarded-Host', currentHost);\n }\n setHeader(request, 'Host', originDomain);\n}\n\n/** Full request URL as the origin will see it (scheme fixed to https). */\nexport function requestUrl(request: CloudFrontRequest, host: string): string {\n const qs = request.querystring ? `?${request.querystring}` : '';\n return `https://${host}${request.uri}${qs}`;\n}\n\n/**\n * Set a header on the origin-bound request (overwrites all prior values).\n */\nexport function setHeader(request: CloudFrontRequest, name: string, value: string): void {\n request.headers[name.toLowerCase()] = [{ key: name, value }];\n}\n\n/**\n * Strip every inbound header matching a prefix (lowercase compare). Used to\n * drop spoofed `x-astrasync-*` trust headers before the shell injects its\n * own — in BOTH modes, so a caller can never smuggle trust past the origin.\n */\nexport function stripHeadersByPrefix(request: CloudFrontRequest, prefix: string): void {\n const p = prefix.toLowerCase();\n for (const name of Object.keys(request.headers)) {\n if (name.startsWith(p)) delete request.headers[name];\n }\n}\n\nexport function jsonResponse(\n status: number,\n body: unknown,\n extraHeaders?: Record<string, string>\n): CloudFrontResultResponse {\n const headers: CloudFrontResultResponse['headers'] = {\n 'content-type': [{ key: 'Content-Type', value: 'application/json' }],\n };\n for (const [name, value] of Object.entries(extraHeaders ?? {})) {\n headers[name.toLowerCase()] = [{ key: name, value }];\n }\n return {\n status: String(status),\n statusDescription: status === 403 ? 'Forbidden' : status === 202 ? 'Accepted' : 'OK',\n headers,\n body: JSON.stringify(body),\n };\n}\n","/**\n * Runtime configuration for the edge shell.\n *\n * Lambda@Edge forbids environment variables, so configuration is layered:\n * 1. Build-time constants baked into the bundle (apiBaseUrl,\n * counterpartyId, counterpartyUrl, apiKeySecretName) — see\n * `tsup.config.ts` define block and `infra/deploy.sh`.\n * 2. The merchant API key from AWS Secrets Manager (us-east-1), fetched\n * lazily once per container and cached with a 15-minute TTL so\n * rotation needs no redeploy. Observe mode works fully without it —\n * the beacon endpoint is unauthenticated and verify() degrades\n * keyless — so a Secrets Manager outage can never take the shell down.\n * 3. The dashboard EdgeConfig via the SDK's getEdgeConfig (60s TTL,\n * stale-while-revalidate, enforce→observe degradation after 24h\n * staleness, DEFAULT_EDGE_CONFIG fallback — all in the SDK).\n */\n\nimport {\n getEdgeConfig,\n DEFAULT_EDGE_CONFIG,\n type EdgeConfig,\n} from '@astrasyncai/verification-gateway/edge-config';\nimport type { EdgeAdapterOptions } from './types';\n\nconst SECRET_TTL_MS = 15 * 60 * 1000;\n\ninterface SecretCacheEntry {\n value: string | undefined;\n fetchedAt: number;\n}\n\nconst secretCache = new Map<string, SecretCacheEntry>();\n\nasync function defaultFetchSecret(secretName: string): Promise<string | undefined> {\n // Lazy import so tests (and the library build) never touch the AWS SDK\n // unless a secret name is actually configured.\n const { SecretsManagerClient, GetSecretValueCommand } =\n await import('@aws-sdk/client-secrets-manager');\n // Lambda@Edge replicates globally but secrets live in us-east-1 (the\n // Lambda@Edge home region).\n const client = new SecretsManagerClient({ region: 'us-east-1' });\n const result = await client.send(new GetSecretValueCommand({ SecretId: secretName }));\n return result.SecretString ?? undefined;\n}\n\n/**\n * Resolve the merchant API key. Never throws — a missing/unreachable secret\n * degrades to keyless operation (observe mode is fully functional without\n * it; enforce mode without a key cannot fetch a config that enforces, so it\n * degrades to observe by construction).\n */\nexport async function resolveApiKey(options: EdgeAdapterOptions): Promise<string | undefined> {\n if (options.apiKey) return options.apiKey;\n const secretName = options.apiKeySecretName;\n if (!secretName) return undefined;\n\n const cached = secretCache.get(secretName);\n if (cached && Date.now() - cached.fetchedAt < SECRET_TTL_MS) return cached.value;\n\n try {\n const fetcher = options.fetchSecret ?? defaultFetchSecret;\n const value = await fetcher(secretName);\n secretCache.set(secretName, { value, fetchedAt: Date.now() });\n return value;\n } catch (err) {\n options.log?.('warn', 'Secrets Manager fetch failed — continuing keyless', {\n secretName,\n error: err instanceof Error ? err.message : String(err),\n });\n // Serve a stale value if we ever had one; otherwise keyless.\n return cached?.value;\n }\n}\n\n/**\n * Load the effective EdgeConfig. Delegates caching/fallback/degradation to\n * the SDK; adds the compile-time fallback override and never throws.\n */\nexport async function loadEdgeConfig(\n options: EdgeAdapterOptions,\n apiKey: string | undefined\n): Promise<EdgeConfig> {\n try {\n return await getEdgeConfig({ apiBaseUrl: options.apiBaseUrl, apiKey }, options.counterpartyId, {\n ttlMs: options.configTtlMs,\n });\n } catch {\n return options.fallbackConfig ?? DEFAULT_EDGE_CONFIG;\n }\n}\n\n/** Reset module caches — tests only. */\nexport function _resetConfigCaches(): void {\n secretCache.clear();\n}\n","/**\n * Three-tier traffic classification (§33.5 #1: verified /\n * identified-but-unregistered / anonymous) plus the two non-tiers the shell\n * touches as little as possible: `human` (zero network calls, zero logging)\n * and `skipped` (static assets / excluded paths).\n *\n * Cheapest checks first — the human path must add microseconds, not\n * milliseconds. Platform signatures come from the SDK so the edge and the\n * backend's verify-access anonymous handler classify identically.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { detectPlatformFingerprint } from '@astrasyncai/verification-gateway/platform-signatures';\nimport { matchEdgePathRule, type EdgeConfig } from '@astrasyncai/verification-gateway/edge-config';\nimport { sanitizeHeaders } from '@astrasyncai/verification-gateway/metadata-capture';\nimport { getHeader, decodeBody, flattenHeaders } from './cf';\nimport { detectCommerce } from './detect';\nimport type { Classification, EffectivePolicy } from './types';\n\n/** Extensions the shell 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/** 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 * 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 decode, no header sniffing\n * beyond UA) — that is the zero-friction setting.\n */\nexport function classify(\n request: CloudFrontRequest,\n host: string,\n depth: 'classify' | 'authenticate' | 'authorize'\n): Classification {\n const userAgent = getHeader(request, 'user-agent') ?? '';\n const flat = flattenHeaders(request.headers);\n\n // 1. Native AstraSync credentials.\n const credentials = extractCredentials(flat, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { tier: 'verified', protocol: 'x-astra' };\n }\n\n // Workstream D — the key-format prefix + platform-signal headers are stronger,\n // less-spoofable platform signals than the UA. Compute once (cheap string\n // work) and feed every fingerprint call below.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(flat);\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(request, host, decodeBody(request));\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 (!getHeader(request, 'sec-fetch-mode') && !getHeader(request, 'accept-language')) {\n return { tier: 'anonymous-bot', evidence: { userAgent, spoofedBrowser: true } };\n }\n\n // 5. Human traffic — the shell 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 };\n","/**\n * Crypto-free commerce-protocol detection (§7.4.2 detection order).\n *\n * The edge only SNIFFS — header shapes, compact-JWT patterns, body field\n * names — and packages what it saw as raw `CommerceArtifactsPayload` for\n * verify-access, whose Step 0.5 pipeline does the authoritative parsing and\n * cryptographic verification server-side. Nothing here imports jose/sd-jwt/\n * signature libraries: detection must stay cheap enough to run on every\n * non-human request, and verification must happen exactly once, in the\n * canonical sink, where it is recorded.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport type { CommerceArtifactsPayload } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, requestUrl, type DecodedBody } from './cf';\n\nexport interface DetectedCommerce {\n /** Detection-order label: rfc9421-agent-pay | rfc9421-tap | rfc9421-web-bot-auth | vi-sd-jwt | ap2 | acp | ucp | mpp | x402 */\n protocol: string;\n artifacts: CommerceArtifactsPayload;\n /** Light detection detail for beacons/audit — never secrets or full credentials. */\n evidence: Record<string, unknown>;\n}\n\n/** Compact SD-JWT: JWT + `~`-separated disclosures. */\nconst SD_JWT_PATTERN = /^eyJ[\\w-]+\\.[\\w-]*\\.[\\w-]+~/;\n\n/** Decode a JWT header segment without verifying anything. */\nfunction sniffJwtHeader(compact: string): Record<string, unknown> | undefined {\n try {\n const seg = compact.split('.')[0];\n return JSON.parse(Buffer.from(seg, 'base64url').toString('utf8')) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonBody(body: DecodedBody): Record<string, unknown> | undefined {\n if (!body.text) return undefined;\n try {\n const parsed: unknown = JSON.parse(body.text);\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * §7.4.2 order (after the X-Astra native check, which classify.ts owns):\n * SD-JWT/VI → RFC 9421 (Agent Pay / TAP / Web Bot Auth by kid namespace or\n * Signature-Agent) → ACP HMAC → UCP session → AP2 body triple → MPP → x402.\n * Returns undefined when nothing commerce-shaped is on the wire.\n *\n * When the body was truncated by CloudFront (`inputTruncated`), body-bound\n * artifacts still forward what arrived but carry a `bodyTruncated` evidence\n * flag — the backend downgrades those signatures rather than hard-failing.\n */\nexport function detectCommerce(\n request: CloudFrontRequest,\n host: string,\n body: DecodedBody\n): DetectedCommerce | undefined {\n const url = requestUrl(request, host);\n const method = request.method;\n const headers = flattenHeaders(request.headers);\n const jsonBody = parseJsonBody(body);\n const truncated = body.truncated ? { bodyTruncated: true } : {};\n\n // --- VI / SD-JWT credential in a header ------------------------------\n const authHeader = getHeader(request, 'authorization');\n const bearer = authHeader?.replace(/^Bearer\\s+/i, '');\n const mandateHeader =\n getHeader(request, 'x-payment-mandate') ?? getHeader(request, 'payment-mandate');\n const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));\n if (sdJwtCandidate) {\n const typ = sniffJwtHeader(sdJwtCandidate)?.typ;\n return {\n protocol: 'vi-sd-jwt',\n artifacts: { viSdJwt: sdJwtCandidate },\n evidence: { typ, ...truncated },\n };\n }\n\n // --- RFC 9421 (Agent Pay / TAP / Web Bot Auth) ------------------------\n const signature = getHeader(request, 'signature');\n const signatureInput = getHeader(request, 'signature-input');\n if (signature && signatureInput) {\n const signatureAgent = getHeader(request, 'signature-agent');\n const registryHint = getHeader(request, 'x-agent-registry');\n const lowerInput = signatureInput.toLowerCase();\n const protocol = signatureAgent\n ? 'rfc9421-web-bot-auth'\n : registryHint?.toLowerCase().includes('visa') || lowerInput.includes('visa')\n ? 'rfc9421-tap'\n : registryHint?.toLowerCase().includes('mastercard') || lowerInput.includes('mastercard')\n ? 'rfc9421-agent-pay'\n : 'rfc9421';\n return {\n protocol,\n artifacts: {\n rfc9421: { headers, method, url, ...(body.text && { body: body.text }) },\n },\n evidence: {\n ...(signatureAgent && { signatureAgent }),\n ...(registryHint && { registryHint }),\n keyid: signatureInput.match(/keyid=\"([^\"]+)\"/)?.[1],\n ...truncated,\n },\n };\n }\n\n // --- ACP (HMAC-signed webhook/checkout: signature WITHOUT signature-input)\n const acpTimestamp = getHeader(request, 'timestamp');\n if (signature && !signatureInput && (acpTimestamp || getHeader(request, 'idempotency-key'))) {\n return {\n protocol: 'acp',\n artifacts: {\n acpRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated },\n };\n }\n\n // --- UCP checkout session ---------------------------------------------\n if (/\\/checkout[-_]sessions(\\/|$)/.test(request.uri)) {\n return {\n protocol: 'ucp',\n artifacts: { ucpRequest: { method, url, ...(jsonBody && { body: jsonBody }) } },\n evidence: { path: request.uri, ...truncated },\n };\n }\n\n // --- AP2 mandate triple in the body -----------------------------------\n if (jsonBody) {\n const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;\n const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;\n const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;\n if (typeof intent === 'string' || typeof cart === 'string' || typeof payment === 'string') {\n return {\n protocol: 'ap2',\n artifacts: {\n ap2Mandates: {\n ...(typeof intent === 'string' && { intent }),\n ...(typeof cart === 'string' && { cart }),\n ...(typeof payment === 'string' && { payment }),\n },\n },\n evidence: {\n mandatesPresent: [\n typeof intent === 'string' && 'intent',\n typeof cart === 'string' && 'cart',\n typeof payment === 'string' && 'payment',\n ].filter(Boolean),\n ...truncated,\n },\n };\n }\n }\n\n // --- MPP (`Authorization: Payment <credential>`) -----------------------\n if (authHeader && /^Payment\\s+/i.test(authHeader)) {\n return {\n protocol: 'mpp',\n artifacts: {\n mppRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: truncated,\n };\n }\n\n // --- x402 (X-PAYMENT header) ------------------------------------------\n if (getHeader(request, 'x-payment')) {\n return {\n protocol: 'x402',\n artifacts: {\n x402Request: { method, url, headers, ...(jsonBody && { body: jsonBody }) },\n },\n evidence: truncated,\n };\n }\n\n return undefined;\n}\n","/**\n * Depth-controlled verification per tier. The edge never verifies\n * credentials itself — it forwards what it detected to verify-access, the\n * canonical sole verification sink (backend Step 0.5 runs the commerce\n * pipeline, records events, provisions orphans, persists sessions). What\n * the depth setting controls is how much the edge LOOKS and how much it\n * FORWARDS:\n *\n * classify — what is it? UA tiers only. Zero verify-access calls;\n * beacons only.\n * authenticate — who is it? + protocol detection. X-Astra agents get a\n * verify-access identity check; commerce/platform traffic\n * is beaconed with protocol + evidence (no signature\n * verification anywhere).\n * authorize — are they allowed? + artifact forwarding. X-Astra verify\n * calls carry commerceArtifacts; identified traffic gets an\n * anonymous verify-access call with artifacts +\n * callerMetadata so the backend cryptographically proves\n * and policy-evaluates once.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { verify, extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { resolveHttpPdlss } from '@astrasyncai/verification-gateway/http-pdlss';\nimport type { GatewayConfig, VerificationRequest } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, buildObservedMetadata } from './cf';\nimport { withBudget, emitBeacon, sampled } from './events';\nimport type { Classification, EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\nfunction baseOutcome(classification: Classification): TierOutcome {\n return {\n tier: classification.tier,\n decision: 'allow',\n reasons: [],\n protocol: classification.protocol,\n };\n}\n\nfunction buildVerificationRequest(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n includeArtifacts: boolean\n): VerificationRequest {\n const headers = flattenHeaders(request.headers);\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n // verify-access REQUIRES a purpose. Resolve via the shared §4.6 chain:\n // the agent's X-Astra-Purpose/-Action declarations, else the pinned\n // method table (GET → data/data.read etc.) — a transport verb never\n // travels as a PDLSS action.\n const pdlss = resolveHttpPdlss({\n method: request.method,\n astraPurpose: getHeader(request, 'x-astra-purpose'),\n astraAction: getHeader(request, 'x-astra-action'),\n });\n // Trust Record (§33.5 #3): forward the caller's attempt-chain handle when\n // well-formed (agent-declared, like x-astra-purpose — not a trust header,\n // so no spoof-strip needed). The edge synthesises NO consideration data —\n // it can't see offer semantics; pure pass-through.\n const attemptId = getHeader(request, 'x-astra-attempt-id');\n return {\n ...(attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId }),\n credentials: extractCredentials(headers, {}),\n purpose: pdlss.purpose,\n action: pdlss.action,\n resource: request.uri,\n createSession: true,\n counterpartyType: 'website',\n counterpartyUrl: options.counterpartyUrl,\n callerMetadata: {\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n referer: getHeader(request, 'referer'),\n host: getHeader(request, 'host'),\n // Workstream D — the full sanitised header + connection capture. The\n // backend stores it fire-and-forget (zero decision latency) and uses the\n // key-format / platform headers for attribution.\n observedMetadata: buildObservedMetadata(request),\n },\n ...(includeArtifacts &&\n classification.artifacts && { commerceArtifacts: classification.artifacts }),\n };\n}\n\nfunction outcomeFromVerifyResult(\n classification: Classification,\n result: Awaited<ReturnType<typeof verify>>\n): TierOutcome {\n const outcome = baseOutcome(classification);\n outcome.sessionId = (result as { sessionId?: string }).sessionId;\n outcome.correlationId = result.correlationId;\n outcome.guidance = result.guidance;\n\n if (result.requiresStepUp || result.stepUpApproval) {\n outcome.decision = 'manual_review';\n outcome.reasons = ['step-up approval required'];\n outcome.stepUp = {\n pollUrl: (result.stepUpApproval as { pollUrl?: string } | undefined)?.pollUrl,\n expiresAt: (result.stepUpApproval as { expiresAt?: string } | undefined)?.expiresAt,\n };\n return outcome;\n }\n\n if (!result.identityVerified || !result.policyAllowed) {\n outcome.decision = 'deny';\n outcome.reasons = result.denialReasons?.length\n ? result.denialReasons\n : [!result.identityVerified ? 'identity not verified' : 'denied by access policy'];\n return outcome;\n }\n\n outcome.asat = {\n trustScore: result.agent?.trustScore,\n agentId: result.agent?.astraId,\n developerId: result.developer?.astradId,\n accessLevel: result.accessLevel,\n };\n return outcome;\n}\n\n/**\n * Run the tier-appropriate verification/telemetry for one classified\n * request. NEVER throws; on any failure returns an `allow` outcome with the\n * failure recorded in `reasons` (infra failures fail open — a presented\n * credential the BACKEND rejected is a deny, but an unreachable backend is\n * not a rejection).\n */\nexport async function runTier(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n policy: EffectivePolicy,\n apiKey: string | undefined,\n sampling: { anonymousBeaconRate: number }\n): Promise<TierOutcome> {\n const budgets = options.budgets ?? {};\n const beaconMs = budgets.beaconMs ?? 300;\n const verifyMs =\n policy.mode === 'enforce'\n ? (budgets.verifyEnforceMs ?? 3000)\n : (budgets.verifyObserveMs ?? 1500);\n\n const gatewayConfig: GatewayConfig = {\n apiBaseUrl: options.apiBaseUrl,\n ...(apiKey && { apiKey }),\n counterpartyId: options.counterpartyId,\n // The shell handles its own error semantics; init self-probes don't\n // belong in a per-request edge function.\n disableInitChecks: true,\n } as GatewayConfig;\n\n try {\n switch (classification.tier) {\n case 'verified': {\n // classify depth = zero API calls, even for credentialed agents.\n if (policy.depth === 'classify') {\n return baseOutcome(classification);\n }\n const result = await withBudget(\n verify(\n gatewayConfig,\n buildVerificationRequest(options, request, classification, policy.depth === 'authorize')\n ),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n\n case 'identified': {\n if (policy.depth === 'authorize' && classification.artifacts) {\n // Anonymous verify-access call WITH artifacts: the backend runs\n // the commerce pipeline, records unverified events, and\n // provisions orphan platform agents — one sink, recorded once.\n const result = await withBudget(\n verify(gatewayConfig, buildVerificationRequest(options, request, classification, true)),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n // classify/credentials depth (or no artifacts): lightweight beacon.\n await emitBeacon(options, request, classification, beaconMs);\n const outcome = baseOutcome(classification);\n if (policy.mode === 'enforce' && policy.depth !== 'classify') {\n // Unregistered agent on an enforced path: deny with guidance.\n outcome.decision = 'deny';\n outcome.reasons = ['agent is not registered with AstraSync'];\n }\n return outcome;\n }\n\n case 'anonymous-bot': {\n if (sampled(sampling.anonymousBeaconRate, options.random)) {\n await emitBeacon(\n options,\n request,\n { ...classification, protocol: classification.protocol ?? 'ua-heuristic' },\n beaconMs\n );\n }\n // Anonymous bots pass through even in enforce mode — enforce gates\n // AGENT traffic; generic bot management stays the CDN/WAF's job\n // (mixed-traffic classification §5.1.7 is the enforce-mode\n // prerequisite tracked as §33.5 #9).\n return baseOutcome(classification);\n }\n\n default:\n return baseOutcome(classification);\n }\n } catch (err) {\n const outcome = baseOutcome(classification);\n outcome.reasons = [\n `edge pipeline error — fail-open: ${err instanceof Error ? err.message : String(err)}`,\n ];\n return outcome;\n }\n}\n","/**\n * Time-budgeted event emission.\n *\n * Lambda@Edge has no `waitUntil` — anything not awaited before the handler\n * returns may never run (the container freezes). So every network call is\n * awaited under an explicit budget and DROPPED on timeout: latency to the\n * customer's traffic is bounded, and a slow AstraSync API costs telemetry,\n * never page loads.\n */\n\nimport { reportUnregisteredAttempt } from '@astrasyncai/verification-gateway/verify';\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { getHeader, buildObservedMetadata } from './cf';\nimport type { Classification, EdgeAdapterOptions } 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\n * (CSRF-exempt on the backend); the backend fingerprints the UA and\n * find-or-provisions orphan platform agents server-side.\n */\nexport async function emitBeacon(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n budgetMs: number\n): Promise<void> {\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n await withBudget(\n reportUnregisteredAttempt(\n { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },\n {\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: 'website',\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n requestPath: request.uri,\n requestMethod: request.method,\n // 3.9.0 evidence fields (backend persists them into eventData).\n protocol: classification.protocol,\n evidence: classification.evidence,\n // Workstream D — full sanitised header + connection capture for the\n // unregistered caller (fire-and-forget, so free).\n observedMetadata: buildObservedMetadata(request),\n }\n ),\n budgetMs\n );\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 * §7.4.6 — protocol-specific machine-readable messaging for enforce-mode\n * responses. Agents (not humans) consume these bodies: stable error codes,\n * the failure list, and registration guidance with real URLs.\n */\n\nimport type { TierOutcome } from './types';\n\nconst PROTOCOL_MESSAGES: Record<string, string> = {\n 'vi-sd-jwt':\n 'This request presented Visa Intelligent Commerce credentials, but the agent is not verified with AstraSync. Register the agent to pair your VI credentials with a verified identity and mandate.',\n 'rfc9421-agent-pay':\n 'This request carried a Mastercard Agent Pay signature, but the agent is not verified with AstraSync. Register the agent to pair Agent Pay credentials with a verified identity and mandate.',\n 'rfc9421-tap':\n 'This request carried a Visa TAP signature, but the agent is not verified with AstraSync. Register the agent to pair TAP credentials with a verified identity and mandate.',\n 'rfc9421-web-bot-auth':\n 'This request carried a Web Bot Auth signature, but the agent is not verified with AstraSync. Register the agent to link your signed-agent identity to a verified principal.',\n rfc9421:\n 'This request carried an RFC 9421 HTTP message signature, but the agent is not verified with AstraSync. Register the agent to link the signing identity to a verified principal.',\n acp: 'This request used the Agentic Commerce Protocol, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ucp: 'This request used a UCP checkout session, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ap2: 'This request presented AP2 mandates, but the agent is not verified with AstraSync. Register the agent to pair your mandates with a verified identity.',\n mpp: 'This request presented MPP payment credentials, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n x402: 'This request used x402 payment headers, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n 'platform-ua':\n 'This traffic was identified as a platform AI agent without AstraSync credentials. Register the agent to access this property with a verified identity.',\n 'x-astra':\n 'The presented AstraSync credentials failed verification or were denied by this property’s access policy.',\n};\n\nexport interface DenyBody {\n success: false;\n error: {\n code: 'UNAUTHORIZED' | 'INSUFFICIENT_ACCESS';\n message: string;\n protocol?: string;\n failures: string[];\n correlationId?: string;\n guidance: {\n message?: string;\n registrationUrl?: string;\n documentationUrl?: string;\n };\n };\n}\n\nexport function buildDenyBody(outcome: TierOutcome, apiBaseUrl: string): DenyBody {\n const origin = apiBaseUrl.replace(/\\/api\\/?$/, '');\n const protocolMessage =\n (outcome.protocol && PROTOCOL_MESSAGES[outcome.protocol]) ??\n 'This request could not be verified by AstraSync.';\n return {\n success: false,\n error: {\n // UNAUTHORIZED = identity failed (register/re-authenticate helps);\n // INSUFFICIENT_ACCESS = identity fine, policy denied (fix the mandate).\n code: outcome.tier === 'verified' ? 'INSUFFICIENT_ACCESS' : 'UNAUTHORIZED',\n message: protocolMessage,\n ...(outcome.protocol && { protocol: outcome.protocol }),\n failures: outcome.reasons,\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n guidance: {\n // `||` not `??`: verify() fills these with EMPTY STRINGS when the\n // well-known cache is cold — empty means \"use the fallback\".\n message:\n outcome.guidance?.message ||\n 'Register this agent with AstraSync to receive verifiable credentials.',\n registrationUrl: outcome.guidance?.registrationUrl || `${origin}/register`,\n documentationUrl: outcome.guidance?.documentationUrl || `${origin}/docs/edge-adapter`,\n },\n },\n };\n}\n\nexport interface ManualReviewBody {\n success: false;\n status: 'manual_review';\n message: string;\n stepUpApproval?: { pollUrl?: string; expiresAt?: string };\n correlationId?: string;\n}\n\nexport function buildManualReviewBody(outcome: TierOutcome): ManualReviewBody {\n return {\n success: false,\n status: 'manual_review',\n message:\n 'This action requires human approval. Poll the step-up approval endpoint and retry once approved.',\n ...(outcome.stepUp && { stepUpApproval: outcome.stepUp }),\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n };\n}\n","/**\n * Decision → CloudFront result wiring (§7.4 enforcement, §7.4.7 ASAT\n * headers). Executed in BOTH modes so observe mode records exactly what\n * enforce mode would have done — but only enforce mode is allowed to return\n * anything other than the origin-bound request.\n */\n\nimport type { CloudFrontRequest, CloudFrontRequestResult } from 'aws-lambda';\nimport { jsonResponse, setHeader, stripHeadersByPrefix } from './cf';\nimport { buildDenyBody, buildManualReviewBody } from './messaging';\nimport type { EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\n/** §7.4.7 ASAT trust-attestation headers injected on allowed requests. */\nexport const ASAT_HEADERS = {\n trustScore: 'X-AstraSync-Trust-Score',\n agentId: 'X-AstraSync-Agent-Id',\n developerId: 'X-AstraSync-Developer-Id',\n permissions: 'X-AstraSync-Permissions',\n observedDecision: 'X-AstraSync-Observed-Decision',\n} as const;\n\n/**\n * Apply the outcome. Always strips inbound spoofed `x-astrasync-*` headers\n * first (both modes — trust headers must only ever originate here).\n *\n * Observe mode: returns the request untouched apart from header hygiene and\n * an `X-AstraSync-Observed-Decision` stamp for origin-side log correlation.\n *\n * Enforce mode: ALLOW → request + ASAT headers; DENY → 403 machine-readable\n * body; MANUAL_REVIEW → 202 with step-up poll info.\n */\nexport function applyOutcome(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n outcome: TierOutcome,\n policy: EffectivePolicy\n): CloudFrontRequestResult {\n stripHeadersByPrefix(request, 'x-astrasync-');\n\n if (policy.mode !== 'enforce') {\n // Shadow stamp: what enforce WOULD have done, visible in origin logs.\n if (outcome.decision !== 'allow') {\n setHeader(request, ASAT_HEADERS.observedDecision, outcome.decision);\n }\n injectAsat(request, outcome);\n return request;\n }\n\n switch (outcome.decision) {\n case 'deny':\n return jsonResponse(403, buildDenyBody(outcome, options.apiBaseUrl));\n case 'manual_review':\n return jsonResponse(202, buildManualReviewBody(outcome), {\n 'Retry-After': '30',\n });\n default:\n injectAsat(request, outcome);\n return request;\n }\n}\n\nfunction injectAsat(request: CloudFrontRequest, outcome: TierOutcome): void {\n if (!outcome.asat) return;\n const { trustScore, agentId, developerId, accessLevel } = outcome.asat;\n if (trustScore !== undefined) {\n setHeader(request, ASAT_HEADERS.trustScore, String(trustScore));\n }\n if (agentId) setHeader(request, ASAT_HEADERS.agentId, agentId);\n if (developerId) setHeader(request, ASAT_HEADERS.developerId, developerId);\n if (accessLevel) setHeader(request, ASAT_HEADERS.permissions, accessLevel);\n}\n","/**\n * Commerce Shield edge shell — Lambda@Edge origin-request handler factory\n * (§7.4 / §33.5 #1).\n *\n * Composition per request:\n * config (cached) → path policy → classify → tier pipeline → apply outcome\n *\n * THE invariant (tested): outside enforce mode the handler ALWAYS returns\n * the origin-bound request — any error, timeout, or misconfiguration\n * results in pass-through. A top-level catch guarantees it even against\n * bugs in the shell itself.\n */\n\nimport type { CloudFrontRequestEvent, CloudFrontRequestResult } from 'aws-lambda';\nimport { getRequest, getHeader, normalizeOriginHost } from './cf';\nimport { resolveApiKey, loadEdgeConfig } from './config';\nimport { classify, resolvePolicy } from './classify';\nimport { runTier } from './pipeline';\nimport { applyOutcome } from './enforce';\nimport type { EdgeAdapterOptions } from './types';\n\nexport type EdgeHandler = (event: CloudFrontRequestEvent) => Promise<CloudFrontRequestResult>;\n\nexport function createEdgeHandler(options: EdgeAdapterOptions): EdgeHandler {\n const log =\n options.log ??\n ((level, message, data) => {\n // Lambda@Edge writes console output to the regional CloudWatch log\n // group of whichever edge location served the request.\n console[level === 'info' ? 'log' : level](`[astrasync-edge] ${message}`, data ?? '');\n });\n\n return async function handler(event) {\n const request = getRequest(event);\n try {\n // Own the Host rewrite (Workstream D): the CloudFront-Viewer-* capture\n // requires an origin-request policy that also forwards the viewer Host,\n // so the shell restores origin-domain Host + X-Forwarded-Host itself.\n // Runs first so EVERY origin-bound return (skip / human / allow) is\n // correctly routed.\n normalizeOriginHost(request);\n\n const apiKey = await resolveApiKey({ ...options, log });\n const config = await loadEdgeConfig(options, apiKey);\n const policy = resolvePolicy(config, request.uri);\n\n // Skipped paths (static assets / skip rules): untouched, zero work.\n if (policy.skip) return request;\n\n const host =\n getHeader(request, 'x-forwarded-host') ??\n getHeader(request, 'host') ??\n new URL(options.counterpartyUrl).host;\n\n const classification = classify(request, host, policy.depth);\n\n // Humans: get out of the way. No calls, no logs, no header changes\n // beyond nothing at all.\n if (classification.tier === 'human') return request;\n\n const outcome = await runTier(\n { ...options, log },\n request,\n classification,\n policy,\n apiKey,\n config.sampling\n );\n\n if (outcome.decision !== 'allow') {\n log(\n 'info',\n policy.mode === 'enforce'\n ? `${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`\n : `[OBSERVE] would have been ${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`,\n { tier: outcome.tier, protocol: outcome.protocol, reasons: outcome.reasons }\n );\n }\n\n return applyOutcome(options, request, outcome, policy);\n } catch (err) {\n // Fail-open, unconditionally: the shell must never take the site down.\n log('error', 'edge handler error — passing request through', {\n error: err instanceof Error ? err.message : String(err),\n });\n return request;\n }\n };\n}\n"],"mappings":"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","names":["import_edge_config","import_metadata_capture","import_verify","import_verify","outcome"]}
package/dist/index.mjs CHANGED
@@ -399,7 +399,9 @@ function buildVerificationRequest(options, request, classification, includeArtif
399
399
  astraPurpose: getHeader(request, "x-astra-purpose"),
400
400
  astraAction: getHeader(request, "x-astra-action")
401
401
  });
402
+ const attemptId = getHeader(request, "x-astra-attempt-id");
402
403
  return {
404
+ ...attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId },
403
405
  credentials: extractCredentials2(headers, {}),
404
406
  purpose: pdlss.purpose,
405
407
  action: pdlss.action,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cf.ts","../src/config.ts","../src/classify.ts","../src/detect.ts","../src/pipeline.ts","../src/events.ts","../src/messaging.ts","../src/enforce.ts","../src/handler.ts"],"sourcesContent":["/**\n * CloudFront origin-request event helpers. The Lambda@Edge event shape puts\n * headers in `{ key, value }[]` arrays keyed by LOWERCASED header name, and\n * (with IncludeBody) the body arrives base64-encoded with an\n * `inputTruncated` flag when it exceeded CloudFront's ~1MB exposure cap.\n */\n\nimport type {\n CloudFrontRequest,\n CloudFrontRequestEvent,\n CloudFrontHeaders,\n CloudFrontResultResponse,\n} from 'aws-lambda';\nimport {\n sanitizeHeaders,\n type ObservedMetadata,\n} from '@astrasyncai/verification-gateway/metadata-capture';\n\nexport function getRequest(event: CloudFrontRequestEvent): CloudFrontRequest {\n return event.Records[0].cf.request;\n}\n\n/** First value of a header (lowercase name), or undefined. */\nexport function getHeader(request: CloudFrontRequest, name: string): string | undefined {\n return request.headers[name.toLowerCase()]?.[0]?.value;\n}\n\n/**\n * Flatten CloudFront headers into the `Record<string, string | string[]>`\n * shape the SDK extractors and verify-access artifacts expect.\n */\nexport function flattenHeaders(headers: CloudFrontHeaders): Record<string, string | string[]> {\n const out: Record<string, string | string[]> = {};\n for (const [name, entries] of Object.entries(headers)) {\n if (!entries?.length) continue;\n out[name] = entries.length === 1 ? entries[0].value : entries.map((e) => e.value);\n }\n return out;\n}\n\nexport interface DecodedBody {\n /** UTF-8 body text, undefined when there is no body. */\n text?: string;\n /** True when CloudFront truncated the body before handing it to the trigger. */\n truncated: boolean;\n}\n\nexport function decodeBody(request: CloudFrontRequest): DecodedBody {\n const body = request.body;\n if (!body?.data) return { truncated: false };\n const text =\n body.encoding === 'base64' ? Buffer.from(body.data, 'base64').toString('utf8') : body.data;\n return { text, truncated: body.inputTruncated === true };\n}\n\n/**\n * Workstream D — connection-layer signals the edge can see but the SDK cannot.\n * CloudFront injects the `CloudFront-Viewer-*` header family (IP, ASN, country,\n * TLS version/cipher, HTTP version, device class) when the OriginRequestPolicy\n * whitelists them (see infra/template.yaml). Absent values are simply omitted —\n * a partial connection block is fine.\n */\nexport function collectConnectionMetadata(request: CloudFrontRequest): Record<string, string> {\n const out: Record<string, string> = {};\n const put = (key: string, headerName: string, transform?: (v: string) => string) => {\n const v = getHeader(request, headerName);\n if (v) out[key] = transform ? transform(v) : v;\n };\n // `cloudfront-viewer-address` is `ip:port` (IPv6 keeps its brackets); take the\n // address portion the same way the beacon/pipeline already do.\n const addr = getHeader(request, 'cloudfront-viewer-address');\n if (addr) out.ip = addr.replace(/:\\d+$/, '');\n put('country', 'cloudfront-viewer-country');\n put('countryName', 'cloudfront-viewer-country-name');\n put('region', 'cloudfront-viewer-country-region');\n put('city', 'cloudfront-viewer-city');\n put('asn', 'cloudfront-viewer-asn');\n put('tlsVersion', 'cloudfront-viewer-tls');\n put('httpVersion', 'cloudfront-viewer-http-version');\n // Device-class booleans → a single compact device string.\n const devices: string[] = [];\n for (const [label, header] of [\n ['desktop', 'cloudfront-is-desktop-viewer'],\n ['mobile', 'cloudfront-is-mobile-viewer'],\n ['tablet', 'cloudfront-is-tablet-viewer'],\n ['smarttv', 'cloudfront-is-smarttv-viewer'],\n ] as const) {\n if (getHeader(request, header) === 'true') devices.push(label);\n }\n if (devices.length) out.device = devices.join(',');\n return out;\n}\n\n/**\n * Workstream D — the FULL sanitised metadata capture for one request: every\n * inbound header (secrets stripped, credential headers reduced to a safe format\n * prefix) plus the connection-layer block. The edge is the richest capture\n * point — the header arrays are already in memory — and this is pure string\n * work, so it adds no page latency. Forwarded on both the verify-access call\n * and the beacon.\n */\nexport function buildObservedMetadata(request: CloudFrontRequest): ObservedMetadata {\n const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(\n flattenHeaders(request.headers)\n );\n const connection = collectConnectionMetadata(request);\n return {\n headers,\n ...(apiKeyFormat && { apiKeyFormat }),\n ...(platformHeaders && { platformHeaders }),\n ...(Object.keys(connection).length > 0 && { connection }),\n };\n}\n\n/**\n * Workstream D — normalize the origin-bound `Host` header.\n *\n * To receive the `CloudFront-Viewer-*` connection headers (IP/ASN/TLS/country)\n * we must move off the managed `AllViewerExceptHostHeader` origin-request policy\n * onto one that whitelists those headers — but every such policy ALSO forwards\n * the viewer `Host`, which would break vhost / PaaS origin routing that expects\n * the origin's own hostname. So the Lambda takes ownership of the Host rewrite:\n * stash the public (viewer) host into `X-Forwarded-Host` for downstream use and\n * detection, then set `Host` to the origin's domain (available on the event as\n * `request.origin.custom.domainName`). No-ops when the origin domain is absent\n * (synthetic test events) or already matches — so it is safe on every path,\n * including static-asset pass-through.\n */\nexport function normalizeOriginHost(request: CloudFrontRequest): void {\n const originDomain =\n request.origin?.custom?.domainName ?? request.origin?.s3?.domainName ?? undefined;\n if (!originDomain) return;\n const currentHost = getHeader(request, 'host');\n if (!currentHost || currentHost === originDomain) return;\n if (!getHeader(request, 'x-forwarded-host')) {\n setHeader(request, 'X-Forwarded-Host', currentHost);\n }\n setHeader(request, 'Host', originDomain);\n}\n\n/** Full request URL as the origin will see it (scheme fixed to https). */\nexport function requestUrl(request: CloudFrontRequest, host: string): string {\n const qs = request.querystring ? `?${request.querystring}` : '';\n return `https://${host}${request.uri}${qs}`;\n}\n\n/**\n * Set a header on the origin-bound request (overwrites all prior values).\n */\nexport function setHeader(request: CloudFrontRequest, name: string, value: string): void {\n request.headers[name.toLowerCase()] = [{ key: name, value }];\n}\n\n/**\n * Strip every inbound header matching a prefix (lowercase compare). Used to\n * drop spoofed `x-astrasync-*` trust headers before the shell injects its\n * own — in BOTH modes, so a caller can never smuggle trust past the origin.\n */\nexport function stripHeadersByPrefix(request: CloudFrontRequest, prefix: string): void {\n const p = prefix.toLowerCase();\n for (const name of Object.keys(request.headers)) {\n if (name.startsWith(p)) delete request.headers[name];\n }\n}\n\nexport function jsonResponse(\n status: number,\n body: unknown,\n extraHeaders?: Record<string, string>\n): CloudFrontResultResponse {\n const headers: CloudFrontResultResponse['headers'] = {\n 'content-type': [{ key: 'Content-Type', value: 'application/json' }],\n };\n for (const [name, value] of Object.entries(extraHeaders ?? {})) {\n headers[name.toLowerCase()] = [{ key: name, value }];\n }\n return {\n status: String(status),\n statusDescription: status === 403 ? 'Forbidden' : status === 202 ? 'Accepted' : 'OK',\n headers,\n body: JSON.stringify(body),\n };\n}\n","/**\n * Runtime configuration for the edge shell.\n *\n * Lambda@Edge forbids environment variables, so configuration is layered:\n * 1. Build-time constants baked into the bundle (apiBaseUrl,\n * counterpartyId, counterpartyUrl, apiKeySecretName) — see\n * `tsup.config.ts` define block and `infra/deploy.sh`.\n * 2. The merchant API key from AWS Secrets Manager (us-east-1), fetched\n * lazily once per container and cached with a 15-minute TTL so\n * rotation needs no redeploy. Observe mode works fully without it —\n * the beacon endpoint is unauthenticated and verify() degrades\n * keyless — so a Secrets Manager outage can never take the shell down.\n * 3. The dashboard EdgeConfig via the SDK's getEdgeConfig (60s TTL,\n * stale-while-revalidate, enforce→observe degradation after 24h\n * staleness, DEFAULT_EDGE_CONFIG fallback — all in the SDK).\n */\n\nimport {\n getEdgeConfig,\n DEFAULT_EDGE_CONFIG,\n type EdgeConfig,\n} from '@astrasyncai/verification-gateway/edge-config';\nimport type { EdgeAdapterOptions } from './types';\n\nconst SECRET_TTL_MS = 15 * 60 * 1000;\n\ninterface SecretCacheEntry {\n value: string | undefined;\n fetchedAt: number;\n}\n\nconst secretCache = new Map<string, SecretCacheEntry>();\n\nasync function defaultFetchSecret(secretName: string): Promise<string | undefined> {\n // Lazy import so tests (and the library build) never touch the AWS SDK\n // unless a secret name is actually configured.\n const { SecretsManagerClient, GetSecretValueCommand } =\n await import('@aws-sdk/client-secrets-manager');\n // Lambda@Edge replicates globally but secrets live in us-east-1 (the\n // Lambda@Edge home region).\n const client = new SecretsManagerClient({ region: 'us-east-1' });\n const result = await client.send(new GetSecretValueCommand({ SecretId: secretName }));\n return result.SecretString ?? undefined;\n}\n\n/**\n * Resolve the merchant API key. Never throws — a missing/unreachable secret\n * degrades to keyless operation (observe mode is fully functional without\n * it; enforce mode without a key cannot fetch a config that enforces, so it\n * degrades to observe by construction).\n */\nexport async function resolveApiKey(options: EdgeAdapterOptions): Promise<string | undefined> {\n if (options.apiKey) return options.apiKey;\n const secretName = options.apiKeySecretName;\n if (!secretName) return undefined;\n\n const cached = secretCache.get(secretName);\n if (cached && Date.now() - cached.fetchedAt < SECRET_TTL_MS) return cached.value;\n\n try {\n const fetcher = options.fetchSecret ?? defaultFetchSecret;\n const value = await fetcher(secretName);\n secretCache.set(secretName, { value, fetchedAt: Date.now() });\n return value;\n } catch (err) {\n options.log?.('warn', 'Secrets Manager fetch failed — continuing keyless', {\n secretName,\n error: err instanceof Error ? err.message : String(err),\n });\n // Serve a stale value if we ever had one; otherwise keyless.\n return cached?.value;\n }\n}\n\n/**\n * Load the effective EdgeConfig. Delegates caching/fallback/degradation to\n * the SDK; adds the compile-time fallback override and never throws.\n */\nexport async function loadEdgeConfig(\n options: EdgeAdapterOptions,\n apiKey: string | undefined\n): Promise<EdgeConfig> {\n try {\n return await getEdgeConfig({ apiBaseUrl: options.apiBaseUrl, apiKey }, options.counterpartyId, {\n ttlMs: options.configTtlMs,\n });\n } catch {\n return options.fallbackConfig ?? DEFAULT_EDGE_CONFIG;\n }\n}\n\n/** Reset module caches — tests only. */\nexport function _resetConfigCaches(): void {\n secretCache.clear();\n}\n","/**\n * Three-tier traffic classification (§33.5 #1: verified /\n * identified-but-unregistered / anonymous) plus the two non-tiers the shell\n * touches as little as possible: `human` (zero network calls, zero logging)\n * and `skipped` (static assets / excluded paths).\n *\n * Cheapest checks first — the human path must add microseconds, not\n * milliseconds. Platform signatures come from the SDK so the edge and the\n * backend's verify-access anonymous handler classify identically.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { detectPlatformFingerprint } from '@astrasyncai/verification-gateway/platform-signatures';\nimport { matchEdgePathRule, type EdgeConfig } from '@astrasyncai/verification-gateway/edge-config';\nimport { sanitizeHeaders } from '@astrasyncai/verification-gateway/metadata-capture';\nimport { getHeader, decodeBody, flattenHeaders } from './cf';\nimport { detectCommerce } from './detect';\nimport type { Classification, EffectivePolicy } from './types';\n\n/** Extensions the shell 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/** 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 * 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 decode, no header sniffing\n * beyond UA) — that is the zero-friction setting.\n */\nexport function classify(\n request: CloudFrontRequest,\n host: string,\n depth: 'classify' | 'authenticate' | 'authorize'\n): Classification {\n const userAgent = getHeader(request, 'user-agent') ?? '';\n const flat = flattenHeaders(request.headers);\n\n // 1. Native AstraSync credentials.\n const credentials = extractCredentials(flat, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { tier: 'verified', protocol: 'x-astra' };\n }\n\n // Workstream D — the key-format prefix + platform-signal headers are stronger,\n // less-spoofable platform signals than the UA. Compute once (cheap string\n // work) and feed every fingerprint call below.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(flat);\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(request, host, decodeBody(request));\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 (!getHeader(request, 'sec-fetch-mode') && !getHeader(request, 'accept-language')) {\n return { tier: 'anonymous-bot', evidence: { userAgent, spoofedBrowser: true } };\n }\n\n // 5. Human traffic — the shell 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 };\n","/**\n * Crypto-free commerce-protocol detection (§7.4.2 detection order).\n *\n * The edge only SNIFFS — header shapes, compact-JWT patterns, body field\n * names — and packages what it saw as raw `CommerceArtifactsPayload` for\n * verify-access, whose Step 0.5 pipeline does the authoritative parsing and\n * cryptographic verification server-side. Nothing here imports jose/sd-jwt/\n * signature libraries: detection must stay cheap enough to run on every\n * non-human request, and verification must happen exactly once, in the\n * canonical sink, where it is recorded.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport type { CommerceArtifactsPayload } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, requestUrl, type DecodedBody } from './cf';\n\nexport interface DetectedCommerce {\n /** Detection-order label: rfc9421-agent-pay | rfc9421-tap | rfc9421-web-bot-auth | vi-sd-jwt | ap2 | acp | ucp | mpp | x402 */\n protocol: string;\n artifacts: CommerceArtifactsPayload;\n /** Light detection detail for beacons/audit — never secrets or full credentials. */\n evidence: Record<string, unknown>;\n}\n\n/** Compact SD-JWT: JWT + `~`-separated disclosures. */\nconst SD_JWT_PATTERN = /^eyJ[\\w-]+\\.[\\w-]*\\.[\\w-]+~/;\n\n/** Decode a JWT header segment without verifying anything. */\nfunction sniffJwtHeader(compact: string): Record<string, unknown> | undefined {\n try {\n const seg = compact.split('.')[0];\n return JSON.parse(Buffer.from(seg, 'base64url').toString('utf8')) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonBody(body: DecodedBody): Record<string, unknown> | undefined {\n if (!body.text) return undefined;\n try {\n const parsed: unknown = JSON.parse(body.text);\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * §7.4.2 order (after the X-Astra native check, which classify.ts owns):\n * SD-JWT/VI → RFC 9421 (Agent Pay / TAP / Web Bot Auth by kid namespace or\n * Signature-Agent) → ACP HMAC → UCP session → AP2 body triple → MPP → x402.\n * Returns undefined when nothing commerce-shaped is on the wire.\n *\n * When the body was truncated by CloudFront (`inputTruncated`), body-bound\n * artifacts still forward what arrived but carry a `bodyTruncated` evidence\n * flag — the backend downgrades those signatures rather than hard-failing.\n */\nexport function detectCommerce(\n request: CloudFrontRequest,\n host: string,\n body: DecodedBody\n): DetectedCommerce | undefined {\n const url = requestUrl(request, host);\n const method = request.method;\n const headers = flattenHeaders(request.headers);\n const jsonBody = parseJsonBody(body);\n const truncated = body.truncated ? { bodyTruncated: true } : {};\n\n // --- VI / SD-JWT credential in a header ------------------------------\n const authHeader = getHeader(request, 'authorization');\n const bearer = authHeader?.replace(/^Bearer\\s+/i, '');\n const mandateHeader =\n getHeader(request, 'x-payment-mandate') ?? getHeader(request, 'payment-mandate');\n const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));\n if (sdJwtCandidate) {\n const typ = sniffJwtHeader(sdJwtCandidate)?.typ;\n return {\n protocol: 'vi-sd-jwt',\n artifacts: { viSdJwt: sdJwtCandidate },\n evidence: { typ, ...truncated },\n };\n }\n\n // --- RFC 9421 (Agent Pay / TAP / Web Bot Auth) ------------------------\n const signature = getHeader(request, 'signature');\n const signatureInput = getHeader(request, 'signature-input');\n if (signature && signatureInput) {\n const signatureAgent = getHeader(request, 'signature-agent');\n const registryHint = getHeader(request, 'x-agent-registry');\n const lowerInput = signatureInput.toLowerCase();\n const protocol = signatureAgent\n ? 'rfc9421-web-bot-auth'\n : registryHint?.toLowerCase().includes('visa') || lowerInput.includes('visa')\n ? 'rfc9421-tap'\n : registryHint?.toLowerCase().includes('mastercard') || lowerInput.includes('mastercard')\n ? 'rfc9421-agent-pay'\n : 'rfc9421';\n return {\n protocol,\n artifacts: {\n rfc9421: { headers, method, url, ...(body.text && { body: body.text }) },\n },\n evidence: {\n ...(signatureAgent && { signatureAgent }),\n ...(registryHint && { registryHint }),\n keyid: signatureInput.match(/keyid=\"([^\"]+)\"/)?.[1],\n ...truncated,\n },\n };\n }\n\n // --- ACP (HMAC-signed webhook/checkout: signature WITHOUT signature-input)\n const acpTimestamp = getHeader(request, 'timestamp');\n if (signature && !signatureInput && (acpTimestamp || getHeader(request, 'idempotency-key'))) {\n return {\n protocol: 'acp',\n artifacts: {\n acpRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated },\n };\n }\n\n // --- UCP checkout session ---------------------------------------------\n if (/\\/checkout[-_]sessions(\\/|$)/.test(request.uri)) {\n return {\n protocol: 'ucp',\n artifacts: { ucpRequest: { method, url, ...(jsonBody && { body: jsonBody }) } },\n evidence: { path: request.uri, ...truncated },\n };\n }\n\n // --- AP2 mandate triple in the body -----------------------------------\n if (jsonBody) {\n const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;\n const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;\n const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;\n if (typeof intent === 'string' || typeof cart === 'string' || typeof payment === 'string') {\n return {\n protocol: 'ap2',\n artifacts: {\n ap2Mandates: {\n ...(typeof intent === 'string' && { intent }),\n ...(typeof cart === 'string' && { cart }),\n ...(typeof payment === 'string' && { payment }),\n },\n },\n evidence: {\n mandatesPresent: [\n typeof intent === 'string' && 'intent',\n typeof cart === 'string' && 'cart',\n typeof payment === 'string' && 'payment',\n ].filter(Boolean),\n ...truncated,\n },\n };\n }\n }\n\n // --- MPP (`Authorization: Payment <credential>`) -----------------------\n if (authHeader && /^Payment\\s+/i.test(authHeader)) {\n return {\n protocol: 'mpp',\n artifacts: {\n mppRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: truncated,\n };\n }\n\n // --- x402 (X-PAYMENT header) ------------------------------------------\n if (getHeader(request, 'x-payment')) {\n return {\n protocol: 'x402',\n artifacts: {\n x402Request: { method, url, headers, ...(jsonBody && { body: jsonBody }) },\n },\n evidence: truncated,\n };\n }\n\n return undefined;\n}\n","/**\n * Depth-controlled verification per tier. The edge never verifies\n * credentials itself — it forwards what it detected to verify-access, the\n * canonical sole verification sink (backend Step 0.5 runs the commerce\n * pipeline, records events, provisions orphans, persists sessions). What\n * the depth setting controls is how much the edge LOOKS and how much it\n * FORWARDS:\n *\n * classify — what is it? UA tiers only. Zero verify-access calls;\n * beacons only.\n * authenticate — who is it? + protocol detection. X-Astra agents get a\n * verify-access identity check; commerce/platform traffic\n * is beaconed with protocol + evidence (no signature\n * verification anywhere).\n * authorize — are they allowed? + artifact forwarding. X-Astra verify\n * calls carry commerceArtifacts; identified traffic gets an\n * anonymous verify-access call with artifacts +\n * callerMetadata so the backend cryptographically proves\n * and policy-evaluates once.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { verify, extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { resolveHttpPdlss } from '@astrasyncai/verification-gateway/http-pdlss';\nimport type { GatewayConfig, VerificationRequest } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, buildObservedMetadata } from './cf';\nimport { withBudget, emitBeacon, sampled } from './events';\nimport type { Classification, EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\nfunction baseOutcome(classification: Classification): TierOutcome {\n return {\n tier: classification.tier,\n decision: 'allow',\n reasons: [],\n protocol: classification.protocol,\n };\n}\n\nfunction buildVerificationRequest(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n includeArtifacts: boolean\n): VerificationRequest {\n const headers = flattenHeaders(request.headers);\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n // verify-access REQUIRES a purpose. Resolve via the shared §4.6 chain:\n // the agent's X-Astra-Purpose/-Action declarations, else the pinned\n // method table (GET → data/data.read etc.) — a transport verb never\n // travels as a PDLSS action.\n const pdlss = resolveHttpPdlss({\n method: request.method,\n astraPurpose: getHeader(request, 'x-astra-purpose'),\n astraAction: getHeader(request, 'x-astra-action'),\n });\n return {\n credentials: extractCredentials(headers, {}),\n purpose: pdlss.purpose,\n action: pdlss.action,\n resource: request.uri,\n createSession: true,\n counterpartyType: 'website',\n counterpartyUrl: options.counterpartyUrl,\n callerMetadata: {\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n referer: getHeader(request, 'referer'),\n host: getHeader(request, 'host'),\n // Workstream D — the full sanitised header + connection capture. The\n // backend stores it fire-and-forget (zero decision latency) and uses the\n // key-format / platform headers for attribution.\n observedMetadata: buildObservedMetadata(request),\n },\n ...(includeArtifacts &&\n classification.artifacts && { commerceArtifacts: classification.artifacts }),\n };\n}\n\nfunction outcomeFromVerifyResult(\n classification: Classification,\n result: Awaited<ReturnType<typeof verify>>\n): TierOutcome {\n const outcome = baseOutcome(classification);\n outcome.sessionId = (result as { sessionId?: string }).sessionId;\n outcome.correlationId = result.correlationId;\n outcome.guidance = result.guidance;\n\n if (result.requiresStepUp || result.stepUpApproval) {\n outcome.decision = 'manual_review';\n outcome.reasons = ['step-up approval required'];\n outcome.stepUp = {\n pollUrl: (result.stepUpApproval as { pollUrl?: string } | undefined)?.pollUrl,\n expiresAt: (result.stepUpApproval as { expiresAt?: string } | undefined)?.expiresAt,\n };\n return outcome;\n }\n\n if (!result.identityVerified || !result.policyAllowed) {\n outcome.decision = 'deny';\n outcome.reasons = result.denialReasons?.length\n ? result.denialReasons\n : [!result.identityVerified ? 'identity not verified' : 'denied by access policy'];\n return outcome;\n }\n\n outcome.asat = {\n trustScore: result.agent?.trustScore,\n agentId: result.agent?.astraId,\n developerId: result.developer?.astradId,\n accessLevel: result.accessLevel,\n };\n return outcome;\n}\n\n/**\n * Run the tier-appropriate verification/telemetry for one classified\n * request. NEVER throws; on any failure returns an `allow` outcome with the\n * failure recorded in `reasons` (infra failures fail open — a presented\n * credential the BACKEND rejected is a deny, but an unreachable backend is\n * not a rejection).\n */\nexport async function runTier(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n policy: EffectivePolicy,\n apiKey: string | undefined,\n sampling: { anonymousBeaconRate: number }\n): Promise<TierOutcome> {\n const budgets = options.budgets ?? {};\n const beaconMs = budgets.beaconMs ?? 300;\n const verifyMs =\n policy.mode === 'enforce'\n ? (budgets.verifyEnforceMs ?? 3000)\n : (budgets.verifyObserveMs ?? 1500);\n\n const gatewayConfig: GatewayConfig = {\n apiBaseUrl: options.apiBaseUrl,\n ...(apiKey && { apiKey }),\n counterpartyId: options.counterpartyId,\n // The shell handles its own error semantics; init self-probes don't\n // belong in a per-request edge function.\n disableInitChecks: true,\n } as GatewayConfig;\n\n try {\n switch (classification.tier) {\n case 'verified': {\n // classify depth = zero API calls, even for credentialed agents.\n if (policy.depth === 'classify') {\n return baseOutcome(classification);\n }\n const result = await withBudget(\n verify(\n gatewayConfig,\n buildVerificationRequest(options, request, classification, policy.depth === 'authorize')\n ),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n\n case 'identified': {\n if (policy.depth === 'authorize' && classification.artifacts) {\n // Anonymous verify-access call WITH artifacts: the backend runs\n // the commerce pipeline, records unverified events, and\n // provisions orphan platform agents — one sink, recorded once.\n const result = await withBudget(\n verify(gatewayConfig, buildVerificationRequest(options, request, classification, true)),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n // classify/credentials depth (or no artifacts): lightweight beacon.\n await emitBeacon(options, request, classification, beaconMs);\n const outcome = baseOutcome(classification);\n if (policy.mode === 'enforce' && policy.depth !== 'classify') {\n // Unregistered agent on an enforced path: deny with guidance.\n outcome.decision = 'deny';\n outcome.reasons = ['agent is not registered with AstraSync'];\n }\n return outcome;\n }\n\n case 'anonymous-bot': {\n if (sampled(sampling.anonymousBeaconRate, options.random)) {\n await emitBeacon(\n options,\n request,\n { ...classification, protocol: classification.protocol ?? 'ua-heuristic' },\n beaconMs\n );\n }\n // Anonymous bots pass through even in enforce mode — enforce gates\n // AGENT traffic; generic bot management stays the CDN/WAF's job\n // (mixed-traffic classification §5.1.7 is the enforce-mode\n // prerequisite tracked as §33.5 #9).\n return baseOutcome(classification);\n }\n\n default:\n return baseOutcome(classification);\n }\n } catch (err) {\n const outcome = baseOutcome(classification);\n outcome.reasons = [\n `edge pipeline error — fail-open: ${err instanceof Error ? err.message : String(err)}`,\n ];\n return outcome;\n }\n}\n","/**\n * Time-budgeted event emission.\n *\n * Lambda@Edge has no `waitUntil` — anything not awaited before the handler\n * returns may never run (the container freezes). So every network call is\n * awaited under an explicit budget and DROPPED on timeout: latency to the\n * customer's traffic is bounded, and a slow AstraSync API costs telemetry,\n * never page loads.\n */\n\nimport { reportUnregisteredAttempt } from '@astrasyncai/verification-gateway/verify';\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { getHeader, buildObservedMetadata } from './cf';\nimport type { Classification, EdgeAdapterOptions } 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\n * (CSRF-exempt on the backend); the backend fingerprints the UA and\n * find-or-provisions orphan platform agents server-side.\n */\nexport async function emitBeacon(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n budgetMs: number\n): Promise<void> {\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n await withBudget(\n reportUnregisteredAttempt(\n { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },\n {\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: 'website',\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n requestPath: request.uri,\n requestMethod: request.method,\n // 3.9.0 evidence fields (backend persists them into eventData).\n protocol: classification.protocol,\n evidence: classification.evidence,\n // Workstream D — full sanitised header + connection capture for the\n // unregistered caller (fire-and-forget, so free).\n observedMetadata: buildObservedMetadata(request),\n }\n ),\n budgetMs\n );\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 * §7.4.6 — protocol-specific machine-readable messaging for enforce-mode\n * responses. Agents (not humans) consume these bodies: stable error codes,\n * the failure list, and registration guidance with real URLs.\n */\n\nimport type { TierOutcome } from './types';\n\nconst PROTOCOL_MESSAGES: Record<string, string> = {\n 'vi-sd-jwt':\n 'This request presented Visa Intelligent Commerce credentials, but the agent is not verified with AstraSync. Register the agent to pair your VI credentials with a verified identity and mandate.',\n 'rfc9421-agent-pay':\n 'This request carried a Mastercard Agent Pay signature, but the agent is not verified with AstraSync. Register the agent to pair Agent Pay credentials with a verified identity and mandate.',\n 'rfc9421-tap':\n 'This request carried a Visa TAP signature, but the agent is not verified with AstraSync. Register the agent to pair TAP credentials with a verified identity and mandate.',\n 'rfc9421-web-bot-auth':\n 'This request carried a Web Bot Auth signature, but the agent is not verified with AstraSync. Register the agent to link your signed-agent identity to a verified principal.',\n rfc9421:\n 'This request carried an RFC 9421 HTTP message signature, but the agent is not verified with AstraSync. Register the agent to link the signing identity to a verified principal.',\n acp: 'This request used the Agentic Commerce Protocol, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ucp: 'This request used a UCP checkout session, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ap2: 'This request presented AP2 mandates, but the agent is not verified with AstraSync. Register the agent to pair your mandates with a verified identity.',\n mpp: 'This request presented MPP payment credentials, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n x402: 'This request used x402 payment headers, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n 'platform-ua':\n 'This traffic was identified as a platform AI agent without AstraSync credentials. Register the agent to access this property with a verified identity.',\n 'x-astra':\n 'The presented AstraSync credentials failed verification or were denied by this property’s access policy.',\n};\n\nexport interface DenyBody {\n success: false;\n error: {\n code: 'UNAUTHORIZED' | 'INSUFFICIENT_ACCESS';\n message: string;\n protocol?: string;\n failures: string[];\n correlationId?: string;\n guidance: {\n message?: string;\n registrationUrl?: string;\n documentationUrl?: string;\n };\n };\n}\n\nexport function buildDenyBody(outcome: TierOutcome, apiBaseUrl: string): DenyBody {\n const origin = apiBaseUrl.replace(/\\/api\\/?$/, '');\n const protocolMessage =\n (outcome.protocol && PROTOCOL_MESSAGES[outcome.protocol]) ??\n 'This request could not be verified by AstraSync.';\n return {\n success: false,\n error: {\n // UNAUTHORIZED = identity failed (register/re-authenticate helps);\n // INSUFFICIENT_ACCESS = identity fine, policy denied (fix the mandate).\n code: outcome.tier === 'verified' ? 'INSUFFICIENT_ACCESS' : 'UNAUTHORIZED',\n message: protocolMessage,\n ...(outcome.protocol && { protocol: outcome.protocol }),\n failures: outcome.reasons,\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n guidance: {\n // `||` not `??`: verify() fills these with EMPTY STRINGS when the\n // well-known cache is cold — empty means \"use the fallback\".\n message:\n outcome.guidance?.message ||\n 'Register this agent with AstraSync to receive verifiable credentials.',\n registrationUrl: outcome.guidance?.registrationUrl || `${origin}/register`,\n documentationUrl: outcome.guidance?.documentationUrl || `${origin}/docs/edge-adapter`,\n },\n },\n };\n}\n\nexport interface ManualReviewBody {\n success: false;\n status: 'manual_review';\n message: string;\n stepUpApproval?: { pollUrl?: string; expiresAt?: string };\n correlationId?: string;\n}\n\nexport function buildManualReviewBody(outcome: TierOutcome): ManualReviewBody {\n return {\n success: false,\n status: 'manual_review',\n message:\n 'This action requires human approval. Poll the step-up approval endpoint and retry once approved.',\n ...(outcome.stepUp && { stepUpApproval: outcome.stepUp }),\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n };\n}\n","/**\n * Decision → CloudFront result wiring (§7.4 enforcement, §7.4.7 ASAT\n * headers). Executed in BOTH modes so observe mode records exactly what\n * enforce mode would have done — but only enforce mode is allowed to return\n * anything other than the origin-bound request.\n */\n\nimport type { CloudFrontRequest, CloudFrontRequestResult } from 'aws-lambda';\nimport { jsonResponse, setHeader, stripHeadersByPrefix } from './cf';\nimport { buildDenyBody, buildManualReviewBody } from './messaging';\nimport type { EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\n/** §7.4.7 ASAT trust-attestation headers injected on allowed requests. */\nexport const ASAT_HEADERS = {\n trustScore: 'X-AstraSync-Trust-Score',\n agentId: 'X-AstraSync-Agent-Id',\n developerId: 'X-AstraSync-Developer-Id',\n permissions: 'X-AstraSync-Permissions',\n observedDecision: 'X-AstraSync-Observed-Decision',\n} as const;\n\n/**\n * Apply the outcome. Always strips inbound spoofed `x-astrasync-*` headers\n * first (both modes — trust headers must only ever originate here).\n *\n * Observe mode: returns the request untouched apart from header hygiene and\n * an `X-AstraSync-Observed-Decision` stamp for origin-side log correlation.\n *\n * Enforce mode: ALLOW → request + ASAT headers; DENY → 403 machine-readable\n * body; MANUAL_REVIEW → 202 with step-up poll info.\n */\nexport function applyOutcome(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n outcome: TierOutcome,\n policy: EffectivePolicy\n): CloudFrontRequestResult {\n stripHeadersByPrefix(request, 'x-astrasync-');\n\n if (policy.mode !== 'enforce') {\n // Shadow stamp: what enforce WOULD have done, visible in origin logs.\n if (outcome.decision !== 'allow') {\n setHeader(request, ASAT_HEADERS.observedDecision, outcome.decision);\n }\n injectAsat(request, outcome);\n return request;\n }\n\n switch (outcome.decision) {\n case 'deny':\n return jsonResponse(403, buildDenyBody(outcome, options.apiBaseUrl));\n case 'manual_review':\n return jsonResponse(202, buildManualReviewBody(outcome), {\n 'Retry-After': '30',\n });\n default:\n injectAsat(request, outcome);\n return request;\n }\n}\n\nfunction injectAsat(request: CloudFrontRequest, outcome: TierOutcome): void {\n if (!outcome.asat) return;\n const { trustScore, agentId, developerId, accessLevel } = outcome.asat;\n if (trustScore !== undefined) {\n setHeader(request, ASAT_HEADERS.trustScore, String(trustScore));\n }\n if (agentId) setHeader(request, ASAT_HEADERS.agentId, agentId);\n if (developerId) setHeader(request, ASAT_HEADERS.developerId, developerId);\n if (accessLevel) setHeader(request, ASAT_HEADERS.permissions, accessLevel);\n}\n","/**\n * Commerce Shield edge shell — Lambda@Edge origin-request handler factory\n * (§7.4 / §33.5 #1).\n *\n * Composition per request:\n * config (cached) → path policy → classify → tier pipeline → apply outcome\n *\n * THE invariant (tested): outside enforce mode the handler ALWAYS returns\n * the origin-bound request — any error, timeout, or misconfiguration\n * results in pass-through. A top-level catch guarantees it even against\n * bugs in the shell itself.\n */\n\nimport type { CloudFrontRequestEvent, CloudFrontRequestResult } from 'aws-lambda';\nimport { getRequest, getHeader, normalizeOriginHost } from './cf';\nimport { resolveApiKey, loadEdgeConfig } from './config';\nimport { classify, resolvePolicy } from './classify';\nimport { runTier } from './pipeline';\nimport { applyOutcome } from './enforce';\nimport type { EdgeAdapterOptions } from './types';\n\nexport type EdgeHandler = (event: CloudFrontRequestEvent) => Promise<CloudFrontRequestResult>;\n\nexport function createEdgeHandler(options: EdgeAdapterOptions): EdgeHandler {\n const log =\n options.log ??\n ((level, message, data) => {\n // Lambda@Edge writes console output to the regional CloudWatch log\n // group of whichever edge location served the request.\n console[level === 'info' ? 'log' : level](`[astrasync-edge] ${message}`, data ?? '');\n });\n\n return async function handler(event) {\n const request = getRequest(event);\n try {\n // Own the Host rewrite (Workstream D): the CloudFront-Viewer-* capture\n // requires an origin-request policy that also forwards the viewer Host,\n // so the shell restores origin-domain Host + X-Forwarded-Host itself.\n // Runs first so EVERY origin-bound return (skip / human / allow) is\n // correctly routed.\n normalizeOriginHost(request);\n\n const apiKey = await resolveApiKey({ ...options, log });\n const config = await loadEdgeConfig(options, apiKey);\n const policy = resolvePolicy(config, request.uri);\n\n // Skipped paths (static assets / skip rules): untouched, zero work.\n if (policy.skip) return request;\n\n const host =\n getHeader(request, 'x-forwarded-host') ??\n getHeader(request, 'host') ??\n new URL(options.counterpartyUrl).host;\n\n const classification = classify(request, host, policy.depth);\n\n // Humans: get out of the way. No calls, no logs, no header changes\n // beyond nothing at all.\n if (classification.tier === 'human') return request;\n\n const outcome = await runTier(\n { ...options, log },\n request,\n classification,\n policy,\n apiKey,\n config.sampling\n );\n\n if (outcome.decision !== 'allow') {\n log(\n 'info',\n policy.mode === 'enforce'\n ? `${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`\n : `[OBSERVE] would have been ${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`,\n { tier: outcome.tier, protocol: outcome.protocol, reasons: outcome.reasons }\n );\n }\n\n return applyOutcome(options, request, outcome, policy);\n } catch (err) {\n // Fail-open, unconditionally: the shell must never take the site down.\n log('error', 'edge handler error — passing request through', {\n error: err instanceof Error ? err.message : String(err),\n });\n return request;\n }\n };\n}\n"],"mappings":"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","names":["sanitizeHeaders","sanitizeHeaders","extractCredentials","extractCredentials","outcome"]}
1
+ {"version":3,"sources":["../src/cf.ts","../src/config.ts","../src/classify.ts","../src/detect.ts","../src/pipeline.ts","../src/events.ts","../src/messaging.ts","../src/enforce.ts","../src/handler.ts"],"sourcesContent":["/**\n * CloudFront origin-request event helpers. The Lambda@Edge event shape puts\n * headers in `{ key, value }[]` arrays keyed by LOWERCASED header name, and\n * (with IncludeBody) the body arrives base64-encoded with an\n * `inputTruncated` flag when it exceeded CloudFront's ~1MB exposure cap.\n */\n\nimport type {\n CloudFrontRequest,\n CloudFrontRequestEvent,\n CloudFrontHeaders,\n CloudFrontResultResponse,\n} from 'aws-lambda';\nimport {\n sanitizeHeaders,\n type ObservedMetadata,\n} from '@astrasyncai/verification-gateway/metadata-capture';\n\nexport function getRequest(event: CloudFrontRequestEvent): CloudFrontRequest {\n return event.Records[0].cf.request;\n}\n\n/** First value of a header (lowercase name), or undefined. */\nexport function getHeader(request: CloudFrontRequest, name: string): string | undefined {\n return request.headers[name.toLowerCase()]?.[0]?.value;\n}\n\n/**\n * Flatten CloudFront headers into the `Record<string, string | string[]>`\n * shape the SDK extractors and verify-access artifacts expect.\n */\nexport function flattenHeaders(headers: CloudFrontHeaders): Record<string, string | string[]> {\n const out: Record<string, string | string[]> = {};\n for (const [name, entries] of Object.entries(headers)) {\n if (!entries?.length) continue;\n out[name] = entries.length === 1 ? entries[0].value : entries.map((e) => e.value);\n }\n return out;\n}\n\nexport interface DecodedBody {\n /** UTF-8 body text, undefined when there is no body. */\n text?: string;\n /** True when CloudFront truncated the body before handing it to the trigger. */\n truncated: boolean;\n}\n\nexport function decodeBody(request: CloudFrontRequest): DecodedBody {\n const body = request.body;\n if (!body?.data) return { truncated: false };\n const text =\n body.encoding === 'base64' ? Buffer.from(body.data, 'base64').toString('utf8') : body.data;\n return { text, truncated: body.inputTruncated === true };\n}\n\n/**\n * Workstream D — connection-layer signals the edge can see but the SDK cannot.\n * CloudFront injects the `CloudFront-Viewer-*` header family (IP, ASN, country,\n * TLS version/cipher, HTTP version, device class) when the OriginRequestPolicy\n * whitelists them (see infra/template.yaml). Absent values are simply omitted —\n * a partial connection block is fine.\n */\nexport function collectConnectionMetadata(request: CloudFrontRequest): Record<string, string> {\n const out: Record<string, string> = {};\n const put = (key: string, headerName: string, transform?: (v: string) => string) => {\n const v = getHeader(request, headerName);\n if (v) out[key] = transform ? transform(v) : v;\n };\n // `cloudfront-viewer-address` is `ip:port` (IPv6 keeps its brackets); take the\n // address portion the same way the beacon/pipeline already do.\n const addr = getHeader(request, 'cloudfront-viewer-address');\n if (addr) out.ip = addr.replace(/:\\d+$/, '');\n put('country', 'cloudfront-viewer-country');\n put('countryName', 'cloudfront-viewer-country-name');\n put('region', 'cloudfront-viewer-country-region');\n put('city', 'cloudfront-viewer-city');\n put('asn', 'cloudfront-viewer-asn');\n put('tlsVersion', 'cloudfront-viewer-tls');\n put('httpVersion', 'cloudfront-viewer-http-version');\n // Device-class booleans → a single compact device string.\n const devices: string[] = [];\n for (const [label, header] of [\n ['desktop', 'cloudfront-is-desktop-viewer'],\n ['mobile', 'cloudfront-is-mobile-viewer'],\n ['tablet', 'cloudfront-is-tablet-viewer'],\n ['smarttv', 'cloudfront-is-smarttv-viewer'],\n ] as const) {\n if (getHeader(request, header) === 'true') devices.push(label);\n }\n if (devices.length) out.device = devices.join(',');\n return out;\n}\n\n/**\n * Workstream D — the FULL sanitised metadata capture for one request: every\n * inbound header (secrets stripped, credential headers reduced to a safe format\n * prefix) plus the connection-layer block. The edge is the richest capture\n * point — the header arrays are already in memory — and this is pure string\n * work, so it adds no page latency. Forwarded on both the verify-access call\n * and the beacon.\n */\nexport function buildObservedMetadata(request: CloudFrontRequest): ObservedMetadata {\n const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(\n flattenHeaders(request.headers)\n );\n const connection = collectConnectionMetadata(request);\n return {\n headers,\n ...(apiKeyFormat && { apiKeyFormat }),\n ...(platformHeaders && { platformHeaders }),\n ...(Object.keys(connection).length > 0 && { connection }),\n };\n}\n\n/**\n * Workstream D — normalize the origin-bound `Host` header.\n *\n * To receive the `CloudFront-Viewer-*` connection headers (IP/ASN/TLS/country)\n * we must move off the managed `AllViewerExceptHostHeader` origin-request policy\n * onto one that whitelists those headers — but every such policy ALSO forwards\n * the viewer `Host`, which would break vhost / PaaS origin routing that expects\n * the origin's own hostname. So the Lambda takes ownership of the Host rewrite:\n * stash the public (viewer) host into `X-Forwarded-Host` for downstream use and\n * detection, then set `Host` to the origin's domain (available on the event as\n * `request.origin.custom.domainName`). No-ops when the origin domain is absent\n * (synthetic test events) or already matches — so it is safe on every path,\n * including static-asset pass-through.\n */\nexport function normalizeOriginHost(request: CloudFrontRequest): void {\n const originDomain =\n request.origin?.custom?.domainName ?? request.origin?.s3?.domainName ?? undefined;\n if (!originDomain) return;\n const currentHost = getHeader(request, 'host');\n if (!currentHost || currentHost === originDomain) return;\n if (!getHeader(request, 'x-forwarded-host')) {\n setHeader(request, 'X-Forwarded-Host', currentHost);\n }\n setHeader(request, 'Host', originDomain);\n}\n\n/** Full request URL as the origin will see it (scheme fixed to https). */\nexport function requestUrl(request: CloudFrontRequest, host: string): string {\n const qs = request.querystring ? `?${request.querystring}` : '';\n return `https://${host}${request.uri}${qs}`;\n}\n\n/**\n * Set a header on the origin-bound request (overwrites all prior values).\n */\nexport function setHeader(request: CloudFrontRequest, name: string, value: string): void {\n request.headers[name.toLowerCase()] = [{ key: name, value }];\n}\n\n/**\n * Strip every inbound header matching a prefix (lowercase compare). Used to\n * drop spoofed `x-astrasync-*` trust headers before the shell injects its\n * own — in BOTH modes, so a caller can never smuggle trust past the origin.\n */\nexport function stripHeadersByPrefix(request: CloudFrontRequest, prefix: string): void {\n const p = prefix.toLowerCase();\n for (const name of Object.keys(request.headers)) {\n if (name.startsWith(p)) delete request.headers[name];\n }\n}\n\nexport function jsonResponse(\n status: number,\n body: unknown,\n extraHeaders?: Record<string, string>\n): CloudFrontResultResponse {\n const headers: CloudFrontResultResponse['headers'] = {\n 'content-type': [{ key: 'Content-Type', value: 'application/json' }],\n };\n for (const [name, value] of Object.entries(extraHeaders ?? {})) {\n headers[name.toLowerCase()] = [{ key: name, value }];\n }\n return {\n status: String(status),\n statusDescription: status === 403 ? 'Forbidden' : status === 202 ? 'Accepted' : 'OK',\n headers,\n body: JSON.stringify(body),\n };\n}\n","/**\n * Runtime configuration for the edge shell.\n *\n * Lambda@Edge forbids environment variables, so configuration is layered:\n * 1. Build-time constants baked into the bundle (apiBaseUrl,\n * counterpartyId, counterpartyUrl, apiKeySecretName) — see\n * `tsup.config.ts` define block and `infra/deploy.sh`.\n * 2. The merchant API key from AWS Secrets Manager (us-east-1), fetched\n * lazily once per container and cached with a 15-minute TTL so\n * rotation needs no redeploy. Observe mode works fully without it —\n * the beacon endpoint is unauthenticated and verify() degrades\n * keyless — so a Secrets Manager outage can never take the shell down.\n * 3. The dashboard EdgeConfig via the SDK's getEdgeConfig (60s TTL,\n * stale-while-revalidate, enforce→observe degradation after 24h\n * staleness, DEFAULT_EDGE_CONFIG fallback — all in the SDK).\n */\n\nimport {\n getEdgeConfig,\n DEFAULT_EDGE_CONFIG,\n type EdgeConfig,\n} from '@astrasyncai/verification-gateway/edge-config';\nimport type { EdgeAdapterOptions } from './types';\n\nconst SECRET_TTL_MS = 15 * 60 * 1000;\n\ninterface SecretCacheEntry {\n value: string | undefined;\n fetchedAt: number;\n}\n\nconst secretCache = new Map<string, SecretCacheEntry>();\n\nasync function defaultFetchSecret(secretName: string): Promise<string | undefined> {\n // Lazy import so tests (and the library build) never touch the AWS SDK\n // unless a secret name is actually configured.\n const { SecretsManagerClient, GetSecretValueCommand } =\n await import('@aws-sdk/client-secrets-manager');\n // Lambda@Edge replicates globally but secrets live in us-east-1 (the\n // Lambda@Edge home region).\n const client = new SecretsManagerClient({ region: 'us-east-1' });\n const result = await client.send(new GetSecretValueCommand({ SecretId: secretName }));\n return result.SecretString ?? undefined;\n}\n\n/**\n * Resolve the merchant API key. Never throws — a missing/unreachable secret\n * degrades to keyless operation (observe mode is fully functional without\n * it; enforce mode without a key cannot fetch a config that enforces, so it\n * degrades to observe by construction).\n */\nexport async function resolveApiKey(options: EdgeAdapterOptions): Promise<string | undefined> {\n if (options.apiKey) return options.apiKey;\n const secretName = options.apiKeySecretName;\n if (!secretName) return undefined;\n\n const cached = secretCache.get(secretName);\n if (cached && Date.now() - cached.fetchedAt < SECRET_TTL_MS) return cached.value;\n\n try {\n const fetcher = options.fetchSecret ?? defaultFetchSecret;\n const value = await fetcher(secretName);\n secretCache.set(secretName, { value, fetchedAt: Date.now() });\n return value;\n } catch (err) {\n options.log?.('warn', 'Secrets Manager fetch failed — continuing keyless', {\n secretName,\n error: err instanceof Error ? err.message : String(err),\n });\n // Serve a stale value if we ever had one; otherwise keyless.\n return cached?.value;\n }\n}\n\n/**\n * Load the effective EdgeConfig. Delegates caching/fallback/degradation to\n * the SDK; adds the compile-time fallback override and never throws.\n */\nexport async function loadEdgeConfig(\n options: EdgeAdapterOptions,\n apiKey: string | undefined\n): Promise<EdgeConfig> {\n try {\n return await getEdgeConfig({ apiBaseUrl: options.apiBaseUrl, apiKey }, options.counterpartyId, {\n ttlMs: options.configTtlMs,\n });\n } catch {\n return options.fallbackConfig ?? DEFAULT_EDGE_CONFIG;\n }\n}\n\n/** Reset module caches — tests only. */\nexport function _resetConfigCaches(): void {\n secretCache.clear();\n}\n","/**\n * Three-tier traffic classification (§33.5 #1: verified /\n * identified-but-unregistered / anonymous) plus the two non-tiers the shell\n * touches as little as possible: `human` (zero network calls, zero logging)\n * and `skipped` (static assets / excluded paths).\n *\n * Cheapest checks first — the human path must add microseconds, not\n * milliseconds. Platform signatures come from the SDK so the edge and the\n * backend's verify-access anonymous handler classify identically.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { detectPlatformFingerprint } from '@astrasyncai/verification-gateway/platform-signatures';\nimport { matchEdgePathRule, type EdgeConfig } from '@astrasyncai/verification-gateway/edge-config';\nimport { sanitizeHeaders } from '@astrasyncai/verification-gateway/metadata-capture';\nimport { getHeader, decodeBody, flattenHeaders } from './cf';\nimport { detectCommerce } from './detect';\nimport type { Classification, EffectivePolicy } from './types';\n\n/** Extensions the shell 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/** 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 * 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 decode, no header sniffing\n * beyond UA) — that is the zero-friction setting.\n */\nexport function classify(\n request: CloudFrontRequest,\n host: string,\n depth: 'classify' | 'authenticate' | 'authorize'\n): Classification {\n const userAgent = getHeader(request, 'user-agent') ?? '';\n const flat = flattenHeaders(request.headers);\n\n // 1. Native AstraSync credentials.\n const credentials = extractCredentials(flat, {});\n if (credentials.astraId || credentials.apiKey || credentials.jwt) {\n return { tier: 'verified', protocol: 'x-astra' };\n }\n\n // Workstream D — the key-format prefix + platform-signal headers are stronger,\n // less-spoofable platform signals than the UA. Compute once (cheap string\n // work) and feed every fingerprint call below.\n const { apiKeyFormat, platformHeaders } = sanitizeHeaders(flat);\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(request, host, decodeBody(request));\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 (!getHeader(request, 'sec-fetch-mode') && !getHeader(request, 'accept-language')) {\n return { tier: 'anonymous-bot', evidence: { userAgent, spoofedBrowser: true } };\n }\n\n // 5. Human traffic — the shell 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 };\n","/**\n * Crypto-free commerce-protocol detection (§7.4.2 detection order).\n *\n * The edge only SNIFFS — header shapes, compact-JWT patterns, body field\n * names — and packages what it saw as raw `CommerceArtifactsPayload` for\n * verify-access, whose Step 0.5 pipeline does the authoritative parsing and\n * cryptographic verification server-side. Nothing here imports jose/sd-jwt/\n * signature libraries: detection must stay cheap enough to run on every\n * non-human request, and verification must happen exactly once, in the\n * canonical sink, where it is recorded.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport type { CommerceArtifactsPayload } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, requestUrl, type DecodedBody } from './cf';\n\nexport interface DetectedCommerce {\n /** Detection-order label: rfc9421-agent-pay | rfc9421-tap | rfc9421-web-bot-auth | vi-sd-jwt | ap2 | acp | ucp | mpp | x402 */\n protocol: string;\n artifacts: CommerceArtifactsPayload;\n /** Light detection detail for beacons/audit — never secrets or full credentials. */\n evidence: Record<string, unknown>;\n}\n\n/** Compact SD-JWT: JWT + `~`-separated disclosures. */\nconst SD_JWT_PATTERN = /^eyJ[\\w-]+\\.[\\w-]*\\.[\\w-]+~/;\n\n/** Decode a JWT header segment without verifying anything. */\nfunction sniffJwtHeader(compact: string): Record<string, unknown> | undefined {\n try {\n const seg = compact.split('.')[0];\n return JSON.parse(Buffer.from(seg, 'base64url').toString('utf8')) as Record<string, unknown>;\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonBody(body: DecodedBody): Record<string, unknown> | undefined {\n if (!body.text) return undefined;\n try {\n const parsed: unknown = JSON.parse(body.text);\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * §7.4.2 order (after the X-Astra native check, which classify.ts owns):\n * SD-JWT/VI → RFC 9421 (Agent Pay / TAP / Web Bot Auth by kid namespace or\n * Signature-Agent) → ACP HMAC → UCP session → AP2 body triple → MPP → x402.\n * Returns undefined when nothing commerce-shaped is on the wire.\n *\n * When the body was truncated by CloudFront (`inputTruncated`), body-bound\n * artifacts still forward what arrived but carry a `bodyTruncated` evidence\n * flag — the backend downgrades those signatures rather than hard-failing.\n */\nexport function detectCommerce(\n request: CloudFrontRequest,\n host: string,\n body: DecodedBody\n): DetectedCommerce | undefined {\n const url = requestUrl(request, host);\n const method = request.method;\n const headers = flattenHeaders(request.headers);\n const jsonBody = parseJsonBody(body);\n const truncated = body.truncated ? { bodyTruncated: true } : {};\n\n // --- VI / SD-JWT credential in a header ------------------------------\n const authHeader = getHeader(request, 'authorization');\n const bearer = authHeader?.replace(/^Bearer\\s+/i, '');\n const mandateHeader =\n getHeader(request, 'x-payment-mandate') ?? getHeader(request, 'payment-mandate');\n const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));\n if (sdJwtCandidate) {\n const typ = sniffJwtHeader(sdJwtCandidate)?.typ;\n return {\n protocol: 'vi-sd-jwt',\n artifacts: { viSdJwt: sdJwtCandidate },\n evidence: { typ, ...truncated },\n };\n }\n\n // --- RFC 9421 (Agent Pay / TAP / Web Bot Auth) ------------------------\n const signature = getHeader(request, 'signature');\n const signatureInput = getHeader(request, 'signature-input');\n if (signature && signatureInput) {\n const signatureAgent = getHeader(request, 'signature-agent');\n const registryHint = getHeader(request, 'x-agent-registry');\n const lowerInput = signatureInput.toLowerCase();\n const protocol = signatureAgent\n ? 'rfc9421-web-bot-auth'\n : registryHint?.toLowerCase().includes('visa') || lowerInput.includes('visa')\n ? 'rfc9421-tap'\n : registryHint?.toLowerCase().includes('mastercard') || lowerInput.includes('mastercard')\n ? 'rfc9421-agent-pay'\n : 'rfc9421';\n return {\n protocol,\n artifacts: {\n rfc9421: { headers, method, url, ...(body.text && { body: body.text }) },\n },\n evidence: {\n ...(signatureAgent && { signatureAgent }),\n ...(registryHint && { registryHint }),\n keyid: signatureInput.match(/keyid=\"([^\"]+)\"/)?.[1],\n ...truncated,\n },\n };\n }\n\n // --- ACP (HMAC-signed webhook/checkout: signature WITHOUT signature-input)\n const acpTimestamp = getHeader(request, 'timestamp');\n if (signature && !signatureInput && (acpTimestamp || getHeader(request, 'idempotency-key'))) {\n return {\n protocol: 'acp',\n artifacts: {\n acpRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated },\n };\n }\n\n // --- UCP checkout session ---------------------------------------------\n if (/\\/checkout[-_]sessions(\\/|$)/.test(request.uri)) {\n return {\n protocol: 'ucp',\n artifacts: { ucpRequest: { method, url, ...(jsonBody && { body: jsonBody }) } },\n evidence: { path: request.uri, ...truncated },\n };\n }\n\n // --- AP2 mandate triple in the body -----------------------------------\n if (jsonBody) {\n const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;\n const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;\n const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;\n if (typeof intent === 'string' || typeof cart === 'string' || typeof payment === 'string') {\n return {\n protocol: 'ap2',\n artifacts: {\n ap2Mandates: {\n ...(typeof intent === 'string' && { intent }),\n ...(typeof cart === 'string' && { cart }),\n ...(typeof payment === 'string' && { payment }),\n },\n },\n evidence: {\n mandatesPresent: [\n typeof intent === 'string' && 'intent',\n typeof cart === 'string' && 'cart',\n typeof payment === 'string' && 'payment',\n ].filter(Boolean),\n ...truncated,\n },\n };\n }\n }\n\n // --- MPP (`Authorization: Payment <credential>`) -----------------------\n if (authHeader && /^Payment\\s+/i.test(authHeader)) {\n return {\n protocol: 'mpp',\n artifacts: {\n mppRequest: {\n method,\n url,\n headers,\n ...(body.text && { rawBody: body.text }),\n ...(jsonBody && { body: jsonBody }),\n },\n },\n evidence: truncated,\n };\n }\n\n // --- x402 (X-PAYMENT header) ------------------------------------------\n if (getHeader(request, 'x-payment')) {\n return {\n protocol: 'x402',\n artifacts: {\n x402Request: { method, url, headers, ...(jsonBody && { body: jsonBody }) },\n },\n evidence: truncated,\n };\n }\n\n return undefined;\n}\n","/**\n * Depth-controlled verification per tier. The edge never verifies\n * credentials itself — it forwards what it detected to verify-access, the\n * canonical sole verification sink (backend Step 0.5 runs the commerce\n * pipeline, records events, provisions orphans, persists sessions). What\n * the depth setting controls is how much the edge LOOKS and how much it\n * FORWARDS:\n *\n * classify — what is it? UA tiers only. Zero verify-access calls;\n * beacons only.\n * authenticate — who is it? + protocol detection. X-Astra agents get a\n * verify-access identity check; commerce/platform traffic\n * is beaconed with protocol + evidence (no signature\n * verification anywhere).\n * authorize — are they allowed? + artifact forwarding. X-Astra verify\n * calls carry commerceArtifacts; identified traffic gets an\n * anonymous verify-access call with artifacts +\n * callerMetadata so the backend cryptographically proves\n * and policy-evaluates once.\n */\n\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { verify, extractCredentials } from '@astrasyncai/verification-gateway/verify';\nimport { resolveHttpPdlss } from '@astrasyncai/verification-gateway/http-pdlss';\nimport type { GatewayConfig, VerificationRequest } from '@astrasyncai/verification-gateway';\nimport { flattenHeaders, getHeader, buildObservedMetadata } from './cf';\nimport { withBudget, emitBeacon, sampled } from './events';\nimport type { Classification, EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\nfunction baseOutcome(classification: Classification): TierOutcome {\n return {\n tier: classification.tier,\n decision: 'allow',\n reasons: [],\n protocol: classification.protocol,\n };\n}\n\nfunction buildVerificationRequest(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n includeArtifacts: boolean\n): VerificationRequest {\n const headers = flattenHeaders(request.headers);\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n // verify-access REQUIRES a purpose. Resolve via the shared §4.6 chain:\n // the agent's X-Astra-Purpose/-Action declarations, else the pinned\n // method table (GET → data/data.read etc.) — a transport verb never\n // travels as a PDLSS action.\n const pdlss = resolveHttpPdlss({\n method: request.method,\n astraPurpose: getHeader(request, 'x-astra-purpose'),\n astraAction: getHeader(request, 'x-astra-action'),\n });\n // Trust Record (§33.5 #3): forward the caller's attempt-chain handle when\n // well-formed (agent-declared, like x-astra-purpose — not a trust header,\n // so no spoof-strip needed). The edge synthesises NO consideration data —\n // it can't see offer semantics; pure pass-through.\n const attemptId = getHeader(request, 'x-astra-attempt-id');\n return {\n ...(attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId }),\n credentials: extractCredentials(headers, {}),\n purpose: pdlss.purpose,\n action: pdlss.action,\n resource: request.uri,\n createSession: true,\n counterpartyType: 'website',\n counterpartyUrl: options.counterpartyUrl,\n callerMetadata: {\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n referer: getHeader(request, 'referer'),\n host: getHeader(request, 'host'),\n // Workstream D — the full sanitised header + connection capture. The\n // backend stores it fire-and-forget (zero decision latency) and uses the\n // key-format / platform headers for attribution.\n observedMetadata: buildObservedMetadata(request),\n },\n ...(includeArtifacts &&\n classification.artifacts && { commerceArtifacts: classification.artifacts }),\n };\n}\n\nfunction outcomeFromVerifyResult(\n classification: Classification,\n result: Awaited<ReturnType<typeof verify>>\n): TierOutcome {\n const outcome = baseOutcome(classification);\n outcome.sessionId = (result as { sessionId?: string }).sessionId;\n outcome.correlationId = result.correlationId;\n outcome.guidance = result.guidance;\n\n if (result.requiresStepUp || result.stepUpApproval) {\n outcome.decision = 'manual_review';\n outcome.reasons = ['step-up approval required'];\n outcome.stepUp = {\n pollUrl: (result.stepUpApproval as { pollUrl?: string } | undefined)?.pollUrl,\n expiresAt: (result.stepUpApproval as { expiresAt?: string } | undefined)?.expiresAt,\n };\n return outcome;\n }\n\n if (!result.identityVerified || !result.policyAllowed) {\n outcome.decision = 'deny';\n outcome.reasons = result.denialReasons?.length\n ? result.denialReasons\n : [!result.identityVerified ? 'identity not verified' : 'denied by access policy'];\n return outcome;\n }\n\n outcome.asat = {\n trustScore: result.agent?.trustScore,\n agentId: result.agent?.astraId,\n developerId: result.developer?.astradId,\n accessLevel: result.accessLevel,\n };\n return outcome;\n}\n\n/**\n * Run the tier-appropriate verification/telemetry for one classified\n * request. NEVER throws; on any failure returns an `allow` outcome with the\n * failure recorded in `reasons` (infra failures fail open — a presented\n * credential the BACKEND rejected is a deny, but an unreachable backend is\n * not a rejection).\n */\nexport async function runTier(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n policy: EffectivePolicy,\n apiKey: string | undefined,\n sampling: { anonymousBeaconRate: number }\n): Promise<TierOutcome> {\n const budgets = options.budgets ?? {};\n const beaconMs = budgets.beaconMs ?? 300;\n const verifyMs =\n policy.mode === 'enforce'\n ? (budgets.verifyEnforceMs ?? 3000)\n : (budgets.verifyObserveMs ?? 1500);\n\n const gatewayConfig: GatewayConfig = {\n apiBaseUrl: options.apiBaseUrl,\n ...(apiKey && { apiKey }),\n counterpartyId: options.counterpartyId,\n // The shell handles its own error semantics; init self-probes don't\n // belong in a per-request edge function.\n disableInitChecks: true,\n } as GatewayConfig;\n\n try {\n switch (classification.tier) {\n case 'verified': {\n // classify depth = zero API calls, even for credentialed agents.\n if (policy.depth === 'classify') {\n return baseOutcome(classification);\n }\n const result = await withBudget(\n verify(\n gatewayConfig,\n buildVerificationRequest(options, request, classification, policy.depth === 'authorize')\n ),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n\n case 'identified': {\n if (policy.depth === 'authorize' && classification.artifacts) {\n // Anonymous verify-access call WITH artifacts: the backend runs\n // the commerce pipeline, records unverified events, and\n // provisions orphan platform agents — one sink, recorded once.\n const result = await withBudget(\n verify(gatewayConfig, buildVerificationRequest(options, request, classification, true)),\n verifyMs\n );\n if (!result) {\n const outcome = baseOutcome(classification);\n outcome.reasons = ['verify-access unreachable within budget — fail-open'];\n return outcome;\n }\n return outcomeFromVerifyResult(classification, result);\n }\n // classify/credentials depth (or no artifacts): lightweight beacon.\n await emitBeacon(options, request, classification, beaconMs);\n const outcome = baseOutcome(classification);\n if (policy.mode === 'enforce' && policy.depth !== 'classify') {\n // Unregistered agent on an enforced path: deny with guidance.\n outcome.decision = 'deny';\n outcome.reasons = ['agent is not registered with AstraSync'];\n }\n return outcome;\n }\n\n case 'anonymous-bot': {\n if (sampled(sampling.anonymousBeaconRate, options.random)) {\n await emitBeacon(\n options,\n request,\n { ...classification, protocol: classification.protocol ?? 'ua-heuristic' },\n beaconMs\n );\n }\n // Anonymous bots pass through even in enforce mode — enforce gates\n // AGENT traffic; generic bot management stays the CDN/WAF's job\n // (mixed-traffic classification §5.1.7 is the enforce-mode\n // prerequisite tracked as §33.5 #9).\n return baseOutcome(classification);\n }\n\n default:\n return baseOutcome(classification);\n }\n } catch (err) {\n const outcome = baseOutcome(classification);\n outcome.reasons = [\n `edge pipeline error — fail-open: ${err instanceof Error ? err.message : String(err)}`,\n ];\n return outcome;\n }\n}\n","/**\n * Time-budgeted event emission.\n *\n * Lambda@Edge has no `waitUntil` — anything not awaited before the handler\n * returns may never run (the container freezes). So every network call is\n * awaited under an explicit budget and DROPPED on timeout: latency to the\n * customer's traffic is bounded, and a slow AstraSync API costs telemetry,\n * never page loads.\n */\n\nimport { reportUnregisteredAttempt } from '@astrasyncai/verification-gateway/verify';\nimport type { CloudFrontRequest } from 'aws-lambda';\nimport { getHeader, buildObservedMetadata } from './cf';\nimport type { Classification, EdgeAdapterOptions } 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\n * (CSRF-exempt on the backend); the backend fingerprints the UA and\n * find-or-provisions orphan platform agents server-side.\n */\nexport async function emitBeacon(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n classification: Classification,\n budgetMs: number\n): Promise<void> {\n const clientIp = getHeader(request, 'cloudfront-viewer-address')?.split(':')[0];\n await withBudget(\n reportUnregisteredAttempt(\n { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },\n {\n counterpartyUrl: options.counterpartyUrl,\n counterpartyType: 'website',\n sourceIp: clientIp,\n userAgent: getHeader(request, 'user-agent'),\n requestPath: request.uri,\n requestMethod: request.method,\n // 3.9.0 evidence fields (backend persists them into eventData).\n protocol: classification.protocol,\n evidence: classification.evidence,\n // Workstream D — full sanitised header + connection capture for the\n // unregistered caller (fire-and-forget, so free).\n observedMetadata: buildObservedMetadata(request),\n }\n ),\n budgetMs\n );\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 * §7.4.6 — protocol-specific machine-readable messaging for enforce-mode\n * responses. Agents (not humans) consume these bodies: stable error codes,\n * the failure list, and registration guidance with real URLs.\n */\n\nimport type { TierOutcome } from './types';\n\nconst PROTOCOL_MESSAGES: Record<string, string> = {\n 'vi-sd-jwt':\n 'This request presented Visa Intelligent Commerce credentials, but the agent is not verified with AstraSync. Register the agent to pair your VI credentials with a verified identity and mandate.',\n 'rfc9421-agent-pay':\n 'This request carried a Mastercard Agent Pay signature, but the agent is not verified with AstraSync. Register the agent to pair Agent Pay credentials with a verified identity and mandate.',\n 'rfc9421-tap':\n 'This request carried a Visa TAP signature, but the agent is not verified with AstraSync. Register the agent to pair TAP credentials with a verified identity and mandate.',\n 'rfc9421-web-bot-auth':\n 'This request carried a Web Bot Auth signature, but the agent is not verified with AstraSync. Register the agent to link your signed-agent identity to a verified principal.',\n rfc9421:\n 'This request carried an RFC 9421 HTTP message signature, but the agent is not verified with AstraSync. Register the agent to link the signing identity to a verified principal.',\n acp: 'This request used the Agentic Commerce Protocol, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ucp: 'This request used a UCP checkout session, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n ap2: 'This request presented AP2 mandates, but the agent is not verified with AstraSync. Register the agent to pair your mandates with a verified identity.',\n mpp: 'This request presented MPP payment credentials, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n x402: 'This request used x402 payment headers, but the agent is not verified with AstraSync. Register the agent to transact on this property.',\n 'platform-ua':\n 'This traffic was identified as a platform AI agent without AstraSync credentials. Register the agent to access this property with a verified identity.',\n 'x-astra':\n 'The presented AstraSync credentials failed verification or were denied by this property’s access policy.',\n};\n\nexport interface DenyBody {\n success: false;\n error: {\n code: 'UNAUTHORIZED' | 'INSUFFICIENT_ACCESS';\n message: string;\n protocol?: string;\n failures: string[];\n correlationId?: string;\n guidance: {\n message?: string;\n registrationUrl?: string;\n documentationUrl?: string;\n };\n };\n}\n\nexport function buildDenyBody(outcome: TierOutcome, apiBaseUrl: string): DenyBody {\n const origin = apiBaseUrl.replace(/\\/api\\/?$/, '');\n const protocolMessage =\n (outcome.protocol && PROTOCOL_MESSAGES[outcome.protocol]) ??\n 'This request could not be verified by AstraSync.';\n return {\n success: false,\n error: {\n // UNAUTHORIZED = identity failed (register/re-authenticate helps);\n // INSUFFICIENT_ACCESS = identity fine, policy denied (fix the mandate).\n code: outcome.tier === 'verified' ? 'INSUFFICIENT_ACCESS' : 'UNAUTHORIZED',\n message: protocolMessage,\n ...(outcome.protocol && { protocol: outcome.protocol }),\n failures: outcome.reasons,\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n guidance: {\n // `||` not `??`: verify() fills these with EMPTY STRINGS when the\n // well-known cache is cold — empty means \"use the fallback\".\n message:\n outcome.guidance?.message ||\n 'Register this agent with AstraSync to receive verifiable credentials.',\n registrationUrl: outcome.guidance?.registrationUrl || `${origin}/register`,\n documentationUrl: outcome.guidance?.documentationUrl || `${origin}/docs/edge-adapter`,\n },\n },\n };\n}\n\nexport interface ManualReviewBody {\n success: false;\n status: 'manual_review';\n message: string;\n stepUpApproval?: { pollUrl?: string; expiresAt?: string };\n correlationId?: string;\n}\n\nexport function buildManualReviewBody(outcome: TierOutcome): ManualReviewBody {\n return {\n success: false,\n status: 'manual_review',\n message:\n 'This action requires human approval. Poll the step-up approval endpoint and retry once approved.',\n ...(outcome.stepUp && { stepUpApproval: outcome.stepUp }),\n ...(outcome.correlationId && { correlationId: outcome.correlationId }),\n };\n}\n","/**\n * Decision → CloudFront result wiring (§7.4 enforcement, §7.4.7 ASAT\n * headers). Executed in BOTH modes so observe mode records exactly what\n * enforce mode would have done — but only enforce mode is allowed to return\n * anything other than the origin-bound request.\n */\n\nimport type { CloudFrontRequest, CloudFrontRequestResult } from 'aws-lambda';\nimport { jsonResponse, setHeader, stripHeadersByPrefix } from './cf';\nimport { buildDenyBody, buildManualReviewBody } from './messaging';\nimport type { EdgeAdapterOptions, EffectivePolicy, TierOutcome } from './types';\n\n/** §7.4.7 ASAT trust-attestation headers injected on allowed requests. */\nexport const ASAT_HEADERS = {\n trustScore: 'X-AstraSync-Trust-Score',\n agentId: 'X-AstraSync-Agent-Id',\n developerId: 'X-AstraSync-Developer-Id',\n permissions: 'X-AstraSync-Permissions',\n observedDecision: 'X-AstraSync-Observed-Decision',\n} as const;\n\n/**\n * Apply the outcome. Always strips inbound spoofed `x-astrasync-*` headers\n * first (both modes — trust headers must only ever originate here).\n *\n * Observe mode: returns the request untouched apart from header hygiene and\n * an `X-AstraSync-Observed-Decision` stamp for origin-side log correlation.\n *\n * Enforce mode: ALLOW → request + ASAT headers; DENY → 403 machine-readable\n * body; MANUAL_REVIEW → 202 with step-up poll info.\n */\nexport function applyOutcome(\n options: EdgeAdapterOptions,\n request: CloudFrontRequest,\n outcome: TierOutcome,\n policy: EffectivePolicy\n): CloudFrontRequestResult {\n stripHeadersByPrefix(request, 'x-astrasync-');\n\n if (policy.mode !== 'enforce') {\n // Shadow stamp: what enforce WOULD have done, visible in origin logs.\n if (outcome.decision !== 'allow') {\n setHeader(request, ASAT_HEADERS.observedDecision, outcome.decision);\n }\n injectAsat(request, outcome);\n return request;\n }\n\n switch (outcome.decision) {\n case 'deny':\n return jsonResponse(403, buildDenyBody(outcome, options.apiBaseUrl));\n case 'manual_review':\n return jsonResponse(202, buildManualReviewBody(outcome), {\n 'Retry-After': '30',\n });\n default:\n injectAsat(request, outcome);\n return request;\n }\n}\n\nfunction injectAsat(request: CloudFrontRequest, outcome: TierOutcome): void {\n if (!outcome.asat) return;\n const { trustScore, agentId, developerId, accessLevel } = outcome.asat;\n if (trustScore !== undefined) {\n setHeader(request, ASAT_HEADERS.trustScore, String(trustScore));\n }\n if (agentId) setHeader(request, ASAT_HEADERS.agentId, agentId);\n if (developerId) setHeader(request, ASAT_HEADERS.developerId, developerId);\n if (accessLevel) setHeader(request, ASAT_HEADERS.permissions, accessLevel);\n}\n","/**\n * Commerce Shield edge shell — Lambda@Edge origin-request handler factory\n * (§7.4 / §33.5 #1).\n *\n * Composition per request:\n * config (cached) → path policy → classify → tier pipeline → apply outcome\n *\n * THE invariant (tested): outside enforce mode the handler ALWAYS returns\n * the origin-bound request — any error, timeout, or misconfiguration\n * results in pass-through. A top-level catch guarantees it even against\n * bugs in the shell itself.\n */\n\nimport type { CloudFrontRequestEvent, CloudFrontRequestResult } from 'aws-lambda';\nimport { getRequest, getHeader, normalizeOriginHost } from './cf';\nimport { resolveApiKey, loadEdgeConfig } from './config';\nimport { classify, resolvePolicy } from './classify';\nimport { runTier } from './pipeline';\nimport { applyOutcome } from './enforce';\nimport type { EdgeAdapterOptions } from './types';\n\nexport type EdgeHandler = (event: CloudFrontRequestEvent) => Promise<CloudFrontRequestResult>;\n\nexport function createEdgeHandler(options: EdgeAdapterOptions): EdgeHandler {\n const log =\n options.log ??\n ((level, message, data) => {\n // Lambda@Edge writes console output to the regional CloudWatch log\n // group of whichever edge location served the request.\n console[level === 'info' ? 'log' : level](`[astrasync-edge] ${message}`, data ?? '');\n });\n\n return async function handler(event) {\n const request = getRequest(event);\n try {\n // Own the Host rewrite (Workstream D): the CloudFront-Viewer-* capture\n // requires an origin-request policy that also forwards the viewer Host,\n // so the shell restores origin-domain Host + X-Forwarded-Host itself.\n // Runs first so EVERY origin-bound return (skip / human / allow) is\n // correctly routed.\n normalizeOriginHost(request);\n\n const apiKey = await resolveApiKey({ ...options, log });\n const config = await loadEdgeConfig(options, apiKey);\n const policy = resolvePolicy(config, request.uri);\n\n // Skipped paths (static assets / skip rules): untouched, zero work.\n if (policy.skip) return request;\n\n const host =\n getHeader(request, 'x-forwarded-host') ??\n getHeader(request, 'host') ??\n new URL(options.counterpartyUrl).host;\n\n const classification = classify(request, host, policy.depth);\n\n // Humans: get out of the way. No calls, no logs, no header changes\n // beyond nothing at all.\n if (classification.tier === 'human') return request;\n\n const outcome = await runTier(\n { ...options, log },\n request,\n classification,\n policy,\n apiKey,\n config.sampling\n );\n\n if (outcome.decision !== 'allow') {\n log(\n 'info',\n policy.mode === 'enforce'\n ? `${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`\n : `[OBSERVE] would have been ${outcome.decision.toUpperCase()}: ${request.method} ${request.uri}`,\n { tier: outcome.tier, protocol: outcome.protocol, reasons: outcome.reasons }\n );\n }\n\n return applyOutcome(options, request, outcome, policy);\n } catch (err) {\n // Fail-open, unconditionally: the shell must never take the site down.\n log('error', 'edge handler error — passing request through', {\n error: err instanceof Error ? err.message : String(err),\n });\n return request;\n }\n };\n}\n"],"mappings":"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","names":["sanitizeHeaders","sanitizeHeaders","extractCredentials","extractCredentials","outcome"]}
@@ -1 +1 @@
1
- "use strict";var Ce=Object.create;var T=Object.defineProperty;var Se=Object.getOwnPropertyDescriptor;var Te=Object.getOwnPropertyNames;var be=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var Ie=(e,t)=>{for(var r in t)T(e,r,{get:t[r],enumerable:!0})},M=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Te(t))!Ee.call(e,a)&&a!==r&&T(e,a,{get:()=>t[a],enumerable:!(n=Se(t,a))||n.enumerable});return e};var Pe=(e,t,r)=>(r=e!=null?Ce(be(e)):{},M(t||!e||!e.__esModule?T(r,"default",{value:e,enumerable:!0}):r,e)),Ue=e=>M(T({},"__esModule",{value:!0}),e);var St={};Ie(St,{handler:()=>Ct});module.exports=Ue(St);var xe=new Set(["cookie","set-cookie","x-csrf-token","proxy-authorization","x-astrasync-signature","x-astrasync-secret","x-hub-signature","x-hub-signature-256"]),_e=["x-astrasync-","kya-","kya_"],Oe=new Set(["authorization","x-api-key","x-goog-api-key","api-key"]);function ke(e){return e==="signature"||e.endsWith("-signature")||e.endsWith("-signature-256")}var Fe=new Set(["openai-organization","openai-project","openai-version","openai-processing-ms","anthropic-version","anthropic-beta","x-goog-user-project","x-goog-api-client","user-agent","x-agent-card-url","x-agent-provider"]),Be=["x-goog-","x-stainless-","x-anthropic-","x-openai-"],He=["sk-ant-api03","sk-ant-api","sk-ant","sk-proj","sk-svcacct","sk-or-v1","sk-or","sk-lf","sk-","gsk_","aiza","ya29","ghp_","gho_","github_pat_","xai-","pplx-","r8_","hf_","astra-","astrae-"],Me=64,D=1024,De=16*1024;function U(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);n<128?t+=1:n<2048?t+=2:n>=55296&&n<=56319?(t+=4,r++):t+=3}return t}function Ne(e){if(!e)return;let t=e.trim(),r=t.indexOf(" ");if(r>0){let a=t.slice(0,r).toLowerCase();(a==="bearer"||a==="basic"||a==="token")&&(t=t.slice(r+1).trim())}let n=t.toLowerCase();for(let a of He)if(n.startsWith(a))return a}function Le(e){return!!(xe.has(e)||_e.some(t=>e.startsWith(t))||ke(e))}function je(e){return Fe.has(e)?!0:Be.some(t=>e.startsWith(t))}function b(e){let t={},r={},n,a=0,i=0;if(!e)return{headers:t};for(let s of Object.keys(e)){if(i>=Me)break;let l=s.toLowerCase(),f=e[s];if(f===void 0)continue;let d=Array.isArray(f)?f.join(", "):String(f);if(Oe.has(l)){let h=Ne(d);h&&!n&&(n=h);continue}if(Le(l))continue;let u=d;U(u)>D&&(u=u.slice(0,D));let m=U(l)+U(u);a+m>De||(a+=m,i++,t[l]=u,je(l)&&(r[l]=u))}let o={headers:t};return n&&(o.apiKeyFormat=n),Object.keys(r).length>0&&(o.platformHeaders=r),o}function N(e){return e.Records[0].cf.request}function c(e,t){return e.headers[t.toLowerCase()]?.[0]?.value}function R(e){let t={};for(let[r,n]of Object.entries(e))n?.length&&(t[r]=n.length===1?n[0].value:n.map(a=>a.value));return t}function L(e){let t=e.body;return t?.data?{text:t.encoding==="base64"?Buffer.from(t.data,"base64").toString("utf8"):t.data,truncated:t.inputTruncated===!0}:{truncated:!1}}function Ke(e){let t={},r=(i,o,s)=>{let l=c(e,o);l&&(t[i]=s?s(l):l)},n=c(e,"cloudfront-viewer-address");n&&(t.ip=n.replace(/:\d+$/,"")),r("country","cloudfront-viewer-country"),r("countryName","cloudfront-viewer-country-name"),r("region","cloudfront-viewer-country-region"),r("city","cloudfront-viewer-city"),r("asn","cloudfront-viewer-asn"),r("tlsVersion","cloudfront-viewer-tls"),r("httpVersion","cloudfront-viewer-http-version");let a=[];for(let[i,o]of[["desktop","cloudfront-is-desktop-viewer"],["mobile","cloudfront-is-mobile-viewer"],["tablet","cloudfront-is-tablet-viewer"],["smarttv","cloudfront-is-smarttv-viewer"]])c(e,o)==="true"&&a.push(i);return a.length&&(t.device=a.join(",")),t}function E(e){let{headers:t,apiKeyFormat:r,platformHeaders:n}=b(R(e.headers)),a=Ke(e);return{headers:t,...r&&{apiKeyFormat:r},...n&&{platformHeaders:n},...Object.keys(a).length>0&&{connection:a}}}function j(e){let t=e.origin?.custom?.domainName??e.origin?.s3?.domainName??void 0;if(!t)return;let r=c(e,"host");!r||r===t||(c(e,"x-forwarded-host")||A(e,"X-Forwarded-Host",r),A(e,"Host",t))}function K(e,t){let r=e.querystring?`?${e.querystring}`:"";return`https://${t}${e.uri}${r}`}function A(e,t,r){e.headers[t.toLowerCase()]=[{key:t,value:r}]}function $(e,t){let r=t.toLowerCase();for(let n of Object.keys(e.headers))n.startsWith(r)&&delete e.headers[n]}function x(e,t,r){let n={"content-type":[{key:"Content-Type",value:"application/json"}]};for(let[a,i]of Object.entries(r??{}))n[a.toLowerCase()]=[{key:a,value:i}];return{status:String(e),statusDescription:e===403?"Forbidden":e===202?"Accepted":"OK",headers:n,body:JSON.stringify(t)}}var O=Object.freeze({version:1,mode:"observe",depth:"classify",pathRules:[],sampling:Object.freeze({anonymousBeaconRate:.1}),failurePosture:"open"}),V=["observe","enforce"],G=["classify","authenticate","authorize"];function $e(e){if(typeof e!="object"||e===null)return!1;let t=e;if(t.version!==1||!V.includes(t.mode)||!G.includes(t.depth)||!Array.isArray(t.pathRules))return!1;for(let n of t.pathRules){if(typeof n!="object"||n===null)return!1;let a=n;if(typeof a.pattern!="string"||a.pattern.length===0||a.mode!==void 0&&!V.includes(a.mode)||a.depth!==void 0&&!G.includes(a.depth))return!1}let r=t.sampling;return typeof r!="object"||r===null||typeof r.anonymousBeaconRate!="number"||r.anonymousBeaconRate<0||r.anonymousBeaconRate>1?!1:t.failurePosture==="open"}async function Ve(e,t,r){if(!t)return null;let n={Accept:"application/json"};e.apiKey&&(n.Authorization=`Bearer ${e.apiKey}`,n["X-API-Key"]=e.apiKey),r?.etag&&(n["If-None-Match"]=r.etag);try{let a=await fetch(`${e.apiBaseUrl}/endpoints/${encodeURIComponent(t)}/edge-config`,{method:"GET",headers:n,signal:AbortSignal.timeout(r?.timeoutMs??5e3)});if(a.status===304)return{notModified:!0};if(!a.ok)return null;let o=(await a.json()).data?.edgeConfig;return $e(o)?{edgeConfig:o,etag:a.headers.get("etag")??void 0}:null}catch{return null}}var Ge=60*1e3,ze=1440*60*1e3,C=new Map,_=new Map;function X(e,t){return`${e}|${t}`}function Xe(e){return e.mode!=="enforce"&&!e.pathRules.some(t=>t.mode==="enforce")?e:{...e,mode:"observe",pathRules:e.pathRules.map(t=>t.mode==="enforce"?{...t,mode:"observe"}:t)}}async function z(e,t){let r=X(e.apiBaseUrl,t),n=_.get(r);if(n)return n;let a=Ve(e,t,{etag:C.get(r)?.etag}).then(i=>{if(i===null)return;let o=Date.now();if("notModified"in i){let s=C.get(r);s&&(s.lastSuccessAt=o);return}C.set(r,{config:i.edgeConfig,etag:i.etag,lastSuccessAt:o})}).finally(()=>{_.delete(r)});return _.set(r,a),a}async function q(e,t,r){let n=r?.ttlMs??Ge,a=r?.maxStaleMs??ze,i=X(e.apiBaseUrl,t),o=C.get(i);if(o){let s=Date.now()-o.lastSuccessAt;return s>n&&z(e,t).catch(()=>{}),s>a?Xe(o.config):o.config}return await z(e,t).catch(()=>{}),C.get(i)?.config??O}function Y(e,t){for(let r of e)if(qe(r.pattern).test(t))return r}function qe(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${t}$`,"i")}var Ye=900*1e3,J=new Map;async function Je(e){let{SecretsManagerClient:t,GetSecretValueCommand:r}=await import("@aws-sdk/client-secrets-manager");return(await new t({region:"us-east-1"}).send(new r({SecretId:e}))).SecretString??void 0}async function W(e){if(e.apiKey)return e.apiKey;let t=e.apiKeySecretName;if(!t)return;let r=J.get(t);if(r&&Date.now()-r.fetchedAt<Ye)return r.value;try{let a=await(e.fetchSecret??Je)(t);return J.set(t,{value:a,fetchedAt:Date.now()}),a}catch(n){return e.log?.("warn","Secrets Manager fetch failed \u2014 continuing keyless",{secretName:t,error:n instanceof Error?n.message:String(n)}),r?.value}}async function Z(e,t){try{return await q({apiBaseUrl:e.apiBaseUrl,apiKey:t},e.counterpartyId,{ttlMs:e.configTtlMs})}catch{return e.fallbackConfig??O}}function We(e){return e>=80?"PLATINUM":e>=60?"GOLD":e>=40?"SILVER":"BRONZE"}var Ze="3.10.0",_t=3600*1e3,Qe=new Map;function et(e){return Qe.get(e)?.data}var te={apiBaseUrl:"https://astrasync.ai/api",defaultAccessLevel:"none",debug:!1},re=!1,Q=!1;async function ee(e,t,r){re=!0;try{let n=`${e}/agents/verify-access`,i=(await fetch(n,{method:"HEAD"})).headers.get("content-type")??"";if(i.startsWith("text/html")){let o=`[VerificationGateway] apiBaseUrl '${e}' returned HTML (content-type: ${i}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;if(r)throw new Error(`${o} (strictInit=true)`);console.warn(`${o} Set disableInitChecks: true on GatewayConfig to silence.`)}else t&&console.log(`[VerificationGateway] init check passed for ${e} (content-type: ${i})`)}catch(n){if(r)throw n;t&&console.log(`[VerificationGateway] init check failed (non-blocking): ${String(n)}`)}}var k=new Map;function ne(e,t){let r=e.credentials;return[r.astraId||"",r.apiKey||"",r.jwt||"",e.purpose||"",e.action||"",e.resourceType||"",e.resource||"",e.jurisdiction||"",e.transactionValue??"",e.currency||"",t||"",e.counterpartyUrl||"",e.counterpartyType||"",e.isSubAgentRequest?"1":"0",e.parentAgentId||"",e.subAgentDepth??"",e.durationRequired??"",e.invocationProtocol||"",e.enableRuntimeChallenge?"1":"0",e.callerMetadata?.sourceIp||"",e.callerMetadata?.userAgent||"",e.callerMetadata?.forwardedFor||"",e.callerMetadata?.agentCardUrl||""].join("|")}function tt(e,t){let r=ne(e,t),n=k.get(r);return n&&n.expiresAt>Date.now()?n.result:(n&&k.delete(r),null)}var rt=60;function nt(e,t,r,n){let a=r&&r>0?r:rt,i=ne(e,n);k.set(i,{result:t,expiresAt:Date.now()+a*1e3})}function I(e,t){let r={},n=/^ASTRAE?-[A-Za-z0-9_-]{1,64}$/,a=e["x-astra-id"]||e["X-Astra-Id"]||e["X-ASTRA-ID"]||e["x-astra-agentid"]||e["X-Astra-AgentId"]||e["x-astra-agent-id"]||e["X-Astra-Agent-Id"]||e["X-ASTRA-AGENT-ID"];if(a){let s=Array.isArray(a)?a[0]:typeof a=="string"?a:void 0;typeof s=="string"&&n.test(s)&&(r.astraId=s)}let i=e["x-api-key"]||e["X-Api-Key"]||e["X-API-KEY"];i&&(r.apiKey=Array.isArray(i)?i[0]:i);let o=e.authorization||e.Authorization;if(o){let s=Array.isArray(o)?o[0]:o;typeof s=="string"&&(r.authorizationHeader=s,s.startsWith("Bearer ")&&(r.jwt=s.slice(7)))}return t&&(t.astraId&&!r.astraId&&(r.astraId=t.astraId),t.apiKey&&!r.apiKey&&(r.apiKey=t.apiKey)),r}function at(e,t,r={}){let a=(r.source??"no_credentials")==="api_error",i=r.urls,o=a?{message:"Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",registrationUrl:i?.registrationUrl??"",documentationUrl:i?.documentationUrl??"",steps:["Retry the request with exponential backoff","If failures persist, share the correlationId with support"]}:{message:"This service verifies AI agents before granting access. Please register your agent with AstraSync.",registrationUrl:i?.registrationUrl??"",documentationUrl:i?.documentationUrl??"",steps:["Register for an AstraSync account","Create and register your agent","Add your ASTRA-ID to request headers","Retry your request"]};return{identityVerified:!1,policyAllowed:!1,accessLevel:"none",guidance:o,denialReasons:t?[t]:["No valid agent credentials provided"],failures:a?[{dimension:"verify_access.api_error",message:t??"Verification temporarily unavailable",guidance:o.message}]:void 0,correlationId:r.correlationId,verifiedAt:new Date}}async function ot(e,t){let{credentials:r,...n}=t,a={...r.astraId&&{agentId:r.astraId},...n.purpose&&{purpose:n.purpose}};if(n.action&&(a.action=n.action),n.resourceType&&(a.resourceType=n.resourceType),n.resource&&(a.resource=n.resource),n.jurisdiction&&(a.jurisdiction=n.jurisdiction),n.transactionValue&&(a.transactionValue=n.transactionValue),n.currency&&(a.currency=n.currency),n.isSubAgentRequest&&(a.isSubAgentRequest=n.isSubAgentRequest),n.parentAgentId&&(a.parentAgentId=n.parentAgentId),n.subAgentDepth!==void 0&&(a.subAgentDepth=n.subAgentDepth),n.enableRuntimeChallenge&&(a.enableRuntimeChallenge=n.enableRuntimeChallenge),n.createSession&&(a.createSession=n.createSession),n.durationRequired&&(a.durationRequired=n.durationRequired),n.counterpartyType&&(a.counterpartyType=n.counterpartyType),n.counterpartyUrl&&(a.counterpartyUrl=n.counterpartyUrl),e.counterpartyId&&(a.counterpartyId=e.counterpartyId),n.runtimeChallengeOptions&&(a.runtimeChallengeOptions=n.runtimeChallengeOptions),n.invocationProtocol&&(a.invocationProtocol=n.invocationProtocol),n.commerceArtifacts&&(a.commerceArtifacts=n.commerceArtifacts),a.sdkVersion=Ze,n.callerMetadata||n.clientIp||n.userAgent){let o={...n.clientIp&&{sourceIp:n.clientIp},...n.userAgent&&{userAgent:n.userAgent},...n.callerMetadata};Object.keys(o).length>0&&(a.callerMetadata=o)}let i={"Content-Type":"application/json",...e.customHeaders};e.apiKey&&(i.Authorization=`Bearer ${e.apiKey}`,i["X-API-Key"]=e.apiKey);try{let o=await fetch(`${e.apiBaseUrl}/agents/verify-access`,{method:"POST",headers:i,body:JSON.stringify(a)}),s=await o.json();return o.status===410?{success:!0,access:{allowed:!1,accessLevel:"none",reason:"endpoint_deactivated",failures:[{dimension:"endpoint.deactivated",message:typeof s?.message=="string"?s.message:"Endpoint has been deactivated",guidance:typeof s?.guidance=="string"?s.guidance:"Reactivate via POST /api/endpoints/{id}/reactivate, or update the URL on the calling agent."}]}}:o.ok?s:{success:!1,error:s.message||s.error||`API returned ${o.status}`,correlationId:typeof s?.correlationId=="string"?s.correlationId:void 0}}catch(o){return{success:!1,error:`Failed to call verify-access API: ${o instanceof Error?o.message:"Unknown error"}`}}}async function F(e,t,r){let n={...te,...e},a=n.apiBaseUrl?et(n.apiBaseUrl):void 0;if(!re&&!n.disableInitChecks&&n.apiBaseUrl&&(n.strictInit?await ee(n.apiBaseUrl,n.debug,!0):ee(n.apiBaseUrl,n.debug,!1)),!Q&&(e.minTrustScore!==void 0||e.minTrustScoreForFull!==void 0)&&(Q=!0,console.warn("[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access-level decisions (the SDK reads access.accessLevel from the verify-access response). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side.")),n.cacheTtl!==0&&!r?.bypassCache){let g=tt(t,n.counterpartyId);if(g)return n.debug&&console.log("[VerificationGateway] Returning cached result"),g}let i={...t};!i.counterpartyUrl&&n.counterpartyUrl&&(i.counterpartyUrl=n.counterpartyUrl),!i.counterpartyType&&n.counterpartyType&&(i.counterpartyType=n.counterpartyType),n.debug&&console.log("[VerificationGateway] Calling verify-access API");let o=await ot(n,i),s=o.denialReasons,l=Array.isArray(s)&&s.length>0?s:void 0;if(!o.success)return at(n,o.error,{source:"api_error",correlationId:o.correlationId,urls:a});if(!o.access?.allowed){let g=o.access?.failures;return{identityVerified:o.verificationContext?.idVerified===!0,policyAllowed:!1,accessLevel:"none",denialReasons:l??(g&&g.length>0?g.map(Re=>Re.message):o.access?.reason?[o.access.reason]:["Access denied"]),failures:g,requiresStepUp:o.access?.requiresStepUp,requiresApproval:o.access?.requiresApproval,guidance:{message:o.access?.reason||"Access denied by PDLSS policy",registrationUrl:a?.registrationUrl??"",documentationUrl:a?.documentationUrl??""},verifiedAt:new Date,sessionId:o.sessionId,correlationId:o.correlationId,recommendation:o.recommendation,recommendationReasons:o.recommendationReasons,stepUpApproval:o.stepUpApproval,settlement:o.settlement}}let f=o.agent?{astraId:o.agent.astraId,name:o.agent.name,trustScore:o.agent.trustScore,trustLevel:We(o.agent.trustScore),blockchainVerified:o.agent.blockchainStatus==="verified",status:o.agent.agentStatus}:void 0,d=o.developer?{astradId:o.developer.kyaOwnerId,name:o.developer.fullName,trustScore:o.developer.trustScore||0,verified:o.developer.identityVerified}:void 0,u=o.organization?{name:o.organization.name,verified:o.organization.verified,trustScore:o.organization.trustScore}:void 0,m=o.verificationContext,h=o.access?.accessLevel??"standard",p={identityVerified:o.verificationContext?.idVerified!==!1,policyAllowed:!0,accessLevel:h,agent:f,developer:d,organization:u,appliedPolicy:o.access?.appliedPolicy,verificationContext:m,requiresStepUp:o.access?.requiresStepUp,requiresApproval:o.access?.requiresApproval,verifiedAt:new Date,cacheTtl:n.cacheTtl,sessionId:o.sessionId,correlationId:o.correlationId,runtimeChallenge:o.runtimeChallenge,tokenGuidance:o.tokenGuidance,recommendation:o.recommendation,recommendationReasons:o.recommendationReasons,warningHeader:o.warningHeader,stepUpApproval:o.stepUpApproval,settlement:o.settlement};p.recommendation==="deny"?(p.policyAllowed=!1,p.accessLevel="none",p.denialReasons=l??p.recommendationReasons??["Access denied by AstraSync recommendation"],p.guidance=p.runtimeChallenge?{message:`Verification failed: ${p.runtimeChallenge.reason||"runtime challenge failed"}`,registrationUrl:a?.registrationUrl??"",documentationUrl:a?.documentationUrl??""}:{message:p.recommendationReasons?.[0]||"Access denied by AstraSync recommendation",registrationUrl:a?.registrationUrl??"",documentationUrl:a?.documentationUrl??""}):p.recommendation==="step_up_required"&&(p.requiresStepUp=!0,p.denialReasons=l??p.recommendationReasons??["Step-up verification required"]);let y=p.requiresStepUp===!0||p.requiresApproval===!0||p.recommendation==="step_up_required";return n.cacheTtl!==0&&p.recommendation!=="deny"&&!y&&nt(t,p,n.cacheTtl,n.counterpartyId),p}async function ae(e,t){let r=e.apiBaseUrl||te.apiBaseUrl,{counterpartyUrl:n,...a}=t,i={...a,...n&&{counterpartyUrl:n},...e.counterpartyId&&{counterpartyId:e.counterpartyId}};await fetch(`${r}/verification-activity/unregistered-attempt`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).catch(()=>{})}var it=[{vendor:"claude",displayName:"Anthropic Claude",uaPatterns:[/claude/i,/anthropic/i],agentCardPatterns:[/anthropic\.com/i,/claude\.ai/i],apiKeyFormatPatterns:[/^sk-ant/i],headerPatterns:[/^anthropic-version/i,/^anthropic-beta/i,/^x-anthropic-/i]},{vendor:"chatgpt",displayName:"OpenAI ChatGPT",uaPatterns:[/chatgpt/i,/openai/i,/gpt-?\d/i],agentCardPatterns:[/openai\.com/i,/chatgpt\.com/i],apiKeyFormatPatterns:[/^sk-proj/i,/^sk-svcacct/i],headerPatterns:[/^openai-organization/i,/^openai-project/i,/^openai-version/i]},{vendor:"gemini",displayName:"Google Gemini",uaPatterns:[/gemini/i,/google-gemini/i,/bard/i],agentCardPatterns:[/gemini\.google\.com/i,/ai\.google\.dev/i],apiKeyFormatPatterns:[/^aiza/i],headerPatterns:[/^x-goog-user-project/i,/^x-goog-api-client/i]},{vendor:"cursor",displayName:"Cursor",uaPatterns:[/cursor/i],agentCardPatterns:[/cursor\.sh/i,/cursor\.com/i]},{vendor:"goose",displayName:"Block Goose",uaPatterns:[/goose/i,/block-goose/i],agentCardPatterns:[/block\.xyz\/goose/i,/goose\.tools/i]},{vendor:"perplexity",displayName:"Perplexity",uaPatterns:[/perplexity/i],agentCardPatterns:[/perplexity\.ai/i],apiKeyFormatPatterns:[/^pplx-/i]}];function st(e,t){let r=t.userAgent??"",n=t.agentCardUrl??"",a=t.apiKeyFormat??"",i=[];if(t.platformHeaders)for(let[o,s]of Object.entries(t.platformHeaders))i.push(o,`${o}: ${s}`);for(let o of e){let s=o.uaPatterns?.some(u=>u.test(r)),l=o.agentCardPatterns?.some(u=>u.test(n)),f=a.length>0&&o.apiKeyFormatPatterns?.some(u=>u.test(a)),d=i.length>0&&o.headerPatterns?.some(u=>i.some(m=>u.test(m)));if(s||l||f||d){let u=r.split(/[\s/]/)[0]?.toLowerCase()??"",m=(()=>{try{return n?new URL(n).host:""}catch{return""}})(),h=u||m||a||"unknown";return{vendor:o.vendor,fingerprintKey:`${o.vendor}:${h}`,displayName:o.displayName}}}}function B(e){return st(it,e)}var ct=/^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;function dt(e){try{let t=e.split(".")[0];return JSON.parse(Buffer.from(t,"base64url").toString("utf8"))}catch{return}}function ut(e){if(e.text)try{let t=JSON.parse(e.text);return typeof t=="object"&&t!==null?t:void 0}catch{return}}function oe(e,t,r){let n=K(e,t),a=e.method,i=R(e.headers),o=ut(r),s=r.truncated?{bodyTruncated:!0}:{},l=c(e,"authorization"),f=l?.replace(/^Bearer\s+/i,""),u=[c(e,"x-payment-mandate")??c(e,"payment-mandate"),f].find(y=>y&&ct.test(y));if(u){let y=dt(u)?.typ;return{protocol:"vi-sd-jwt",artifacts:{viSdJwt:u},evidence:{typ:y,...s}}}let m=c(e,"signature"),h=c(e,"signature-input");if(m&&h){let y=c(e,"signature-agent"),g=c(e,"x-agent-registry"),v=h.toLowerCase();return{protocol:y?"rfc9421-web-bot-auth":g?.toLowerCase().includes("visa")||v.includes("visa")?"rfc9421-tap":g?.toLowerCase().includes("mastercard")||v.includes("mastercard")?"rfc9421-agent-pay":"rfc9421",artifacts:{rfc9421:{headers:i,method:a,url:n,...r.text&&{body:r.text}}},evidence:{...y&&{signatureAgent:y},...g&&{registryHint:g},keyid:h.match(/keyid="([^"]+)"/)?.[1],...s}}}let p=c(e,"timestamp");if(m&&!h&&(p||c(e,"idempotency-key")))return{protocol:"acp",artifacts:{acpRequest:{method:a,url:n,headers:i,...r.text&&{rawBody:r.text},...o&&{body:o}}},evidence:{hasTimestamp:!!p,...s}};if(/\/checkout[-_]sessions(\/|$)/.test(e.uri))return{protocol:"ucp",artifacts:{ucpRequest:{method:a,url:n,...o&&{body:o}}},evidence:{path:e.uri,...s}};if(o){let y=o.intent_mandate??o.intentMandate,g=o.cart_mandate??o.cartMandate,v=o.payment_mandate??o.paymentMandate;if(typeof y=="string"||typeof g=="string"||typeof v=="string")return{protocol:"ap2",artifacts:{ap2Mandates:{...typeof y=="string"&&{intent:y},...typeof g=="string"&&{cart:g},...typeof v=="string"&&{payment:v}}},evidence:{mandatesPresent:[typeof y=="string"&&"intent",typeof g=="string"&&"cart",typeof v=="string"&&"payment"].filter(Boolean),...s}}}if(l&&/^Payment\s+/i.test(l))return{protocol:"mpp",artifacts:{mppRequest:{method:a,url:n,headers:i,...r.text&&{rawBody:r.text},...o&&{body:o}}},evidence:s};if(c(e,"x-payment"))return{protocol:"x402",artifacts:{x402Request:{method:a,url:n,headers:i,...o&&{body:o}}},evidence:s}}var lt=/\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i,pt=/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,ft=/mozilla\/\d/i;function ie(e,t){if(lt.test(t))return{mode:e.mode,depth:e.depth,skip:!0};let r=Y(e.pathRules,t);return r?{mode:r.mode??e.mode,depth:r.depth??e.depth,skip:r.skip===!0}:{mode:e.mode,depth:e.depth,skip:!1}}function se(e,t,r){let n=c(e,"user-agent")??"",a=R(e.headers),i=I(a,{});if(i.astraId||i.apiKey||i.jwt)return{tier:"verified",protocol:"x-astra"};let{apiKeyFormat:o,platformHeaders:s}=b(a),l={userAgent:n,apiKeyFormat:o,platformHeaders:s};if(r!=="classify"){let d=oe(e,t,L(e));if(d)return{tier:"identified",protocol:d.protocol,artifacts:d.artifacts,evidence:d.evidence,fingerprint:B(l)}}let f=B(l);return f?{tier:"identified",protocol:"platform-ua",fingerprint:f}:!n||pt.test(n)||!ft.test(n)?{tier:"anonymous-bot",evidence:{userAgent:n||"(none)"}}:!c(e,"sec-fetch-mode")&&!c(e,"accept-language")?{tier:"anonymous-bot",evidence:{userAgent:n,spoofedBrowser:!0}}:{tier:"human"}}var gt={GET:"data.read",HEAD:"data.read",OPTIONS:"data.read",POST:"data.write",PUT:"data.write",PATCH:"data.write",DELETE:"data.delete"},yt="data.write",mt="data";function ht(e){return gt[e.toUpperCase()]??yt}function vt(e){let t=e.indexOf(":");if(t>=0)return{purpose:e.slice(0,t)};let r=e.indexOf(".");return r>0&&r<e.length-1?{purpose:e.slice(0,r),actionCandidate:e}:{purpose:e}}function ce(e){let t=e.astraPurpose?vt(e.astraPurpose):void 0,r,n;e.routeAction?(r=e.routeAction,n="route_config"):e.hasCustomActionExtractor&&e.customAction?(r=e.customAction,n="custom_extractor"):!e.hasCustomActionExtractor&&e.astraAction?(r=e.astraAction,n="header"):!e.hasCustomActionExtractor&&t?.actionCandidate?(r=t.actionCandidate,n="purpose_header_derived"):(r=ht(e.method),n="method_table");let a,i;if(e.routePurpose?(a=e.routePurpose,i="route_config"):e.hasCustomPurposeExtractor?e.customPurpose&&(a=e.customPurpose,i="custom_extractor"):t?(a=t.purpose,i="header"):e.legacyPurpose?(a=e.legacyPurpose,i="legacy_header"):e.queryPurpose&&(a=e.queryPurpose,i="query"),!a){let o=r.indexOf(".");o>0?(a=r.slice(0,o),i="action_derived"):(a=mt,i="transport_default")}return{purpose:a,action:r,purposeSource:i,actionSource:n}}async function P(e,t){let r;try{return await Promise.race([e,new Promise(n=>{r=setTimeout(()=>n(void 0),t)})])}catch{return}finally{r&&clearTimeout(r)}}async function H(e,t,r,n){let a=c(t,"cloudfront-viewer-address")?.split(":")[0];await P(ae({apiBaseUrl:e.apiBaseUrl,counterpartyId:e.counterpartyId},{counterpartyUrl:e.counterpartyUrl,counterpartyType:"website",sourceIp:a,userAgent:c(t,"user-agent"),requestPath:t.uri,requestMethod:t.method,protocol:r.protocol,evidence:r.evidence,observedMetadata:E(t)}),n)}function de(e,t=Math.random){return e<=0?!1:e>=1?!0:t()<e}function w(e){return{tier:e.tier,decision:"allow",reasons:[],protocol:e.protocol}}function ue(e,t,r,n){let a=R(t.headers),i=c(t,"cloudfront-viewer-address")?.split(":")[0],o=ce({method:t.method,astraPurpose:c(t,"x-astra-purpose"),astraAction:c(t,"x-astra-action")});return{credentials:I(a,{}),purpose:o.purpose,action:o.action,resource:t.uri,createSession:!0,counterpartyType:"website",counterpartyUrl:e.counterpartyUrl,callerMetadata:{sourceIp:i,userAgent:c(t,"user-agent"),referer:c(t,"referer"),host:c(t,"host"),observedMetadata:E(t)},...n&&r.artifacts&&{commerceArtifacts:r.artifacts}}}function le(e,t){let r=w(e);return r.sessionId=t.sessionId,r.correlationId=t.correlationId,r.guidance=t.guidance,t.requiresStepUp||t.stepUpApproval?(r.decision="manual_review",r.reasons=["step-up approval required"],r.stepUp={pollUrl:t.stepUpApproval?.pollUrl,expiresAt:t.stepUpApproval?.expiresAt},r):!t.identityVerified||!t.policyAllowed?(r.decision="deny",r.reasons=t.denialReasons?.length?t.denialReasons:[t.identityVerified?"denied by access policy":"identity not verified"],r):(r.asat={trustScore:t.agent?.trustScore,agentId:t.agent?.astraId,developerId:t.developer?.astradId,accessLevel:t.accessLevel},r)}async function pe(e,t,r,n,a,i){let o=e.budgets??{},s=o.beaconMs??300,l=n.mode==="enforce"?o.verifyEnforceMs??3e3:o.verifyObserveMs??1500,f={apiBaseUrl:e.apiBaseUrl,...a&&{apiKey:a},counterpartyId:e.counterpartyId,disableInitChecks:!0};try{switch(r.tier){case"verified":{if(n.depth==="classify")return w(r);let d=await P(F(f,ue(e,t,r,n.depth==="authorize")),l);if(!d){let u=w(r);return u.reasons=["verify-access unreachable within budget \u2014 fail-open"],u}return le(r,d)}case"identified":{if(n.depth==="authorize"&&r.artifacts){let u=await P(F(f,ue(e,t,r,!0)),l);if(!u){let m=w(r);return m.reasons=["verify-access unreachable within budget \u2014 fail-open"],m}return le(r,u)}await H(e,t,r,s);let d=w(r);return n.mode==="enforce"&&n.depth!=="classify"&&(d.decision="deny",d.reasons=["agent is not registered with AstraSync"]),d}case"anonymous-bot":return de(i.anonymousBeaconRate,e.random)&&await H(e,t,{...r,protocol:r.protocol??"ua-heuristic"},s),w(r);default:return w(r)}}catch(d){let u=w(r);return u.reasons=[`edge pipeline error \u2014 fail-open: ${d instanceof Error?d.message:String(d)}`],u}}var At={"vi-sd-jwt":"This request presented Visa Intelligent Commerce credentials, but the agent is not verified with AstraSync. Register the agent to pair your VI credentials with a verified identity and mandate.","rfc9421-agent-pay":"This request carried a Mastercard Agent Pay signature, but the agent is not verified with AstraSync. Register the agent to pair Agent Pay credentials with a verified identity and mandate.","rfc9421-tap":"This request carried a Visa TAP signature, but the agent is not verified with AstraSync. Register the agent to pair TAP credentials with a verified identity and mandate.","rfc9421-web-bot-auth":"This request carried a Web Bot Auth signature, but the agent is not verified with AstraSync. Register the agent to link your signed-agent identity to a verified principal.",rfc9421:"This request carried an RFC 9421 HTTP message signature, but the agent is not verified with AstraSync. Register the agent to link the signing identity to a verified principal.",acp:"This request used the Agentic Commerce Protocol, but the agent is not verified with AstraSync. Register the agent to transact on this property.",ucp:"This request used a UCP checkout session, but the agent is not verified with AstraSync. Register the agent to transact on this property.",ap2:"This request presented AP2 mandates, but the agent is not verified with AstraSync. Register the agent to pair your mandates with a verified identity.",mpp:"This request presented MPP payment credentials, but the agent is not verified with AstraSync. Register the agent to transact on this property.",x402:"This request used x402 payment headers, but the agent is not verified with AstraSync. Register the agent to transact on this property.","platform-ua":"This traffic was identified as a platform AI agent without AstraSync credentials. Register the agent to access this property with a verified identity.","x-astra":"The presented AstraSync credentials failed verification or were denied by this property\u2019s access policy."};function fe(e,t){let r=t.replace(/\/api\/?$/,""),n=(e.protocol&&At[e.protocol])??"This request could not be verified by AstraSync.";return{success:!1,error:{code:e.tier==="verified"?"INSUFFICIENT_ACCESS":"UNAUTHORIZED",message:n,...e.protocol&&{protocol:e.protocol},failures:e.reasons,...e.correlationId&&{correlationId:e.correlationId},guidance:{message:e.guidance?.message||"Register this agent with AstraSync to receive verifiable credentials.",registrationUrl:e.guidance?.registrationUrl||`${r}/register`,documentationUrl:e.guidance?.documentationUrl||`${r}/docs/edge-adapter`}}}}function ge(e){return{success:!1,status:"manual_review",message:"This action requires human approval. Poll the step-up approval endpoint and retry once approved.",...e.stepUp&&{stepUpApproval:e.stepUp},...e.correlationId&&{correlationId:e.correlationId}}}var S={trustScore:"X-AstraSync-Trust-Score",agentId:"X-AstraSync-Agent-Id",developerId:"X-AstraSync-Developer-Id",permissions:"X-AstraSync-Permissions",observedDecision:"X-AstraSync-Observed-Decision"};function me(e,t,r,n){if($(t,"x-astrasync-"),n.mode!=="enforce")return r.decision!=="allow"&&A(t,S.observedDecision,r.decision),ye(t,r),t;switch(r.decision){case"deny":return x(403,fe(r,e.apiBaseUrl));case"manual_review":return x(202,ge(r),{"Retry-After":"30"});default:return ye(t,r),t}}function ye(e,t){if(!t.asat)return;let{trustScore:r,agentId:n,developerId:a,accessLevel:i}=t.asat;r!==void 0&&A(e,S.trustScore,String(r)),n&&A(e,S.agentId,n),a&&A(e,S.developerId,a),i&&A(e,S.permissions,i)}function he(e){let t=e.log??((r,n,a)=>{console[r==="info"?"log":r](`[astrasync-edge] ${n}`,a??"")});return async function(n){let a=N(n);try{j(a);let i=await W({...e,log:t}),o=await Z(e,i),s=ie(o,a.uri);if(s.skip)return a;let l=c(a,"x-forwarded-host")??c(a,"host")??new URL(e.counterpartyUrl).host,f=se(a,l,s.depth);if(f.tier==="human")return a;let d=await pe({...e,log:t},a,f,s,i,o.sampling);return d.decision!=="allow"&&t("info",s.mode==="enforce"?`${d.decision.toUpperCase()}: ${a.method} ${a.uri}`:`[OBSERVE] would have been ${d.decision.toUpperCase()}: ${a.method} ${a.uri}`,{tier:d.tier,protocol:d.protocol,reasons:d.reasons}),me(e,a,d,s)}catch(i){return t("error","edge handler error \u2014 passing request through",{error:i instanceof Error?i.message:String(i)}),a}}}var wt="https://astrasync.ai/api",ve="",Ae="",Rt=void 0;(!ve||!Ae)&&console.error("[astrasync-edge] ASTRASYNC_COUNTERPARTY_ID / ASTRASYNC_COUNTERPARTY_URL were not baked into the bundle \u2014 rebuild via infra/deploy.sh with the ASTRASYNC_* env vars set.");var Ct=he({apiBaseUrl:wt,counterpartyId:ve,counterpartyUrl:Ae,apiKeySecretName:Rt});0&&(module.exports={handler});
1
+ "use strict";var Ce=Object.create;var T=Object.defineProperty;var Se=Object.getOwnPropertyDescriptor;var Te=Object.getOwnPropertyNames;var be=Object.getPrototypeOf,Ie=Object.prototype.hasOwnProperty;var Ee=(e,t)=>{for(var r in t)T(e,r,{get:t[r],enumerable:!0})},M=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Te(t))!Ie.call(e,a)&&a!==r&&T(e,a,{get:()=>t[a],enumerable:!(n=Se(t,a))||n.enumerable});return e};var Pe=(e,t,r)=>(r=e!=null?Ce(be(e)):{},M(t||!e||!e.__esModule?T(r,"default",{value:e,enumerable:!0}):r,e)),Ue=e=>M(T({},"__esModule",{value:!0}),e);var St={};Ee(St,{handler:()=>Ct});module.exports=Ue(St);var xe=new Set(["cookie","set-cookie","x-csrf-token","proxy-authorization","x-astrasync-signature","x-astrasync-secret","x-hub-signature","x-hub-signature-256"]),_e=["x-astrasync-","kya-","kya_"],Oe=new Set(["authorization","x-api-key","x-goog-api-key","api-key"]);function ke(e){return e==="signature"||e.endsWith("-signature")||e.endsWith("-signature-256")}var Be=new Set(["openai-organization","openai-project","openai-version","openai-processing-ms","anthropic-version","anthropic-beta","x-goog-user-project","x-goog-api-client","user-agent","x-agent-card-url","x-agent-provider"]),Fe=["x-goog-","x-stainless-","x-anthropic-","x-openai-"],He=["sk-ant-api03","sk-ant-api","sk-ant","sk-proj","sk-svcacct","sk-or-v1","sk-or","sk-lf","sk-","gsk_","aiza","ya29","ghp_","gho_","github_pat_","xai-","pplx-","r8_","hf_","astra-","astrae-"],Me=64,D=1024,De=16*1024;function U(e){let t=0;for(let r=0;r<e.length;r++){let n=e.charCodeAt(r);n<128?t+=1:n<2048?t+=2:n>=55296&&n<=56319?(t+=4,r++):t+=3}return t}function Ne(e){if(!e)return;let t=e.trim(),r=t.indexOf(" ");if(r>0){let a=t.slice(0,r).toLowerCase();(a==="bearer"||a==="basic"||a==="token")&&(t=t.slice(r+1).trim())}let n=t.toLowerCase();for(let a of He)if(n.startsWith(a))return a}function Le(e){return!!(xe.has(e)||_e.some(t=>e.startsWith(t))||ke(e))}function Ke(e){return Be.has(e)?!0:Fe.some(t=>e.startsWith(t))}function b(e){let t={},r={},n,a=0,i=0;if(!e)return{headers:t};for(let s of Object.keys(e)){if(i>=Me)break;let p=s.toLowerCase(),f=e[s];if(f===void 0)continue;let d=Array.isArray(f)?f.join(", "):String(f);if(Oe.has(p)){let v=Ne(d);v&&!n&&(n=v);continue}if(Le(p))continue;let u=d;U(u)>D&&(u=u.slice(0,D));let m=U(p)+U(u);a+m>De||(a+=m,i++,t[p]=u,Ke(p)&&(r[p]=u))}let o={headers:t};return n&&(o.apiKeyFormat=n),Object.keys(r).length>0&&(o.platformHeaders=r),o}function N(e){return e.Records[0].cf.request}function c(e,t){return e.headers[t.toLowerCase()]?.[0]?.value}function R(e){let t={};for(let[r,n]of Object.entries(e))n?.length&&(t[r]=n.length===1?n[0].value:n.map(a=>a.value));return t}function L(e){let t=e.body;return t?.data?{text:t.encoding==="base64"?Buffer.from(t.data,"base64").toString("utf8"):t.data,truncated:t.inputTruncated===!0}:{truncated:!1}}function $e(e){let t={},r=(i,o,s)=>{let p=c(e,o);p&&(t[i]=s?s(p):p)},n=c(e,"cloudfront-viewer-address");n&&(t.ip=n.replace(/:\d+$/,"")),r("country","cloudfront-viewer-country"),r("countryName","cloudfront-viewer-country-name"),r("region","cloudfront-viewer-country-region"),r("city","cloudfront-viewer-city"),r("asn","cloudfront-viewer-asn"),r("tlsVersion","cloudfront-viewer-tls"),r("httpVersion","cloudfront-viewer-http-version");let a=[];for(let[i,o]of[["desktop","cloudfront-is-desktop-viewer"],["mobile","cloudfront-is-mobile-viewer"],["tablet","cloudfront-is-tablet-viewer"],["smarttv","cloudfront-is-smarttv-viewer"]])c(e,o)==="true"&&a.push(i);return a.length&&(t.device=a.join(",")),t}function I(e){let{headers:t,apiKeyFormat:r,platformHeaders:n}=b(R(e.headers)),a=$e(e);return{headers:t,...r&&{apiKeyFormat:r},...n&&{platformHeaders:n},...Object.keys(a).length>0&&{connection:a}}}function K(e){let t=e.origin?.custom?.domainName??e.origin?.s3?.domainName??void 0;if(!t)return;let r=c(e,"host");!r||r===t||(c(e,"x-forwarded-host")||A(e,"X-Forwarded-Host",r),A(e,"Host",t))}function $(e,t){let r=e.querystring?`?${e.querystring}`:"";return`https://${t}${e.uri}${r}`}function A(e,t,r){e.headers[t.toLowerCase()]=[{key:t,value:r}]}function j(e,t){let r=t.toLowerCase();for(let n of Object.keys(e.headers))n.startsWith(r)&&delete e.headers[n]}function x(e,t,r){let n={"content-type":[{key:"Content-Type",value:"application/json"}]};for(let[a,i]of Object.entries(r??{}))n[a.toLowerCase()]=[{key:a,value:i}];return{status:String(e),statusDescription:e===403?"Forbidden":e===202?"Accepted":"OK",headers:n,body:JSON.stringify(t)}}var O=Object.freeze({version:1,mode:"observe",depth:"classify",pathRules:[],sampling:Object.freeze({anonymousBeaconRate:.1}),failurePosture:"open"}),V=["observe","enforce"],z=["classify","authenticate","authorize"];function je(e){if(typeof e!="object"||e===null)return!1;let t=e;if(t.version!==1||!V.includes(t.mode)||!z.includes(t.depth)||!Array.isArray(t.pathRules))return!1;for(let n of t.pathRules){if(typeof n!="object"||n===null)return!1;let a=n;if(typeof a.pattern!="string"||a.pattern.length===0||a.mode!==void 0&&!V.includes(a.mode)||a.depth!==void 0&&!z.includes(a.depth))return!1}let r=t.sampling;return typeof r!="object"||r===null||typeof r.anonymousBeaconRate!="number"||r.anonymousBeaconRate<0||r.anonymousBeaconRate>1?!1:t.failurePosture==="open"}async function Ve(e,t,r){if(!t)return null;let n={Accept:"application/json"};e.apiKey&&(n.Authorization=`Bearer ${e.apiKey}`,n["X-API-Key"]=e.apiKey),r?.etag&&(n["If-None-Match"]=r.etag);try{let a=await fetch(`${e.apiBaseUrl}/endpoints/${encodeURIComponent(t)}/edge-config`,{method:"GET",headers:n,signal:AbortSignal.timeout(r?.timeoutMs??5e3)});if(a.status===304)return{notModified:!0};if(!a.ok)return null;let o=(await a.json()).data?.edgeConfig;return je(o)?{edgeConfig:o,etag:a.headers.get("etag")??void 0}:null}catch{return null}}var ze=60*1e3,Ge=1440*60*1e3,C=new Map,_=new Map;function X(e,t){return`${e}|${t}`}function Xe(e){return e.mode!=="enforce"&&!e.pathRules.some(t=>t.mode==="enforce")?e:{...e,mode:"observe",pathRules:e.pathRules.map(t=>t.mode==="enforce"?{...t,mode:"observe"}:t)}}async function G(e,t){let r=X(e.apiBaseUrl,t),n=_.get(r);if(n)return n;let a=Ve(e,t,{etag:C.get(r)?.etag}).then(i=>{if(i===null)return;let o=Date.now();if("notModified"in i){let s=C.get(r);s&&(s.lastSuccessAt=o);return}C.set(r,{config:i.edgeConfig,etag:i.etag,lastSuccessAt:o})}).finally(()=>{_.delete(r)});return _.set(r,a),a}async function Y(e,t,r){let n=r?.ttlMs??ze,a=r?.maxStaleMs??Ge,i=X(e.apiBaseUrl,t),o=C.get(i);if(o){let s=Date.now()-o.lastSuccessAt;return s>n&&G(e,t).catch(()=>{}),s>a?Xe(o.config):o.config}return await G(e,t).catch(()=>{}),C.get(i)?.config??O}function q(e,t){for(let r of e)if(Ye(r.pattern).test(t))return r}function Ye(e){let t=e.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${t}$`,"i")}var qe=900*1e3,J=new Map;async function Je(e){let{SecretsManagerClient:t,GetSecretValueCommand:r}=await import("@aws-sdk/client-secrets-manager");return(await new t({region:"us-east-1"}).send(new r({SecretId:e}))).SecretString??void 0}async function W(e){if(e.apiKey)return e.apiKey;let t=e.apiKeySecretName;if(!t)return;let r=J.get(t);if(r&&Date.now()-r.fetchedAt<qe)return r.value;try{let a=await(e.fetchSecret??Je)(t);return J.set(t,{value:a,fetchedAt:Date.now()}),a}catch(n){return e.log?.("warn","Secrets Manager fetch failed \u2014 continuing keyless",{secretName:t,error:n instanceof Error?n.message:String(n)}),r?.value}}async function Z(e,t){try{return await Y({apiBaseUrl:e.apiBaseUrl,apiKey:t},e.counterpartyId,{ttlMs:e.configTtlMs})}catch{return e.fallbackConfig??O}}function We(e){return e>=80?"PLATINUM":e>=60?"GOLD":e>=40?"SILVER":"BRONZE"}var Ze="3.12.0",_t=3600*1e3,Qe=new Map;function et(e){return Qe.get(e)?.data}var te={apiBaseUrl:"https://astrasync.ai/api",defaultAccessLevel:"none",debug:!1},re=!1,Q=!1;async function ee(e,t,r){re=!0;try{let n=`${e}/agents/verify-access`,i=(await fetch(n,{method:"HEAD"})).headers.get("content-type")??"";if(i.startsWith("text/html")){let o=`[VerificationGateway] apiBaseUrl '${e}' returned HTML (content-type: ${i}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;if(r)throw new Error(`${o} (strictInit=true)`);console.warn(`${o} Set disableInitChecks: true on GatewayConfig to silence.`)}else t&&console.log(`[VerificationGateway] init check passed for ${e} (content-type: ${i})`)}catch(n){if(r)throw n;t&&console.log(`[VerificationGateway] init check failed (non-blocking): ${String(n)}`)}}var k=new Map;function ne(e,t){let r=e.credentials;return[r.astraId||"",r.apiKey||"",r.jwt||"",e.purpose||"",e.action||"",e.resourceType||"",e.resource||"",e.jurisdiction||"",e.transactionValue??"",e.currency||"",t||"",e.counterpartyUrl||"",e.counterpartyType||"",e.isSubAgentRequest?"1":"0",e.parentAgentId||"",e.subAgentDepth??"",e.durationRequired??"",e.invocationProtocol||"",e.enableRuntimeChallenge?"1":"0",e.callerMetadata?.sourceIp||"",e.callerMetadata?.userAgent||"",e.callerMetadata?.forwardedFor||"",e.callerMetadata?.agentCardUrl||""].join("|")}function tt(e,t){let r=ne(e,t),n=k.get(r);return n&&n.expiresAt>Date.now()?n.result:(n&&k.delete(r),null)}var rt=60;function nt(e,t,r,n){let a=r&&r>0?r:rt,i=ne(e,n);k.set(i,{result:t,expiresAt:Date.now()+a*1e3})}function E(e,t){let r={},n=/^ASTRAE?-[A-Za-z0-9_-]{1,64}$/,a=e["x-astra-id"]||e["X-Astra-Id"]||e["X-ASTRA-ID"]||e["x-astra-agentid"]||e["X-Astra-AgentId"]||e["x-astra-agent-id"]||e["X-Astra-Agent-Id"]||e["X-ASTRA-AGENT-ID"];if(a){let s=Array.isArray(a)?a[0]:typeof a=="string"?a:void 0;typeof s=="string"&&n.test(s)&&(r.astraId=s)}let i=e["x-api-key"]||e["X-Api-Key"]||e["X-API-KEY"];i&&(r.apiKey=Array.isArray(i)?i[0]:i);let o=e.authorization||e.Authorization;if(o){let s=Array.isArray(o)?o[0]:o;typeof s=="string"&&(r.authorizationHeader=s,s.startsWith("Bearer ")&&(r.jwt=s.slice(7)))}return t&&(t.astraId&&!r.astraId&&(r.astraId=t.astraId),t.apiKey&&!r.apiKey&&(r.apiKey=t.apiKey)),r}function at(e,t,r={}){let a=(r.source??"no_credentials")==="api_error",i=r.urls,o=a?{message:"Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",registrationUrl:i?.registrationUrl??"",documentationUrl:i?.documentationUrl??"",steps:["Retry the request with exponential backoff","If failures persist, share the correlationId with support"]}:{message:"This service verifies AI agents before granting access. Please register your agent with AstraSync.",registrationUrl:i?.registrationUrl??"",documentationUrl:i?.documentationUrl??"",steps:["Register for an AstraSync account","Create and register your agent","Add your ASTRA-ID to request headers","Retry your request"]};return{identityVerified:!1,policyAllowed:!1,accessLevel:"none",guidance:o,denialReasons:t?[t]:["No valid agent credentials provided"],failures:a?[{dimension:"verify_access.api_error",message:t??"Verification temporarily unavailable",guidance:o.message}]:void 0,correlationId:r.correlationId,attemptId:r.attemptId,verifiedAt:new Date}}async function ot(e,t){let{credentials:r,...n}=t,a={...r.astraId&&{agentId:r.astraId},...n.purpose&&{purpose:n.purpose}};if(n.action&&(a.action=n.action),n.resourceType&&(a.resourceType=n.resourceType),n.resource&&(a.resource=n.resource),n.jurisdiction&&(a.jurisdiction=n.jurisdiction),n.transactionValue&&(a.transactionValue=n.transactionValue),n.currency&&(a.currency=n.currency),n.isSubAgentRequest&&(a.isSubAgentRequest=n.isSubAgentRequest),n.parentAgentId&&(a.parentAgentId=n.parentAgentId),n.subAgentDepth!==void 0&&(a.subAgentDepth=n.subAgentDepth),n.enableRuntimeChallenge&&(a.enableRuntimeChallenge=n.enableRuntimeChallenge),n.createSession&&(a.createSession=n.createSession),n.durationRequired&&(a.durationRequired=n.durationRequired),n.counterpartyType&&(a.counterpartyType=n.counterpartyType),n.counterpartyUrl&&(a.counterpartyUrl=n.counterpartyUrl),e.counterpartyId&&(a.counterpartyId=e.counterpartyId),n.runtimeChallengeOptions&&(a.runtimeChallengeOptions=n.runtimeChallengeOptions),n.invocationProtocol&&(a.invocationProtocol=n.invocationProtocol),n.commerceArtifacts&&(a.commerceArtifacts=n.commerceArtifacts),n.attemptId&&(a.attemptId=n.attemptId),n.considerationSet&&(a.considerationSet=n.considerationSet),a.sdkVersion=Ze,n.callerMetadata||n.clientIp||n.userAgent){let o={...n.clientIp&&{sourceIp:n.clientIp},...n.userAgent&&{userAgent:n.userAgent},...n.callerMetadata};Object.keys(o).length>0&&(a.callerMetadata=o)}let i={"Content-Type":"application/json",...e.customHeaders};e.apiKey&&(i.Authorization=`Bearer ${e.apiKey}`,i["X-API-Key"]=e.apiKey);try{let o=await fetch(`${e.apiBaseUrl}/agents/verify-access`,{method:"POST",headers:i,body:JSON.stringify(a)}),s=await o.json();return o.status===410?{success:!0,attemptId:typeof s?.attemptId=="string"?s.attemptId:void 0,access:{allowed:!1,accessLevel:"none",reason:"endpoint_deactivated",failures:[{dimension:"endpoint.deactivated",message:typeof s?.message=="string"?s.message:"Endpoint has been deactivated",guidance:typeof s?.guidance=="string"?s.guidance:"Reactivate via POST /api/endpoints/{id}/reactivate, or update the URL on the calling agent."}]}}:o.ok?s:{success:!1,error:s.message||s.error||`API returned ${o.status}`,correlationId:typeof s?.correlationId=="string"?s.correlationId:void 0,attemptId:typeof s?.attemptId=="string"?s.attemptId:void 0}}catch(o){return{success:!1,error:`Failed to call verify-access API: ${o instanceof Error?o.message:"Unknown error"}`}}}async function B(e,t,r){let n={...te,...e},a=n.apiBaseUrl?et(n.apiBaseUrl):void 0;if(!re&&!n.disableInitChecks&&n.apiBaseUrl&&(n.strictInit?await ee(n.apiBaseUrl,n.debug,!0):ee(n.apiBaseUrl,n.debug,!1)),!Q&&(e.minTrustScore!==void 0||e.minTrustScoreForFull!==void 0)&&(Q=!0,console.warn("[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access-level decisions (the SDK reads access.accessLevel from the verify-access response). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side.")),n.cacheTtl!==0&&!r?.bypassCache){let g=tt(t,n.counterpartyId);if(g){n.debug&&console.log("[VerificationGateway] Returning cached result");let h={...g};return t.attemptId?h.attemptId=t.attemptId:delete h.attemptId,h}}let i={...t};!i.counterpartyUrl&&n.counterpartyUrl&&(i.counterpartyUrl=n.counterpartyUrl),!i.counterpartyType&&n.counterpartyType&&(i.counterpartyType=n.counterpartyType),n.debug&&console.log("[VerificationGateway] Calling verify-access API");let o=await ot(n,i),s=o.denialReasons,p=Array.isArray(s)&&s.length>0?s:void 0;if(!o.success)return at(n,o.error,{source:"api_error",correlationId:o.correlationId,attemptId:o.attemptId,urls:a});if(!o.access?.allowed){let g=o.access?.failures;return{identityVerified:o.verificationContext?.idVerified===!0,policyAllowed:!1,accessLevel:"none",denialReasons:p??(g&&g.length>0?g.map(Re=>Re.message):o.access?.reason?[o.access.reason]:["Access denied"]),failures:g,requiresStepUp:o.access?.requiresStepUp,requiresApproval:o.access?.requiresApproval,guidance:{message:o.access?.reason||"Access denied by PDLSS policy",registrationUrl:a?.registrationUrl??"",documentationUrl:a?.documentationUrl??""},verifiedAt:new Date,sessionId:o.sessionId,correlationId:o.correlationId,attemptId:o.attemptId,recommendation:o.recommendation,recommendationReasons:o.recommendationReasons,stepUpApproval:o.stepUpApproval,settlement:o.settlement}}let f=o.agent?{astraId:o.agent.astraId,name:o.agent.name,trustScore:o.agent.trustScore,trustLevel:We(o.agent.trustScore),blockchainVerified:o.agent.blockchainStatus==="verified",status:o.agent.agentStatus}:void 0,d=o.developer?{astradId:o.developer.kyaOwnerId,name:o.developer.fullName,trustScore:o.developer.trustScore||0,verified:o.developer.identityVerified}:void 0,u=o.organization?{name:o.organization.name,verified:o.organization.verified,trustScore:o.organization.trustScore}:void 0,m=o.verificationContext,v=o.access?.accessLevel??"standard",l={identityVerified:o.verificationContext?.idVerified!==!1,policyAllowed:!0,accessLevel:v,agent:f,developer:d,organization:u,appliedPolicy:o.access?.appliedPolicy,verificationContext:m,requiresStepUp:o.access?.requiresStepUp,requiresApproval:o.access?.requiresApproval,verifiedAt:new Date,cacheTtl:n.cacheTtl,sessionId:o.sessionId,correlationId:o.correlationId,attemptId:o.attemptId,runtimeChallenge:o.runtimeChallenge,tokenGuidance:o.tokenGuidance,recommendation:o.recommendation,recommendationReasons:o.recommendationReasons,warningHeader:o.warningHeader,stepUpApproval:o.stepUpApproval,settlement:o.settlement};l.recommendation==="deny"?(l.policyAllowed=!1,l.accessLevel="none",l.denialReasons=p??l.recommendationReasons??["Access denied by AstraSync recommendation"],l.guidance=l.runtimeChallenge?{message:`Verification failed: ${l.runtimeChallenge.reason||"runtime challenge failed"}`,registrationUrl:a?.registrationUrl??"",documentationUrl:a?.documentationUrl??""}:{message:l.recommendationReasons?.[0]||"Access denied by AstraSync recommendation",registrationUrl:a?.registrationUrl??"",documentationUrl:a?.documentationUrl??""}):l.recommendation==="step_up_required"&&(l.requiresStepUp=!0,l.denialReasons=p??l.recommendationReasons??["Step-up verification required"]);let y=l.requiresStepUp===!0||l.requiresApproval===!0||l.recommendation==="step_up_required";return n.cacheTtl!==0&&l.recommendation!=="deny"&&!y&&nt(t,l,n.cacheTtl,n.counterpartyId),l}async function ae(e,t){let r=e.apiBaseUrl||te.apiBaseUrl,{counterpartyUrl:n,...a}=t,i={...a,...n&&{counterpartyUrl:n},...e.counterpartyId&&{counterpartyId:e.counterpartyId}};await fetch(`${r}/verification-activity/unregistered-attempt`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).catch(()=>{})}var it=[{vendor:"claude",displayName:"Anthropic Claude",uaPatterns:[/claude/i,/anthropic/i],agentCardPatterns:[/anthropic\.com/i,/claude\.ai/i],apiKeyFormatPatterns:[/^sk-ant/i],headerPatterns:[/^anthropic-version/i,/^anthropic-beta/i,/^x-anthropic-/i]},{vendor:"chatgpt",displayName:"OpenAI ChatGPT",uaPatterns:[/chatgpt/i,/openai/i,/gpt-?\d/i],agentCardPatterns:[/openai\.com/i,/chatgpt\.com/i],apiKeyFormatPatterns:[/^sk-proj/i,/^sk-svcacct/i],headerPatterns:[/^openai-organization/i,/^openai-project/i,/^openai-version/i]},{vendor:"gemini",displayName:"Google Gemini",uaPatterns:[/gemini/i,/google-gemini/i,/bard/i],agentCardPatterns:[/gemini\.google\.com/i,/ai\.google\.dev/i],apiKeyFormatPatterns:[/^aiza/i],headerPatterns:[/^x-goog-user-project/i,/^x-goog-api-client/i]},{vendor:"cursor",displayName:"Cursor",uaPatterns:[/cursor/i],agentCardPatterns:[/cursor\.sh/i,/cursor\.com/i]},{vendor:"goose",displayName:"Block Goose",uaPatterns:[/goose/i,/block-goose/i],agentCardPatterns:[/block\.xyz\/goose/i,/goose\.tools/i]},{vendor:"perplexity",displayName:"Perplexity",uaPatterns:[/perplexity/i],agentCardPatterns:[/perplexity\.ai/i],apiKeyFormatPatterns:[/^pplx-/i]}];function st(e,t){let r=t.userAgent??"",n=t.agentCardUrl??"",a=t.apiKeyFormat??"",i=[];if(t.platformHeaders)for(let[o,s]of Object.entries(t.platformHeaders))i.push(o,`${o}: ${s}`);for(let o of e){let s=o.uaPatterns?.some(u=>u.test(r)),p=o.agentCardPatterns?.some(u=>u.test(n)),f=a.length>0&&o.apiKeyFormatPatterns?.some(u=>u.test(a)),d=i.length>0&&o.headerPatterns?.some(u=>i.some(m=>u.test(m)));if(s||p||f||d){let u=r.split(/[\s/]/)[0]?.toLowerCase()??"",m=(()=>{try{return n?new URL(n).host:""}catch{return""}})(),v=u||m||a||"unknown";return{vendor:o.vendor,fingerprintKey:`${o.vendor}:${v}`,displayName:o.displayName}}}}function F(e){return st(it,e)}var ct=/^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;function dt(e){try{let t=e.split(".")[0];return JSON.parse(Buffer.from(t,"base64url").toString("utf8"))}catch{return}}function ut(e){if(e.text)try{let t=JSON.parse(e.text);return typeof t=="object"&&t!==null?t:void 0}catch{return}}function oe(e,t,r){let n=$(e,t),a=e.method,i=R(e.headers),o=ut(r),s=r.truncated?{bodyTruncated:!0}:{},p=c(e,"authorization"),f=p?.replace(/^Bearer\s+/i,""),u=[c(e,"x-payment-mandate")??c(e,"payment-mandate"),f].find(y=>y&&ct.test(y));if(u){let y=dt(u)?.typ;return{protocol:"vi-sd-jwt",artifacts:{viSdJwt:u},evidence:{typ:y,...s}}}let m=c(e,"signature"),v=c(e,"signature-input");if(m&&v){let y=c(e,"signature-agent"),g=c(e,"x-agent-registry"),h=v.toLowerCase();return{protocol:y?"rfc9421-web-bot-auth":g?.toLowerCase().includes("visa")||h.includes("visa")?"rfc9421-tap":g?.toLowerCase().includes("mastercard")||h.includes("mastercard")?"rfc9421-agent-pay":"rfc9421",artifacts:{rfc9421:{headers:i,method:a,url:n,...r.text&&{body:r.text}}},evidence:{...y&&{signatureAgent:y},...g&&{registryHint:g},keyid:v.match(/keyid="([^"]+)"/)?.[1],...s}}}let l=c(e,"timestamp");if(m&&!v&&(l||c(e,"idempotency-key")))return{protocol:"acp",artifacts:{acpRequest:{method:a,url:n,headers:i,...r.text&&{rawBody:r.text},...o&&{body:o}}},evidence:{hasTimestamp:!!l,...s}};if(/\/checkout[-_]sessions(\/|$)/.test(e.uri))return{protocol:"ucp",artifacts:{ucpRequest:{method:a,url:n,...o&&{body:o}}},evidence:{path:e.uri,...s}};if(o){let y=o.intent_mandate??o.intentMandate,g=o.cart_mandate??o.cartMandate,h=o.payment_mandate??o.paymentMandate;if(typeof y=="string"||typeof g=="string"||typeof h=="string")return{protocol:"ap2",artifacts:{ap2Mandates:{...typeof y=="string"&&{intent:y},...typeof g=="string"&&{cart:g},...typeof h=="string"&&{payment:h}}},evidence:{mandatesPresent:[typeof y=="string"&&"intent",typeof g=="string"&&"cart",typeof h=="string"&&"payment"].filter(Boolean),...s}}}if(p&&/^Payment\s+/i.test(p))return{protocol:"mpp",artifacts:{mppRequest:{method:a,url:n,headers:i,...r.text&&{rawBody:r.text},...o&&{body:o}}},evidence:s};if(c(e,"x-payment"))return{protocol:"x402",artifacts:{x402Request:{method:a,url:n,headers:i,...o&&{body:o}}},evidence:s}}var pt=/\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i,lt=/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,ft=/mozilla\/\d/i;function ie(e,t){if(pt.test(t))return{mode:e.mode,depth:e.depth,skip:!0};let r=q(e.pathRules,t);return r?{mode:r.mode??e.mode,depth:r.depth??e.depth,skip:r.skip===!0}:{mode:e.mode,depth:e.depth,skip:!1}}function se(e,t,r){let n=c(e,"user-agent")??"",a=R(e.headers),i=E(a,{});if(i.astraId||i.apiKey||i.jwt)return{tier:"verified",protocol:"x-astra"};let{apiKeyFormat:o,platformHeaders:s}=b(a),p={userAgent:n,apiKeyFormat:o,platformHeaders:s};if(r!=="classify"){let d=oe(e,t,L(e));if(d)return{tier:"identified",protocol:d.protocol,artifacts:d.artifacts,evidence:d.evidence,fingerprint:F(p)}}let f=F(p);return f?{tier:"identified",protocol:"platform-ua",fingerprint:f}:!n||lt.test(n)||!ft.test(n)?{tier:"anonymous-bot",evidence:{userAgent:n||"(none)"}}:!c(e,"sec-fetch-mode")&&!c(e,"accept-language")?{tier:"anonymous-bot",evidence:{userAgent:n,spoofedBrowser:!0}}:{tier:"human"}}var gt={GET:"data.read",HEAD:"data.read",OPTIONS:"data.read",POST:"data.write",PUT:"data.write",PATCH:"data.write",DELETE:"data.delete"},yt="data.write",mt="data";function ht(e){return gt[e.toUpperCase()]??yt}function vt(e){let t=e.indexOf(":");if(t>=0)return{purpose:e.slice(0,t)};let r=e.indexOf(".");return r>0&&r<e.length-1?{purpose:e.slice(0,r),actionCandidate:e}:{purpose:e}}function ce(e){let t=e.astraPurpose?vt(e.astraPurpose):void 0,r,n;e.routeAction?(r=e.routeAction,n="route_config"):e.hasCustomActionExtractor&&e.customAction?(r=e.customAction,n="custom_extractor"):!e.hasCustomActionExtractor&&e.astraAction?(r=e.astraAction,n="header"):!e.hasCustomActionExtractor&&t?.actionCandidate?(r=t.actionCandidate,n="purpose_header_derived"):(r=ht(e.method),n="method_table");let a,i;if(e.routePurpose?(a=e.routePurpose,i="route_config"):e.hasCustomPurposeExtractor?e.customPurpose&&(a=e.customPurpose,i="custom_extractor"):t?(a=t.purpose,i="header"):e.legacyPurpose?(a=e.legacyPurpose,i="legacy_header"):e.queryPurpose&&(a=e.queryPurpose,i="query"),!a){let o=r.indexOf(".");o>0?(a=r.slice(0,o),i="action_derived"):(a=mt,i="transport_default")}return{purpose:a,action:r,purposeSource:i,actionSource:n}}async function P(e,t){let r;try{return await Promise.race([e,new Promise(n=>{r=setTimeout(()=>n(void 0),t)})])}catch{return}finally{r&&clearTimeout(r)}}async function H(e,t,r,n){let a=c(t,"cloudfront-viewer-address")?.split(":")[0];await P(ae({apiBaseUrl:e.apiBaseUrl,counterpartyId:e.counterpartyId},{counterpartyUrl:e.counterpartyUrl,counterpartyType:"website",sourceIp:a,userAgent:c(t,"user-agent"),requestPath:t.uri,requestMethod:t.method,protocol:r.protocol,evidence:r.evidence,observedMetadata:I(t)}),n)}function de(e,t=Math.random){return e<=0?!1:e>=1?!0:t()<e}function w(e){return{tier:e.tier,decision:"allow",reasons:[],protocol:e.protocol}}function ue(e,t,r,n){let a=R(t.headers),i=c(t,"cloudfront-viewer-address")?.split(":")[0],o=ce({method:t.method,astraPurpose:c(t,"x-astra-purpose"),astraAction:c(t,"x-astra-action")}),s=c(t,"x-astra-attempt-id");return{...s&&/^att_[0-9a-f]{32}$/.test(s)&&{attemptId:s},credentials:E(a,{}),purpose:o.purpose,action:o.action,resource:t.uri,createSession:!0,counterpartyType:"website",counterpartyUrl:e.counterpartyUrl,callerMetadata:{sourceIp:i,userAgent:c(t,"user-agent"),referer:c(t,"referer"),host:c(t,"host"),observedMetadata:I(t)},...n&&r.artifacts&&{commerceArtifacts:r.artifacts}}}function pe(e,t){let r=w(e);return r.sessionId=t.sessionId,r.correlationId=t.correlationId,r.guidance=t.guidance,t.requiresStepUp||t.stepUpApproval?(r.decision="manual_review",r.reasons=["step-up approval required"],r.stepUp={pollUrl:t.stepUpApproval?.pollUrl,expiresAt:t.stepUpApproval?.expiresAt},r):!t.identityVerified||!t.policyAllowed?(r.decision="deny",r.reasons=t.denialReasons?.length?t.denialReasons:[t.identityVerified?"denied by access policy":"identity not verified"],r):(r.asat={trustScore:t.agent?.trustScore,agentId:t.agent?.astraId,developerId:t.developer?.astradId,accessLevel:t.accessLevel},r)}async function le(e,t,r,n,a,i){let o=e.budgets??{},s=o.beaconMs??300,p=n.mode==="enforce"?o.verifyEnforceMs??3e3:o.verifyObserveMs??1500,f={apiBaseUrl:e.apiBaseUrl,...a&&{apiKey:a},counterpartyId:e.counterpartyId,disableInitChecks:!0};try{switch(r.tier){case"verified":{if(n.depth==="classify")return w(r);let d=await P(B(f,ue(e,t,r,n.depth==="authorize")),p);if(!d){let u=w(r);return u.reasons=["verify-access unreachable within budget \u2014 fail-open"],u}return pe(r,d)}case"identified":{if(n.depth==="authorize"&&r.artifacts){let u=await P(B(f,ue(e,t,r,!0)),p);if(!u){let m=w(r);return m.reasons=["verify-access unreachable within budget \u2014 fail-open"],m}return pe(r,u)}await H(e,t,r,s);let d=w(r);return n.mode==="enforce"&&n.depth!=="classify"&&(d.decision="deny",d.reasons=["agent is not registered with AstraSync"]),d}case"anonymous-bot":return de(i.anonymousBeaconRate,e.random)&&await H(e,t,{...r,protocol:r.protocol??"ua-heuristic"},s),w(r);default:return w(r)}}catch(d){let u=w(r);return u.reasons=[`edge pipeline error \u2014 fail-open: ${d instanceof Error?d.message:String(d)}`],u}}var At={"vi-sd-jwt":"This request presented Visa Intelligent Commerce credentials, but the agent is not verified with AstraSync. Register the agent to pair your VI credentials with a verified identity and mandate.","rfc9421-agent-pay":"This request carried a Mastercard Agent Pay signature, but the agent is not verified with AstraSync. Register the agent to pair Agent Pay credentials with a verified identity and mandate.","rfc9421-tap":"This request carried a Visa TAP signature, but the agent is not verified with AstraSync. Register the agent to pair TAP credentials with a verified identity and mandate.","rfc9421-web-bot-auth":"This request carried a Web Bot Auth signature, but the agent is not verified with AstraSync. Register the agent to link your signed-agent identity to a verified principal.",rfc9421:"This request carried an RFC 9421 HTTP message signature, but the agent is not verified with AstraSync. Register the agent to link the signing identity to a verified principal.",acp:"This request used the Agentic Commerce Protocol, but the agent is not verified with AstraSync. Register the agent to transact on this property.",ucp:"This request used a UCP checkout session, but the agent is not verified with AstraSync. Register the agent to transact on this property.",ap2:"This request presented AP2 mandates, but the agent is not verified with AstraSync. Register the agent to pair your mandates with a verified identity.",mpp:"This request presented MPP payment credentials, but the agent is not verified with AstraSync. Register the agent to transact on this property.",x402:"This request used x402 payment headers, but the agent is not verified with AstraSync. Register the agent to transact on this property.","platform-ua":"This traffic was identified as a platform AI agent without AstraSync credentials. Register the agent to access this property with a verified identity.","x-astra":"The presented AstraSync credentials failed verification or were denied by this property\u2019s access policy."};function fe(e,t){let r=t.replace(/\/api\/?$/,""),n=(e.protocol&&At[e.protocol])??"This request could not be verified by AstraSync.";return{success:!1,error:{code:e.tier==="verified"?"INSUFFICIENT_ACCESS":"UNAUTHORIZED",message:n,...e.protocol&&{protocol:e.protocol},failures:e.reasons,...e.correlationId&&{correlationId:e.correlationId},guidance:{message:e.guidance?.message||"Register this agent with AstraSync to receive verifiable credentials.",registrationUrl:e.guidance?.registrationUrl||`${r}/register`,documentationUrl:e.guidance?.documentationUrl||`${r}/docs/edge-adapter`}}}}function ge(e){return{success:!1,status:"manual_review",message:"This action requires human approval. Poll the step-up approval endpoint and retry once approved.",...e.stepUp&&{stepUpApproval:e.stepUp},...e.correlationId&&{correlationId:e.correlationId}}}var S={trustScore:"X-AstraSync-Trust-Score",agentId:"X-AstraSync-Agent-Id",developerId:"X-AstraSync-Developer-Id",permissions:"X-AstraSync-Permissions",observedDecision:"X-AstraSync-Observed-Decision"};function me(e,t,r,n){if(j(t,"x-astrasync-"),n.mode!=="enforce")return r.decision!=="allow"&&A(t,S.observedDecision,r.decision),ye(t,r),t;switch(r.decision){case"deny":return x(403,fe(r,e.apiBaseUrl));case"manual_review":return x(202,ge(r),{"Retry-After":"30"});default:return ye(t,r),t}}function ye(e,t){if(!t.asat)return;let{trustScore:r,agentId:n,developerId:a,accessLevel:i}=t.asat;r!==void 0&&A(e,S.trustScore,String(r)),n&&A(e,S.agentId,n),a&&A(e,S.developerId,a),i&&A(e,S.permissions,i)}function he(e){let t=e.log??((r,n,a)=>{console[r==="info"?"log":r](`[astrasync-edge] ${n}`,a??"")});return async function(n){let a=N(n);try{K(a);let i=await W({...e,log:t}),o=await Z(e,i),s=ie(o,a.uri);if(s.skip)return a;let p=c(a,"x-forwarded-host")??c(a,"host")??new URL(e.counterpartyUrl).host,f=se(a,p,s.depth);if(f.tier==="human")return a;let d=await le({...e,log:t},a,f,s,i,o.sampling);return d.decision!=="allow"&&t("info",s.mode==="enforce"?`${d.decision.toUpperCase()}: ${a.method} ${a.uri}`:`[OBSERVE] would have been ${d.decision.toUpperCase()}: ${a.method} ${a.uri}`,{tier:d.tier,protocol:d.protocol,reasons:d.reasons}),me(e,a,d,s)}catch(i){return t("error","edge handler error \u2014 passing request through",{error:i instanceof Error?i.message:String(i)}),a}}}var wt="https://astrasync.ai/api",ve="",Ae="",Rt=void 0;(!ve||!Ae)&&console.error("[astrasync-edge] ASTRASYNC_COUNTERPARTY_ID / ASTRASYNC_COUNTERPARTY_URL were not baked into the bundle \u2014 rebuild via infra/deploy.sh with the ASTRASYNC_* env vars set.");var Ct=he({apiBaseUrl:wt,counterpartyId:ve,counterpartyUrl:Ae,apiKeySecretName:Rt});0&&(module.exports={handler});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrasyncai/adapter-lambda",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "AstraSync Commerce Shield edge adapter — Lambda@Edge/CloudFront interception shell that classifies and verifies inbound agent traffic against the AstraSync platform. Observe-only by default.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -44,7 +44,7 @@
44
44
  "directory": "packages/adapter-lambda"
45
45
  },
46
46
  "dependencies": {
47
- "@astrasyncai/verification-gateway": "^3.10.0",
47
+ "@astrasyncai/verification-gateway": "^3.12.0",
48
48
  "@aws-sdk/client-secrets-manager": "^3.632.0"
49
49
  },
50
50
  "devDependencies": {