@deploybaseline/microsoft 0.0.0-stage → 0.14.1
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/LICENSE +202 -0
- package/NOTICE +11 -0
- package/README.md +35 -2
- package/THIRD_PARTY_NOTICES.md +622 -0
- package/api-reference.json +59783 -0
- package/dist/chunk-BEGIZZSN.js +4762 -0
- package/dist/chunk-BEGIZZSN.js.map +1 -0
- package/dist/chunk-G7326MH2.js +3837 -0
- package/dist/chunk-G7326MH2.js.map +1 -0
- package/dist/chunk-PBJS3RQA.js +41 -0
- package/dist/chunk-PBJS3RQA.js.map +1 -0
- package/dist/fonts/GeistPixel-Square.woff2 +0 -0
- package/dist/fonts/favicon.ico +0 -0
- package/dist/fonts/geist-sans.woff2 +0 -0
- package/dist/index.d.ts +355 -0
- package/dist/index.js +58927 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +5 -0
- package/dist/manifest.js +7 -0
- package/dist/manifest.js.map +1 -0
- package/dist/provider.d.ts +2 -0
- package/dist/provider.js +10 -0
- package/dist/provider.js.map +1 -0
- package/dist/upload-L2WXFOLU.js +11 -0
- package/dist/upload-L2WXFOLU.js.map +1 -0
- package/init.json +20 -0
- package/package.json +93 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/base-url.ts","../../core/src/compose.ts","../../core/src/control.ts","../../core/src/oauth-helpers.ts","../../core/src/redact.ts","../../core/src/snapshots.ts","../../core/src/persistence.ts","../../core/src/state.ts","../../core/src/middleware/auth.ts","../../core/src/debug.ts","../../core/src/ui.ts","../../core/src/fonts.ts","../../core/src/http.ts","../../core/src/custom-inspector.ts","../../core/src/webhook-signing.ts","../../core/src/webhooks.ts","../../core/src/custom.ts","../../core/src/faults.ts","../../core/src/identities.ts","../../core/src/middleware/error-handler.ts","../../core/src/middleware/pagination.ts","../../core/src/mount.ts","../../core/src/oidc-kit.ts","../../core/src/optional-package.ts","../../core/src/protocol.ts","../../core/src/provider-client.ts","../../core/src/run-provider.ts","../../core/src/store.ts","../../core/src/server.ts","../../core/src/sql-state.ts","../../core/src/xml.ts","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/buffer_utils.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/util/errors.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/util/base64url.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/validate.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/key.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/key_descriptor.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jwe_algorithms.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jws_algorithms.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jws_verify.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jwt_claims_set.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/jwt/verify.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/jws_sign.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/jwt/sign.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/key_algorithm.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/lib/asn1.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/key/import.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/util/decode_protected_header.js","../../../../node_modules/.pnpm/jose@6.2.12/node_modules/jose/dist/webapi/util/decode_jwt.js"],"sourcesContent":["export interface ResolveBaseUrlOptions {\n service: string;\n port: number;\n baseUrl?: string;\n seedBaseUrl?: string;\n}\n\n/**\n * Fallback chain:\n * 1. Per-service baseUrl from seed config\n * 2. Explicit baseUrl (CLI flag or programmatic option)\n * 3. BASELINE_BASE_URL env var (with {service} interpolation)\n * 4. http://localhost:<port>\n */\nexport function resolveBaseUrl(opts: ResolveBaseUrlOptions): string {\n if (opts.seedBaseUrl) {\n return opts.seedBaseUrl.replace(/\\{service\\}/g, opts.service);\n }\n if (opts.baseUrl) {\n return opts.baseUrl.replace(/\\{service\\}/g, opts.service);\n }\n const envBaseUrl = process.env.BASELINE_BASE_URL;\n if (envBaseUrl) {\n return envBaseUrl.replace(/\\{service\\}/g, opts.service);\n }\n return `http://localhost:${opts.port}`;\n}\n","import type { Hono } from \"./http.js\";\nimport type { AppEnv, TokenMap } from \"./middleware/auth.js\";\nimport type { RouteContext, ServicePlugin } from \"./plugin.js\";\nimport type { Store } from \"./store.js\";\nimport type { WebhookDispatcher } from \"./webhooks.js\";\n\n/** One API surface of a composed service, e.g. Gmail inside Google. */\nexport interface ServiceModule {\n name: string;\n /**\n * Store collections this module creates. Names must be namespaced\n * (`gmail.messages`). A module may read collections another module owns.\n */\n collections?: readonly string[];\n register(ctx: RouteContext): void;\n seed?(ctx: { store: Store; baseUrl: string }): void;\n}\n\nexport interface ComposedService extends ServicePlugin {\n readonly modules: readonly ServiceModule[];\n /** Routes (`\"METHOD /pattern\"`) and operations (`\"Query.issues\"`) each module registered, from the last register() call. */\n moduleRoutes(): ReadonlyMap<string, readonly string[]>;\n}\n\n/**\n * Build one service (one server, store, token map, and seed key) from several\n * route modules. Modules register in array order, so a module with catch-all\n * routes (such as `/:id`) goes last.\n */\nexport function composeService(options: { name: string; modules: readonly ServiceModule[] }): ComposedService {\n const { name, modules } = options;\n const owners = new Map<string, string>();\n const moduleNames = new Set<string>();\n for (const module of modules) {\n if (moduleNames.has(module.name)) {\n throw new Error(`${name}: module ${module.name} is listed twice`);\n }\n moduleNames.add(module.name);\n for (const collection of module.collections ?? []) {\n if (!collection.includes(\".\")) {\n throw new Error(\n `${name}/${module.name}: collection \"${collection}\" must be namespaced, e.g. \"${module.name}.${collection}\"`,\n );\n }\n const owner = owners.get(collection);\n if (owner) {\n throw new Error(`${name}: modules ${owner} and ${module.name} both own collection \"${collection}\"`);\n }\n owners.set(collection, module.name);\n }\n }\n\n let routes = new Map<string, readonly string[]>();\n\n return {\n name,\n modules,\n moduleRoutes: () => routes,\n register(app: Hono<AppEnv>, store: Store, webhooks: WebhookDispatcher, baseUrl: string, tokenMap?: TokenMap): void {\n const registered = new Map<string, readonly string[]>();\n const routeOwner = new Map<string, string>();\n for (const module of modules) {\n const before = app.routeTable.length;\n const operationsBefore = app.operationTable.length;\n const upgradesBefore = app.upgradeTable.length;\n module.register({ app, store: guardedStore(store, name, module.name, owners), webhooks, baseUrl, tokenMap });\n // Operations (GraphQL root fields) belong to the module that declared them, like routes.\n const added = [\n ...app.routeTable.slice(before).map((route) => `${route.method} ${route.path}`),\n ...app.upgradeTable.slice(upgradesBefore).map((path) => `WS ${path}`),\n ...app.operationTable.slice(operationsBefore),\n ];\n for (const route of added) {\n const owner = routeOwner.get(route);\n if (owner) {\n throw new Error(`${name}: modules ${owner} and ${module.name} both register ${route}`);\n }\n routeOwner.set(route, module.name);\n }\n registered.set(module.name, added);\n }\n routes = registered;\n },\n seed(store: Store, baseUrl: string): void {\n for (const module of modules) {\n module.seed?.({ store: guardedStore(store, name, module.name, owners), baseUrl });\n }\n },\n };\n}\n\n// Creating a collection nobody declared fails, so modules cannot collide by\n// accident. Reading an existing collection, including another module's, is fine.\nfunction guardedStore(store: Store, service: string, module: string, owners: ReadonlyMap<string, string>): Store {\n return new Proxy(store, {\n get(target, property, receiver) {\n if (property !== \"collection\") {\n const value = Reflect.get(target, property, receiver);\n return typeof value === \"function\" ? value.bind(target) : value;\n }\n return (collection: string, indexFields?: never[]) => {\n if (!(target.hasCollection(collection) || owners.has(collection))) {\n throw new Error(\n `${service}/${module}: creates collection \"${collection}\" without declaring it in collections`,\n );\n }\n return target.collection(collection, indexFields);\n };\n },\n });\n}\n","import { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport type { ActiveFaults, FaultInjector } from \"./faults.js\";\nimport { parseCookies } from \"./oauth-helpers.js\";\nimport { redactState } from \"./redact.js\";\nimport { checkSnapshotName, type SnapshotInfo, SnapshotNameError, type SnapshotStore } from \"./snapshots.js\";\nimport { parseStateFile, type StateFile, StateFileError, StateVersionError } from \"./state.js\";\nimport { escapeAttr, escapeHtml, type InspectorTab, renderInspectorPage } from \"./ui.js\";\n\nconst URL_SCHEME = /^[a-z]+:\\/\\//i;\nconst FAULT_PATH = /^\\/_baseline\\/faults\\/([^/]+)$/;\nconst SNAPSHOT_PATH = /^\\/_baseline\\/state\\/snapshots\\/([^/]+)(\\/restore)?$/;\nconst PORT_SUFFIX = /:\\d+$/;\n\nconst TOKEN_HEADER = \"x-baseline-control-token\";\nconst COOKIE = \"baseline_control\";\nconst LOOPBACK = new Set([\"localhost\", \"127.0.0.1\", \"::1\"]);\n\nconst INSPECTOR = \"/_baseline/control/inspector\";\nconst STATE_PAGE = `${INSPECTOR}/state`;\nconst TABS: InspectorTab[] = [\n { id: \"faults\", label: \"Faults\", href: INSPECTOR },\n { id: \"state\", label: \"State\", href: STATE_PAGE },\n];\nconst NO_STORE = { \"Cache-Control\": \"no-store\" };\n\ntype Fetch = (request: Request) => Response | Promise<Response>;\n\n/** What a state replacement did to each service. */\nexport interface RestoreSummary {\n /** Running services whose state was replaced. */\n restored: string[];\n /** Running services the new state had nothing for; left as they were. */\n unchanged: string[];\n /** Services in the new state that are not running here. */\n ignored: string[];\n}\n\n/** The process's live state, as the `/_baseline/state` endpoints see it. */\nexport interface ControlState {\n /** Where state is saved (a file path), or undefined when it lives only in memory. */\n readonly target?: string;\n /** When state was last written to the target. */\n readonly savedAt?: Date;\n /** Every running service's state, as a snapshot would hold it. */\n capture(): Promise<StateFile>;\n /**\n * Replace the running services' state. Throws `StateVersionError` or\n * `StateFileError` when the state does not fit, leaving everything as it was.\n */\n replace(state: StateFile): Promise<RestoreSummary>;\n readonly snapshots: SnapshotStore;\n}\n\nexport interface ControlService {\n name: string;\n url: string;\n port: number;\n faults: FaultInjector;\n /**\n * Called with the config a client set (or `[]` when it cleared the faults), after it was\n * validated. A service in another process applies its faults there. The control API answers\n * once this settles.\n */\n onFaultsChange?(config: unknown): void | Promise<void>;\n}\n\n/**\n * The `/_baseline/*` control router shared by every service in a process. Any\n * service port answers for all of them. Requests must come from a loopback or\n * configured host (DNS rebinding), carry no foreign Origin (cross-site), and\n * present the per-process token. The token goes in a header; the inspector\n * cookie only authorizes reads, and is set only after the token was presented.\n */\nexport class ControlPlane {\n readonly token: string;\n private readonly services = new Map<string, ControlService>();\n private readonly allowedHosts = new Set<string>();\n private readonly formToken: string;\n private state: ControlState | undefined;\n\n constructor(options: { token?: string; allowedHosts?: Iterable<string> } = {}) {\n this.token = options.token ?? randomBytes(24).toString(\"base64url\");\n for (const host of options.allowedHosts ?? []) {\n this.allowHost(host);\n }\n // Inspector forms carry this alongside the cookie. Pages on other localhost\n // ports share the cookie's site but cannot read the inspector to learn it.\n this.formToken = createHmac(\"sha256\", this.token).update(\"baseline inspector form\").digest(\"base64url\");\n }\n\n /** Serve `/_baseline/state` and the inspector's State tab from this state. */\n setState(state: ControlState): void {\n this.state = state;\n }\n\n /** Accept requests addressed to this host, e.g. the host of a configured base URL. */\n allowHost(hostOrUrl: string): void {\n const host = URL_SCHEME.test(hostOrUrl) ? new URL(hostOrUrl).hostname : hostOrUrl;\n this.allowedHosts.add(stripBrackets(host).toLowerCase());\n }\n\n addService(service: ControlService): void {\n if (this.services.has(service.name)) {\n throw new Error(`Control plane already has a service named ${service.name}`);\n }\n this.services.set(service.name, service);\n this.allowHost(service.url);\n }\n\n /** Wrap a service's fetch: control paths are answered here, everything else goes through faults to the service. */\n wrap(name: string, fetch: Fetch): Fetch {\n const service = this.services.get(name);\n if (!service) {\n throw new Error(`Unknown control service ${name}`);\n }\n const inner = service.faults.wrap(fetch);\n return async (request) => {\n const control = await this.handle(request);\n if (control) {\n return control;\n }\n return inner(request);\n };\n }\n\n /** Answer a control request, or return undefined when the path is not a control path. */\n async handle(request: Request): Promise<Response | undefined> {\n const url = new URL(request.url);\n if (![\"control\", \"faults\", \"state\"].some((root) => isUnder(url.pathname, `/_baseline/${root}`))) {\n return undefined;\n }\n if (request.method === \"POST\" && url.pathname === STATE_PAGE) {\n return this.inspectorAction(request);\n }\n const denied = this.check(request);\n if (denied) {\n return denied;\n }\n if (isUnder(url.pathname, \"/_baseline/state\")) {\n return this.handleState(request, url);\n }\n\n if (request.method === \"GET\" && url.pathname === \"/_baseline/control\") {\n return Response.json({\n pid: process.pid,\n services: [...this.services.values()].map(({ name, url: serviceUrl, port }) => ({\n name,\n url: serviceUrl,\n port,\n })),\n });\n }\n // Opening a printed inspector link (?token=...) swaps the token for a\n // cookie and drops it from the address bar.\n if (\n request.method === \"GET\" &&\n (url.pathname === INSPECTOR || url.pathname === STATE_PAGE) &&\n url.searchParams.has(\"token\")\n ) {\n return new Response(null, {\n status: 303,\n headers: {\n Location: url.pathname,\n \"Set-Cookie\": `${COOKIE}=${this.token}; HttpOnly; SameSite=Strict; Path=/_baseline`,\n },\n });\n }\n if (request.method === \"GET\" && url.pathname === STATE_PAGE) {\n return new Response(await this.renderStatePage(url), {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\", ...NO_STORE },\n });\n }\n if (request.method === \"GET\" && url.pathname === INSPECTOR) {\n return new Response(this.renderInspector(), { headers: { \"Content-Type\": \"text/html; charset=utf-8\" } });\n }\n if (url.pathname === \"/_baseline/faults\") {\n if (request.method === \"GET\") {\n return Response.json({ services: this.faultsSnapshot() });\n }\n if (request.method === \"POST\") {\n return this.setFaults(request);\n }\n if (request.method === \"DELETE\") {\n for (const service of this.services.values()) {\n service.faults.clear();\n }\n const failed = await this.propagate([...this.services.values()], []);\n if (failed) {\n return failed;\n }\n return Response.json({ services: this.faultsSnapshot() });\n }\n }\n const match = FAULT_PATH.exec(url.pathname);\n if (match && request.method === \"DELETE\") {\n let name: string;\n try {\n name = decodeURIComponent(match[1]);\n } catch {\n return Response.json({ error: \"Malformed service name\" }, { status: 400 });\n }\n const service = this.services.get(name);\n if (!service) {\n return Response.json({ error: `Unknown service ${match[1]}` }, { status: 404 });\n }\n service.faults.clear();\n const failed = await this.propagate([service], []);\n if (failed) {\n return failed;\n }\n return Response.json({ service: service.name, faults: service.faults.current() });\n }\n return Response.json({ error: \"Not found\" }, { status: 404 });\n }\n\n private async handleState(request: Request, url: URL): Promise<Response> {\n const { state } = this;\n if (!state) {\n return Response.json({ error: \"State endpoints are not available in this runtime\" }, { status: 404 });\n }\n const json = (body: unknown, status = 200) => Response.json(body, { status, headers: NO_STORE });\n const redact = (value: StateFile) => (isTrue(url.searchParams.get(\"redact\")) ? redactState(value) : value);\n const download = (value: StateFile, name: string) =>\n new Response(`${JSON.stringify(redact(value), null, 2)}\\n`, {\n headers: {\n \"Content-Type\": \"application/json; charset=utf-8\",\n ...NO_STORE,\n ...(isTrue(url.searchParams.get(\"download\"))\n ? {\n \"Content-Disposition\": `attachment; filename=\"${name}${isTrue(url.searchParams.get(\"redact\")) ? \".redacted\" : \"\"}.json\"`,\n }\n : {}),\n },\n });\n try {\n if (url.pathname === \"/_baseline/state\") {\n if (request.method === \"GET\") {\n return download(await state.capture(), \"baseline-state\");\n }\n if (request.method === \"PUT\") {\n const parsed = parseStateFile(await request.text());\n return json(await state.replace(parsed));\n }\n return json({ error: \"Use GET or PUT\" }, 405);\n }\n if (url.pathname === \"/_baseline/state/snapshots\") {\n if (request.method === \"GET\") {\n return json({ store: state.snapshots.label, snapshots: await state.snapshots.list() });\n }\n if (request.method === \"POST\") {\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n body = undefined;\n }\n const name = checkSnapshotName((body as { name?: unknown } | undefined)?.name);\n const { snapshot, replaced } = await saveNamedSnapshot(state, name);\n return json({ snapshot, replaced }, replaced ? 200 : 201);\n }\n return json({ error: \"Use GET or POST\" }, 405);\n }\n const match = SNAPSHOT_PATH.exec(url.pathname);\n if (!match) {\n return json({ error: \"Not found\" }, 404);\n }\n let name: string;\n try {\n name = checkSnapshotName(decodeURIComponent(match[1]));\n } catch (error) {\n return json({ error: error instanceof Error ? error.message : String(error) }, 400);\n }\n if (match[2]) {\n if (request.method !== \"POST\") {\n return json({ error: \"Use POST\" }, 405);\n }\n return json({ snapshot: name, ...(await restoreNamedSnapshot(state, name)) });\n }\n if (request.method === \"GET\") {\n const data = await state.snapshots.load(name);\n if (data === null) {\n return json({ error: `No snapshot named ${name}` }, 404);\n }\n return download(parseStateFile(data), name);\n }\n if (request.method === \"DELETE\") {\n if (!(await state.snapshots.delete(name))) {\n return json({ error: `No snapshot named ${name}` }, 404);\n }\n return json({ deleted: name });\n }\n return json({ error: \"Use GET, DELETE, or POST .../restore\" }, 405);\n } catch (error) {\n const { status, message } = describeStateError(error);\n return json({ error: message }, status);\n }\n }\n\n // Inspector buttons post forms: the cookie proves the token was presented,\n // and the form token proves the form came from the inspector page itself.\n private async inspectorAction(request: Request): Promise<Response> {\n const denied = this.checkOrigin(request);\n if (denied) {\n return denied;\n }\n const cookie = parseCookies(request.headers.get(\"cookie\") ?? \"\")[COOKIE] ?? \"\";\n let form: FormData | undefined;\n try {\n form = await request.formData();\n } catch {\n form = undefined;\n }\n const field = (name: string) => {\n const value = form?.get(name);\n return typeof value === \"string\" ? value : \"\";\n };\n if (!(safeEqual(cookie, this.token) && safeEqual(field(\"form_token\"), this.formToken))) {\n return Response.json(\n { error: \"Open the inspector from the link printed at start, then try again.\" },\n { status: 401 },\n );\n }\n const back = (kind: \"message\" | \"error\", text: string) =>\n new Response(null, { status: 303, headers: { Location: `${STATE_PAGE}?${kind}=${encodeURIComponent(text)}` } });\n const { state } = this;\n if (!state) {\n return back(\"error\", \"State is not available in this runtime\");\n }\n const action = field(\"action\");\n try {\n const name = checkSnapshotName(field(\"name\").trim());\n if (action === \"save\") {\n const { replaced } = await saveNamedSnapshot(state, name);\n return back(\"message\", `${replaced ? \"Replaced\" : \"Saved\"} snapshot ${name}`);\n }\n if (action === \"restore\") {\n const summary = await restoreNamedSnapshot(state, name);\n return back(\"message\", `Restored snapshot ${name}${describeSummary(summary)}`);\n }\n if (action === \"delete\") {\n if (!(await state.snapshots.delete(name))) {\n return back(\"error\", `No snapshot named ${name}`);\n }\n return back(\"message\", `Deleted snapshot ${name}`);\n }\n return back(\"error\", `Unknown action ${action}`);\n } catch (error) {\n return back(\"error\", describeStateError(error).message);\n }\n }\n\n private async setFaults(request: Request): Promise<Response> {\n let body: { service?: unknown; faults?: unknown } | null;\n try {\n body = (await request.json()) as { service?: unknown; faults?: unknown } | null;\n } catch {\n body = null;\n }\n if (!body || typeof body !== \"object\" || Array.isArray(body)) {\n return Response.json({ error: \"Body must be JSON: { service, faults }\" }, { status: 400 });\n }\n const service = typeof body.service === \"string\" ? this.services.get(body.service) : undefined;\n if (!service) {\n return Response.json({ error: `Unknown service ${String(body.service)}` }, { status: 404 });\n }\n let faults: ActiveFaults;\n try {\n faults = service.faults.set(body.faults ?? []);\n } catch (error) {\n return Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 400 });\n }\n const failed = await this.propagate([service], body.faults ?? []);\n if (failed) {\n return failed;\n }\n return Response.json({ service: service.name, faults });\n }\n\n // Hand a fault change to services that apply faults elsewhere (a provider process).\n private async propagate(services: ControlService[], config: unknown): Promise<Response | undefined> {\n const results = await Promise.allSettled(services.map((service) => service.onFaultsChange?.(config)));\n const errors = results.flatMap((result, index) =>\n result.status === \"rejected\"\n ? [`${services[index].name}: ${result.reason instanceof Error ? result.reason.message : result.reason}`]\n : [],\n );\n return errors.length\n ? Response.json({ error: `Could not apply faults (${errors.join(\"; \")})` }, { status: 502 })\n : undefined;\n }\n\n private faultsSnapshot() {\n return Object.fromEntries([...this.services.values()].map((service) => [service.name, service.faults.current()]));\n }\n\n private check(request: Request): Response | undefined {\n const denied = this.checkOrigin(request);\n if (denied) {\n return denied;\n }\n if (this.presentsToken(request)) {\n return undefined;\n }\n return Response.json(\n { error: \"Missing or wrong control token. Send it in the X-Baseline-Control-Token header.\" },\n { status: 401 },\n );\n }\n\n private checkOrigin(request: Request): Response | undefined {\n if (!this.hostAllowed(requestHost(request))) {\n return Response.json({ error: \"Host not allowed for the control API\" }, { status: 403 });\n }\n const origin = request.headers.get(\"origin\");\n if (origin !== null && (origin === \"null\" || !this.hostAllowed(safeHost(origin)))) {\n return Response.json({ error: \"Cross-origin requests to the control API are not allowed\" }, { status: 403 });\n }\n if (request.headers.get(\"sec-fetch-site\") === \"cross-site\") {\n return Response.json({ error: \"Cross-site requests to the control API are not allowed\" }, { status: 403 });\n }\n return undefined;\n }\n\n // The header works for every request. The cookie works only for reads, so a\n // page on another localhost port cannot change faults with a simple POST.\n // The inspector link carries the token once as ?token=.\n private presentsToken(request: Request): boolean {\n const header = request.headers.get(TOKEN_HEADER);\n if (header !== null) {\n return safeEqual(header, this.token);\n }\n if (request.method !== \"GET\") {\n return false;\n }\n const url = new URL(request.url);\n if ((url.pathname === INSPECTOR || url.pathname === STATE_PAGE) && url.searchParams.has(\"token\")) {\n return safeEqual(url.searchParams.get(\"token\") ?? \"\", this.token);\n }\n return safeEqual(parseCookies(request.headers.get(\"cookie\") ?? \"\")[COOKIE] ?? \"\", this.token);\n }\n\n private hostAllowed(hostHeader: string | null | undefined): boolean {\n if (!hostHeader) {\n return false;\n }\n const host = stripBrackets(hostHeader.replace(PORT_SUFFIX, \"\")).toLowerCase();\n return LOOPBACK.has(host) || host.endsWith(\".localhost\") || this.allowedHosts.has(host);\n }\n\n private renderInspector(): string {\n const rows = [...this.services.values()]\n .map((service) => {\n const active = service.faults.current();\n const rules = active.rules.length\n ? active.rules\n .map((rule) => {\n const effect = [\n rule.latency_ms ? `+${rule.latency_ms} ms` : \"\",\n rule.response ? `respond ${rule.response.status}` : \"\",\n ]\n .filter(Boolean)\n .join(\", \");\n return `${escapeHtml(rule.match)} (${rule.rate ?? 1} chance): ${escapeHtml(effect)}`;\n })\n .join(\"<br>\")\n : \"none\";\n const note = [\n active.profile ? `profile ${active.profile}` : \"\",\n active.seed === undefined ? \"\" : `seed ${active.seed}`,\n ]\n .filter(Boolean)\n .join(\", \");\n return `<tr><td>${escapeHtml(service.name)}</td><td>${escapeHtml(service.url)}</td><td>${rules}</td><td>${escapeHtml(note)}</td></tr>`;\n })\n .join(\"\");\n const body = `<table class=\"inspector-table\"><thead><tr><th>Service</th><th>URL</th><th>Active faults</th><th></th></tr></thead><tbody>${rows}</tbody></table>`;\n return renderInspectorPage(\"Faults\", TABS, \"faults\", body, \"Baseline\");\n }\n\n private async renderStatePage(url: URL): Promise<string> {\n const { state } = this;\n if (!state) {\n return renderInspectorPage(\n \"State\",\n TABS,\n \"state\",\n `<p class=\"inspector-empty\">State is not available in this runtime.</p>`,\n \"Baseline\",\n );\n }\n const message = url.searchParams.get(\"message\");\n const error = url.searchParams.get(\"error\");\n let notice = \"\";\n if (message) {\n notice = `<p class=\"inspector-notice\">${escapeHtml(message)}</p>`;\n } else if (error) {\n notice = `<p class=\"inspector-notice inspector-notice-error\">${escapeHtml(error)}</p>`;\n }\n const current = await state.capture();\n const size = Buffer.byteLength(JSON.stringify(current));\n const where = state.target\n ? `Saved to <code>${escapeHtml(state.target)}</code>${state.savedAt ? `, last written ${escapeHtml(state.savedAt.toISOString())}` : \"; nothing has changed since start\"}.`\n : \"In memory only. Start with --state to keep it across restarts.\";\n const services = [\n ...Object.entries(current.services).map(([name, service]) => {\n const records = Object.values(service.store.collections).reduce((sum, item) => sum + item.items.length, 0);\n return `<tr><td>${escapeHtml(name)}</td><td>${records}</td><td>${service.tokens.length}</td><td>${service.webhooks.subscriptions.length}</td></tr>`;\n }),\n ...Object.keys(current.custom ?? {}).map(\n (name) => `<tr><td>${escapeHtml(name)}</td><td>custom</td><td></td><td></td></tr>`,\n ),\n ].join(\"\");\n const snapshots = await state.snapshots.list();\n const form = (action: string, name: string, label: string, className = \"inspector-action\") =>\n `<form method=\"post\" action=\"${STATE_PAGE}\" class=\"inspector-inline-form\"><input type=\"hidden\" name=\"form_token\" value=\"${escapeAttr(this.formToken)}\"><input type=\"hidden\" name=\"action\" value=\"${action}\"><input type=\"hidden\" name=\"name\" value=\"${escapeAttr(name)}\"><button type=\"submit\" class=\"${className}\">${label}</button></form>`;\n const snapshotRows = snapshots\n .map(\n (snapshot) =>\n `<tr><td>${escapeHtml(snapshot.name)}</td><td>${escapeHtml(snapshot.services.join(\", \"))}</td><td>${formatBytes(snapshot.size)}</td><td>${escapeHtml(snapshot.createdAt)}</td><td><div class=\"inspector-actions\">${form(\"restore\", snapshot.name, \"Restore\")}<a class=\"inspector-action\" href=\"/_baseline/state/snapshots/${encodeURIComponent(snapshot.name)}?download=1\">Download</a>${form(\"delete\", snapshot.name, \"Delete\", \"btn-revoke\")}</div></td></tr>`,\n )\n .join(\"\");\n const body = `${notice}\n<section class=\"inspector-section\">\n <h2>Current state</h2>\n <p class=\"info-text\">${where} ${formatBytes(size)}.</p>\n <div class=\"inspector-scroll\"><table class=\"inspector-table\"><thead><tr><th>Service</th><th>Records</th><th>Tokens</th><th>Webhooks</th></tr></thead><tbody>${services}</tbody></table></div>\n <div class=\"inspector-actions\">\n <a class=\"inspector-action\" href=\"/_baseline/state?download=1\">Download</a>\n <a class=\"inspector-action\" href=\"/_baseline/state?download=1&redact=1\">Download with secrets redacted</a>\n </div>\n</section>\n<section class=\"inspector-section\">\n <h2>Snapshots</h2>\n <p class=\"info-text\">Kept ${escapeHtml(state.snapshots.label)}. Restoring replaces the state of every service the snapshot holds.</p>\n ${\n snapshots.length\n ? `<div class=\"inspector-scroll\"><table class=\"inspector-table\"><thead><tr><th>Name</th><th>Services</th><th>Size</th><th>Saved</th><th></th></tr></thead><tbody>${snapshotRows}</tbody></table></div>`\n : `<p class=\"inspector-empty\">No snapshots yet.</p>`\n }\n <form method=\"post\" action=\"${STATE_PAGE}\" class=\"inspector-actions\">\n <input type=\"hidden\" name=\"form_token\" value=\"${escapeAttr(this.formToken)}\"><input type=\"hidden\" name=\"action\" value=\"save\">\n <input class=\"inspector-input\" name=\"name\" placeholder=\"snapshot name\" required pattern=\"[A-Za-z0-9][A-Za-z0-9._-]{0,63}\" aria-label=\"Snapshot name\">\n <button type=\"submit\" class=\"inspector-action\">Save snapshot</button>\n </form>\n</section>`;\n return renderInspectorPage(\"State\", TABS, \"state\", body, \"Baseline\");\n }\n}\n\n// The listener builds the request URL from the Host header, so the URL host is\n// the Host the client sent. In-process requests have no Host header at all.\nfunction requestHost(request: Request): string {\n return request.headers.get(\"host\") ?? new URL(request.url).host;\n}\n\n/** No snapshot has the requested name. */\nexport class SnapshotNotFoundError extends Error {\n override name = \"SnapshotNotFoundError\";\n}\n\n/** Save the current state as a named snapshot, replacing one with the same name. */\nexport async function saveNamedSnapshot(\n state: ControlState,\n name: string,\n): Promise<{ snapshot: SnapshotInfo; replaced: boolean }> {\n checkSnapshotName(name);\n const replaced = (await state.snapshots.load(name)) !== null;\n await state.snapshots.save(name, JSON.stringify(await state.capture()));\n const snapshot = (await state.snapshots.list()).find((info) => info.name === name);\n if (!snapshot) {\n throw new Error(`Snapshot ${name} was not saved`);\n }\n return { snapshot, replaced };\n}\n\n/** Replace the current state with a named snapshot. */\nexport async function restoreNamedSnapshot(state: ControlState, name: string): Promise<RestoreSummary> {\n checkSnapshotName(name);\n const data = await state.snapshots.load(name);\n if (data === null) {\n throw new SnapshotNotFoundError(`No snapshot named ${name}`);\n }\n return state.replace(parseStateFile(data));\n}\n\nfunction describeStateError(error: unknown): { status: number; message: string } {\n const message = error instanceof Error ? error.message : String(error);\n if (error instanceof SnapshotNotFoundError) {\n return { status: 404, message };\n }\n if (error instanceof StateVersionError || (error instanceof StateFileError && error.code === \"newer-format\")) {\n return { status: 409, message };\n }\n if (error instanceof StateFileError || error instanceof SnapshotNameError) {\n return { status: 400, message };\n }\n return { status: 500, message };\n}\n\nfunction describeSummary(summary: RestoreSummary): string {\n const parts = [\n summary.unchanged.length ? `left ${summary.unchanged.join(\", \")} as they were` : \"\",\n summary.ignored.length ? `ignored ${summary.ignored.join(\", \")} (not running)` : \"\",\n ].filter(Boolean);\n return parts.length ? `; ${parts.join(\"; \")}` : \"\";\n}\n\nfunction formatBytes(size: number): string {\n if (size < 1024) {\n return `${size} B`;\n }\n if (size < 1024 * 1024) {\n return `${(size / 1024).toFixed(1)} KB`;\n }\n return `${(size / 1024 / 1024).toFixed(1)} MB`;\n}\n\nconst isTrue = (value: string | null) => value !== null && value !== \"0\" && value !== \"false\";\n\nfunction isUnder(path: string, root: string): boolean {\n return path === root || path.startsWith(`${root}/`);\n}\n\nfunction stripBrackets(host: string): string {\n return host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n}\n\nfunction safeHost(origin: string): string | undefined {\n try {\n return new URL(origin).host;\n } catch {\n return undefined;\n }\n}\n\nfunction safeEqual(a: string, b: string): boolean {\n const left = Buffer.from(a);\n const right = Buffer.from(b);\n return left.length === right.length && timingSafeEqual(left, right);\n}\n","import { timingSafeEqual } from \"node:crypto\";\n\nconst TRAILING_SLASHES = /\\/+$/;\n\nexport function normalizeUri(uri: string): string {\n try {\n const u = new URL(uri);\n return `${u.origin}${u.pathname.replace(TRAILING_SLASHES, \"\")}`;\n } catch {\n return uri.replace(TRAILING_SLASHES, \"\").split(\"?\")[0];\n }\n}\n\nexport function matchesRedirectUri(incoming: string, registered: string[]): boolean {\n const normalized = normalizeUri(incoming);\n return registered.some((r) => normalizeUri(r) === normalized);\n}\n\nexport function constantTimeSecretEqual(a: string, b: string): boolean {\n const bufA = Buffer.from(a, \"utf-8\");\n const bufB = Buffer.from(b, \"utf-8\");\n if (bufA.length !== bufB.length) {\n return false;\n }\n return timingSafeEqual(bufA, bufB);\n}\n\nexport function bodyStr(v: unknown): string {\n if (typeof v === \"string\") {\n return v;\n }\n if (Array.isArray(v) && typeof v[0] === \"string\") {\n return v[0];\n }\n return \"\";\n}\n\nexport function parseCookies(header: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n for (const part of header.split(\";\")) {\n const [k, ...v] = part.split(\"=\");\n if (k) {\n cookies[k.trim()] = v.join(\"=\").trim();\n }\n }\n return cookies;\n}\n","import type { StateFile } from \"./state.js\";\n\n// Keys whose values are secrets: tokens, client secrets, passwords, signing\n// material, OAuth codes, and session ids. Checked against object keys in\n// provider stores, store data names (\"slack.signing_secret\"), and custom state.\nconst SECRET_KEY =\n /secret|passw|token|private|credential|signing|api_?key|session|verifier|cookie|^code$|_code$|codes$|auth_?code/i;\n// Keys that look secret but hold descriptions of secrets, not secrets.\nconst NOT_SECRET_KEY =\n /(_method|_methods|_type|_types|_url|_uri|_at|_ttl|_ttl_seconds|_expires_in|_expiry|_count|_id|_ids|_sid|_scope|_scopes|_hint|_name|_label)$/i;\n// Private parts of a JSON Web Key.\nconst JWK_PRIVATE = new Set([\"d\", \"p\", \"q\", \"dp\", \"dq\", \"qi\", \"k\"]);\n// Shorter strings are redacted where they are found but not searched for elsewhere.\nconst MIN_SHARED_LENGTH = 8;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport function isSecretKey(key: string): boolean {\n return SECRET_KEY.test(key) && !NOT_SECRET_KEY.test(key);\n}\n\n/**\n * A copy of `state` with secrets replaced by placeholders, for sharing or\n * reading. The same secret gets the same placeholder everywhere it appears\n * (a token as a value and as a map key), so references still line up. The\n * result is marked `redacted: true` and cannot be loaded, since restored keys\n * and tokens would not work.\n */\nexport function redactState(state: StateFile): StateFile {\n const placeholders = new Map<string, string>();\n const hide = (value: string): string => {\n let placeholder = placeholders.get(value);\n if (!placeholder) {\n placeholder = `redacted:${placeholders.size + 1}`;\n placeholders.set(value, placeholder);\n }\n return placeholder;\n };\n\n // Everything under a secret key: strings are hidden, structure is kept.\n const hideAll = (value: unknown): unknown => {\n if (typeof value === \"string\") {\n return hide(value);\n }\n if (Array.isArray(value)) {\n return value.map(hideAll);\n }\n if (isRecord(value)) {\n if (value.__type === \"Map\" && Array.isArray(value.entries)) {\n // A map under a secret name is keyed by the secrets (tokens, codes); its values are ordinary records.\n return {\n ...value,\n entries: (value.entries as unknown[]).map((entry) =>\n Array.isArray(entry) && entry.length === 2\n ? [typeof entry[0] === \"string\" ? hide(entry[0]) : entry[0], walk(entry[1])]\n : walk(entry),\n ),\n };\n }\n if (value.__type === \"Set\" && Array.isArray(value.values)) {\n return { ...value, values: value.values.map(hideAll) };\n }\n // A record that names its own secret parts (a signing key with private_jwk, a JWK) keeps its public parts.\n if (typeof value.kty === \"string\" || Object.keys(value).some(isSecretKey)) {\n return walk(value);\n }\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, hideAll(item)]));\n }\n return value;\n };\n\n const walk = (value: unknown): unknown => {\n if (typeof value === \"string\") {\n return value.includes(\"-----BEGIN\") ? hide(value) : value;\n }\n if (Array.isArray(value)) {\n return value.map(walk);\n }\n if (!isRecord(value)) {\n return value;\n }\n const jwk = typeof value.kty === \"string\";\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => {\n if ((jwk && JWK_PRIVATE.has(key)) || (key !== \"__type\" && isSecretKey(key))) {\n return [key, hideAll(item)];\n }\n return [key, walk(item)];\n }),\n );\n };\n\n const redacted: StateFile = { ...state, redacted: true, services: {} };\n for (const [name, service] of Object.entries(state.services)) {\n redacted.services[name] = {\n stateVersion: service.stateVersion,\n store: {\n // Collection names (\"slack.tokens\") say what the records are, not that every field is secret.\n collections: Object.fromEntries(\n Object.entries(service.store.collections).map(([key, collection]) => [\n key,\n { ...collection, items: collection.items.map((item) => walk(item) as typeof item) },\n ]),\n ),\n data: Object.fromEntries(\n Object.entries(service.store.data).map(([key, item]) => [key, isSecretKey(key) ? hideAll(item) : walk(item)]),\n ),\n },\n tokens: service.tokens.map((entry) => ({ ...entry, token: hide(entry.token) })),\n webhooks: walk(service.webhooks) as StateFile[\"services\"][string][\"webhooks\"],\n };\n }\n if (state.generatedSecrets) {\n redacted.generatedSecrets = state.generatedSecrets.map((secret) => ({ ...secret, value: hide(secret.value) }));\n }\n if (state.custom) {\n redacted.custom = walk(state.custom) as StateFile[\"custom\"];\n }\n\n // A secret found under one name can appear elsewhere as a plain value or a\n // key (a token in a map of sessions). Replace those copies too.\n const shared = new Map([...placeholders].filter(([value]) => value.length >= MIN_SHARED_LENGTH));\n if (!shared.size) {\n return redacted;\n }\n const replace = (value: unknown): unknown => {\n if (typeof value === \"string\") {\n return shared.get(value) ?? value;\n }\n if (Array.isArray(value)) {\n return value.map(replace);\n }\n if (!isRecord(value)) {\n return value;\n }\n return Object.fromEntries(Object.entries(value).map(([key, item]) => [shared.get(key) ?? key, replace(item)]));\n };\n const { format, createdBy, seeds } = redacted;\n return {\n ...(replace(redacted) as StateFile),\n format,\n createdBy,\n ...(seeds ? { seeds } : {}),\n };\n}\n","import { readdir, readFile, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { filePersistence } from \"./persistence.js\";\n\n/** A named snapshot as listed: what it holds and when it was taken. */\nexport interface SnapshotInfo {\n name: string;\n /** ISO 8601 time the snapshot was saved. */\n createdAt: string;\n /** Size of the saved state in bytes. */\n size: number;\n /** Services the snapshot holds, built-in and custom. */\n services: string[];\n}\n\n/**\n * Where named snapshots live. Each snapshot is a whole `StateFile`, stored as\n * JSON text. Names are checked with `checkSnapshotName` before they get here.\n */\nexport interface SnapshotStore {\n /** Where the snapshots are kept, for messages: \"in memory\", \"in .baseline/state.snapshots\". */\n readonly label: string;\n list(): Promise<SnapshotInfo[]>;\n load(name: string): Promise<string | null>;\n save(name: string, data: string): Promise<void>;\n /** False when there was no snapshot with that name. */\n delete(name: string): Promise<boolean>;\n}\n\n/** A snapshot name that cannot be used. */\nexport class SnapshotNameError extends Error {\n override name = \"SnapshotNameError\";\n}\n\nconst NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;\n\n/**\n * Throw unless `name` is usable as a snapshot name: 1 to 64 letters, digits,\n * dots, underscores, or hyphens, starting with a letter or digit. \"current\"\n * is reserved for the live state in database targets.\n */\nexport function checkSnapshotName(name: unknown): string {\n if (typeof name !== \"string\" || !NAME.test(name)) {\n throw new SnapshotNameError(\n `Invalid snapshot name ${JSON.stringify(name)}. Use 1 to 64 letters, digits, dots, underscores, or hyphens, starting with a letter or digit.`,\n );\n }\n if (name.toLowerCase() === \"current\") {\n throw new SnapshotNameError(`\"current\" is reserved for the live state; pick another name`);\n }\n return name;\n}\n\n/** Services named in serialized state, without validating the rest of it. */\nexport function snapshotServices(data: string): string[] {\n try {\n const value = JSON.parse(data) as { services?: unknown; custom?: unknown };\n const names = (record: unknown) =>\n record && typeof record === \"object\" && !Array.isArray(record) ? Object.keys(record) : [];\n return [...names(value.services), ...names(value.custom)];\n } catch {\n return [];\n }\n}\n\nconst byTime = (a: SnapshotInfo, b: SnapshotInfo) =>\n a.createdAt === b.createdAt ? a.name.localeCompare(b.name) : a.createdAt.localeCompare(b.createdAt);\n\n/** Snapshots kept for the life of the process. */\nexport function memorySnapshotStore(): SnapshotStore {\n const snapshots = new Map<string, { data: string; createdAt: string }>();\n return {\n label: \"in memory\",\n async list() {\n return [...snapshots]\n .map(([name, { data, createdAt }]) => ({\n name,\n createdAt,\n size: Buffer.byteLength(data),\n services: snapshotServices(data),\n }))\n .sort(byTime);\n },\n async load(name) {\n return snapshots.get(name)?.data ?? null;\n },\n async save(name, data) {\n snapshots.set(name, { data, createdAt: new Date().toISOString() });\n },\n async delete(name) {\n return snapshots.delete(name);\n },\n };\n}\n\n/**\n * Snapshots as `<name>.json` files in a folder, written atomically with\n * owner-only permissions like the state file itself.\n */\nexport function fileSnapshotStore(directory: string, label = `in ${directory}`): SnapshotStore {\n const path = (name: string) => join(directory, `${checkSnapshotName(name)}.json`);\n return {\n label,\n async list() {\n let files: string[];\n try {\n files = await readdir(directory);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n const infos: SnapshotInfo[] = [];\n for (const file of files) {\n const name = file.slice(0, -\".json\".length);\n if (!(file.endsWith(\".json\") && NAME.test(name)) || name.toLowerCase() === \"current\") {\n continue;\n }\n try {\n const [data, info] = await Promise.all([\n readFile(join(directory, file), \"utf8\"),\n stat(join(directory, file)),\n ]);\n infos.push({\n name,\n createdAt: info.mtime.toISOString(),\n size: info.size,\n services: snapshotServices(data),\n });\n } catch (error) {\n // Deleted between readdir and read.\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n }\n return infos.sort(byTime);\n },\n async load(name) {\n try {\n return await readFile(path(name), \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n },\n async save(name, data) {\n await filePersistence(path(name)).save(data);\n },\n async delete(name) {\n try {\n await unlink(path(name));\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return false;\n }\n throw error;\n }\n },\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { link, mkdir, open, readFile, rename, unlink } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nexport interface PersistenceAdapter {\n load(): Promise<string | null>;\n save(data: string): Promise<void>;\n initialize?(data: string): Promise<string>;\n}\n\nexport function filePersistence(path: string): PersistenceAdapter {\n return {\n async load() {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return null;\n }\n },\n async save(data: string) {\n await mkdir(dirname(path), { recursive: true });\n const temporaryPath = `${path}.${randomUUID()}.tmp`;\n try {\n const file = await open(temporaryPath, \"wx\", 0o600);\n try {\n await file.chmod(0o600);\n await file.writeFile(data, \"utf-8\");\n await file.sync();\n } finally {\n await file.close();\n }\n await rename(temporaryPath, path);\n } finally {\n await unlink(temporaryPath).catch(() => {\n // Best effort: the failure is ignored.\n });\n }\n },\n async initialize(data: string) {\n await mkdir(dirname(path), { recursive: true });\n const temporaryPath = `${path}.${randomUUID()}.tmp`;\n try {\n const file = await open(temporaryPath, \"wx\", 0o600);\n try {\n await file.chmod(0o600);\n await file.writeFile(data, \"utf-8\");\n await file.sync();\n } finally {\n await file.close();\n }\n try {\n await link(temporaryPath, path);\n return data;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw error;\n }\n return await readFile(path, \"utf-8\");\n }\n } finally {\n await unlink(temporaryPath).catch(() => {\n // Best effort: the failure is ignored.\n });\n }\n },\n };\n}\n","import { createHash } from \"node:crypto\";\nimport type { EmulatorSnapshot } from \"./custom.js\";\nimport { restoreTokenMap, serializeTokenMap, type TokenEntry, type TokenMap } from \"./middleware/auth.js\";\nimport type { CollectionSnapshot, Store, StoreSnapshot } from \"./store.js\";\nimport type { WebhookDispatcher, WebhookDispatcherSnapshot } from \"./webhooks.js\";\n\ndeclare const __CORE_VERSION__: string | undefined;\n\n/**\n * Envelope version. Bump it when a change to this layout would break older readers.\n * Format 2 records which provider package wrote each service; formats 0 and 1 still load.\n */\nexport const STATE_FORMAT = 2;\n\n/** This SDK's version, or \"dev\" when it runs from source. */\nexport const SDK_VERSION = typeof __CORE_VERSION__ === \"string\" ? __CORE_VERSION__ : \"dev\";\n\n/** Name and version of the code that writes a state file, e.g. \"@deploybaseline/core@0.16.0\". */\nexport const STATE_WRITER = `@deploybaseline/core@${SDK_VERSION}`;\n\nexport interface GeneratedSecret {\n readonly service: string;\n readonly kind: string;\n readonly id: string;\n readonly label: string;\n readonly value: string;\n}\n\n/** Everything one built-in service needs to come back exactly as it was. */\nexport interface ServiceState {\n /** The provider package and version that wrote this state. Absent in format 1 files. */\n provider?: { package: string; version: string };\n /** The provider's `stateVersion` when this was saved. */\n stateVersion: number;\n store: StoreSnapshot;\n tokens: TokenEntry[];\n webhooks: WebhookDispatcherSnapshot;\n}\n\n/**\n * Saved emulator state, shared by the CLI, `createEmulator`, and custom\n * emulators. Webhook delivery history, rate limit counters, and pending\n * retries are not saved.\n */\nexport interface StateFile {\n format: typeof STATE_FORMAT;\n createdBy: string;\n services: Record<string, ServiceState>;\n generatedSecrets?: GeneratedSecret[];\n /** False while generated identities are reserved but the services are not seeded yet. */\n seeded?: boolean;\n custom?: Record<string, EmulatorSnapshot>;\n /**\n * Fingerprint of each service's seed config when its state was first seeded.\n * Lets a runner tell whether the seed changed since (`seedFingerprint`).\n */\n seeds?: Record<string, string>;\n /** Set by `redactState`: secrets are placeholders, so this state is for reading only. */\n redacted?: true;\n}\n\n/** The live pieces of a built-in service that a `ServiceState` captures. */\nexport interface ServiceStateTarget {\n store: Store;\n tokenMap: TokenMap;\n webhooks: WebhookDispatcher;\n}\n\nexport class StateFileError extends Error {\n override name = \"StateFileError\";\n constructor(\n message: string,\n options?: ErrorOptions & {\n /** `newer-format` means the file is fine but this version cannot read it: never overwrite it. */\n code?: \"invalid\" | \"newer-format\";\n },\n ) {\n super(message, options);\n this.code = options?.code ?? \"invalid\";\n }\n readonly code: \"invalid\" | \"newer-format\";\n}\n\n/** True for errors that must stop startup instead of falling back to a fresh seed. */\nexport function isFatalStateError(error: unknown): boolean {\n return error instanceof StateVersionError || (error instanceof StateFileError && error.code === \"newer-format\");\n}\n\n/** A service's saved state has a different `stateVersion` than the running provider. */\nexport class StateVersionError extends Error {\n readonly mismatches: ReadonlyArray<{ service: string; saved: number; expected: number }>;\n readonly createdBy: string;\n override name = \"StateVersionError\";\n constructor(\n mismatches: ReadonlyArray<{ service: string; saved: number; expected: number }>,\n createdBy: string,\n resetHint: string,\n ) {\n const lines = mismatches.map(\n ({ service, saved, expected }) =>\n `Saved state for ${service} has stateVersion ${saved}, but this version of baseline expects ${expected}.`,\n );\n super(\n `${lines.join(\"\\n\")}\\nThe saved shape is not compatible and is not migrated automatically. Either ${resetHint}, or run the version that wrote it (${createdBy}).`,\n );\n this.mismatches = mismatches;\n this.createdBy = createdBy;\n }\n}\n\nexport function captureServiceState(target: ServiceStateTarget, stateVersion: number): ServiceState {\n return {\n stateVersion,\n store: target.store.snapshot(),\n tokens: serializeTokenMap(target.tokenMap),\n webhooks: target.webhooks.snapshot(),\n };\n}\n\nexport function restoreServiceState(target: ServiceStateTarget, state: ServiceState): void {\n target.store.restore(state.store);\n restoreTokenMap(target.tokenMap, state.tokens);\n target.webhooks.restore(state.webhooks);\n}\n\n/** Stable fingerprint of a seed config: SHA-256 of its JSON with object keys sorted. */\nexport function seedFingerprint(seed: unknown): string {\n return createHash(\"sha256\")\n .update(stableJson(seed) ?? \"null\")\n .digest(\"hex\")\n .slice(0, 16);\n}\n\nfunction stableJson(value: unknown): string | undefined {\n if (Array.isArray(value)) {\n return `[${value.map((item) => stableJson(item) ?? \"null\").join(\",\")}]`;\n }\n if (isRecord(value)) {\n return `{${Object.keys(value)\n .sort()\n .flatMap((key) => {\n const item = stableJson(value[key]);\n return item === undefined ? [] : [`${JSON.stringify(key)}:${item}`];\n })\n .join(\",\")}}`;\n }\n return JSON.stringify(value);\n}\n\nexport function emptyStateFile(fields: Partial<Omit<StateFile, \"format\">> = {}): StateFile {\n return { format: STATE_FORMAT, createdBy: STATE_WRITER, services: {}, ...fields };\n}\n\n/**\n * Throw a `StateVersionError` naming every service whose saved `stateVersion`\n * differs from `expected`. Services missing from either side are fine: a new\n * service seeds, and state for a service that is not running is kept as is.\n */\nexport function checkStateVersions(\n state: StateFile,\n expected: ReadonlyMap<string, number> | Record<string, number>,\n resetHint = \"remove the saved state so the emulator reseeds\",\n): void {\n const entries = expected instanceof Map ? [...expected] : Object.entries(expected);\n const mismatches = entries.flatMap(([service, version]) => {\n const saved = state.services[service];\n return saved && saved.stateVersion !== version ? [{ service, saved: saved.stateVersion, expected: version }] : [];\n });\n if (mismatches.length) {\n throw new StateVersionError(mismatches, state.createdBy, resetHint);\n }\n}\n\n/**\n * Parse saved state. Accepts the current format and format 0 (the snapshot\n * written before 0.16, with `service:` prefixed store keys), which is\n * upgraded in memory. Throws `StateFileError` for anything else.\n */\nexport function parseStateFile(input: string | unknown): StateFile {\n let value: unknown;\n if (typeof input === \"string\") {\n try {\n value = JSON.parse(input);\n } catch (error) {\n throw new StateFileError(\"Saved state is not valid JSON\", { cause: error });\n }\n } else {\n value = input;\n }\n if (!isRecord(value)) {\n throw new StateFileError(\"Saved state must be a JSON object\");\n }\n if (value.format === undefined) {\n return upgradeFormat0(value);\n }\n if (typeof value.format !== \"number\" || !Number.isSafeInteger(value.format) || value.format < 1) {\n throw new StateFileError(`Saved state has an unknown format: ${JSON.stringify(value.format)}`);\n }\n if (value.format > STATE_FORMAT) {\n throw new StateFileError(\n `Saved state uses format ${value.format}, written by ${typeof value.createdBy === \"string\" ? value.createdBy : \"a newer version\"}. This version of baseline reads format ${STATE_FORMAT}. Upgrade baseline, or discard the saved state.`,\n { code: \"newer-format\" },\n );\n }\n if (value.redacted === true) {\n throw new StateFileError(\n \"This state was exported with --redact: its secrets are placeholders, so it cannot be loaded. Export it again without --redact.\",\n );\n }\n if (typeof value.createdBy !== \"string\") {\n throw new StateFileError(\"Saved state is missing createdBy\");\n }\n if (!isRecord(value.services)) {\n throw new StateFileError(\"Saved state is missing services\");\n }\n const services: Record<string, ServiceState> = {};\n for (const [name, service] of Object.entries(value.services)) {\n services[name] = parseServiceState(name, service);\n }\n return {\n format: STATE_FORMAT,\n createdBy: value.createdBy,\n services,\n ...parseShared(value),\n };\n}\n\nfunction parseServiceState(name: string, value: unknown): ServiceState {\n const where = `Saved state for ${name}`;\n if (!isRecord(value)) {\n throw new StateFileError(`${where} must be an object`);\n }\n if (!Number.isSafeInteger(value.stateVersion) || (value.stateVersion as number) < 1) {\n throw new StateFileError(`${where} has no valid stateVersion`);\n }\n if (!isStoreSnapshot(value.store)) {\n throw new StateFileError(`${where} has no valid store`);\n }\n if (!(Array.isArray(value.tokens) && value.tokens.every(isTokenEntry))) {\n throw new StateFileError(`${where} has invalid tokens`);\n }\n if (!isWebhookSnapshot(value.webhooks)) {\n throw new StateFileError(`${where} has invalid webhooks`);\n }\n const { provider } = value;\n if (\n provider !== undefined &&\n !(isRecord(provider) && typeof provider.package === \"string\" && typeof provider.version === \"string\")\n ) {\n throw new StateFileError(`${where} has an invalid provider`);\n }\n return {\n ...(provider ? { provider: { package: provider.package as string, version: provider.version as string } } : {}),\n stateVersion: value.stateVersion as number,\n store: value.store,\n tokens: value.tokens,\n webhooks: value.webhooks,\n };\n}\n\n// Format 0 merged every service into one store, keyed \"service:collection\".\nfunction upgradeFormat0(value: Record<string, unknown>): StateFile {\n const { store } = value;\n if (!(isRecord(store) && isRecord(store.collections) && isRecord(store.data) && isRecord(value.tokens))) {\n throw new StateFileError(\"Saved state has no format and is not a format 0 snapshot\");\n }\n if (!Object.values(value.tokens).every((tokens) => Array.isArray(tokens) && tokens.every(isTokenEntry))) {\n throw new StateFileError(\"Saved format 0 snapshot has invalid tokens\");\n }\n const services: Record<string, ServiceState> = {};\n const service = (name: string) => {\n services[name] ??= {\n // Format 0 predates stateVersion; every provider was at 1 then.\n stateVersion: 1,\n store: { collections: {}, data: {} },\n tokens: [],\n webhooks: { subscriptions: [], nextSubscriptionId: 1, nextDeliveryId: 1 },\n };\n return services[name];\n };\n const split = (qualified: string) => {\n const separator = qualified.indexOf(\":\");\n if (separator < 1) {\n throw new StateFileError(`Saved format 0 snapshot has an unqualified key: ${qualified}`);\n }\n return [qualified.slice(0, separator), qualified.slice(separator + 1)] as const;\n };\n for (const [qualified, collection] of Object.entries(store.collections)) {\n if (!isCollectionSnapshot(collection)) {\n throw new StateFileError(`Saved format 0 snapshot has an invalid collection: ${qualified}`);\n }\n const [name, key] = split(qualified);\n service(name).store.collections[key] = collection;\n }\n for (const [qualified, data] of Object.entries(store.data)) {\n const [name, key] = split(qualified);\n service(name).store.data[key] = data;\n }\n for (const [name, tokens] of Object.entries(value.tokens)) {\n service(name).tokens = tokens as TokenEntry[];\n }\n return {\n format: STATE_FORMAT,\n createdBy: \"format 0 (before @deploybaseline/core 0.16)\",\n services,\n ...parseShared(value),\n };\n}\n\nfunction parseShared(\n value: Record<string, unknown>,\n): Pick<StateFile, \"generatedSecrets\" | \"seeded\" | \"custom\" | \"seeds\"> {\n if (value.seeded !== undefined && typeof value.seeded !== \"boolean\") {\n throw new StateFileError(\"Saved state has an invalid seeded flag\");\n }\n if (value.custom !== undefined && !isRecord(value.custom)) {\n throw new StateFileError(\"Saved state has invalid custom emulator state\");\n }\n if (\n value.generatedSecrets !== undefined &&\n !(Array.isArray(value.generatedSecrets) && value.generatedSecrets.every(isGeneratedSecret))\n ) {\n throw new StateFileError(\"Saved state has invalid generated secrets\");\n }\n if (\n value.seeds !== undefined &&\n !(isRecord(value.seeds) && Object.values(value.seeds).every((seed) => typeof seed === \"string\"))\n ) {\n throw new StateFileError(\"Saved state has invalid seed fingerprints\");\n }\n return {\n ...(value.generatedSecrets === undefined ? {} : { generatedSecrets: value.generatedSecrets as GeneratedSecret[] }),\n ...(value.seeded === undefined ? {} : { seeded: value.seeded }),\n ...(value.custom === undefined ? {} : { custom: value.custom as Record<string, EmulatorSnapshot> }),\n ...(value.seeds === undefined ? {} : { seeds: value.seeds as Record<string, string> }),\n };\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\nconst isNonEmptyString = (value: unknown): value is string => typeof value === \"string\" && value.length > 0;\n\nfunction isGeneratedSecret(value: unknown): value is GeneratedSecret {\n return isRecord(value) && [value.service, value.kind, value.id, value.label, value.value].every(isNonEmptyString);\n}\n\nfunction isCollectionSnapshot(value: unknown): value is CollectionSnapshot {\n return (\n isRecord(value) &&\n Array.isArray(value.items) &&\n value.items.every((item) => isRecord(item) && typeof item.id === \"number\") &&\n typeof value.autoId === \"number\" &&\n Array.isArray(value.indexFields) &&\n value.indexFields.every((field) => typeof field === \"string\")\n );\n}\n\nfunction isStoreSnapshot(value: unknown): value is StoreSnapshot {\n return (\n isRecord(value) &&\n isRecord(value.collections) &&\n Object.values(value.collections).every(isCollectionSnapshot) &&\n isRecord(value.data)\n );\n}\n\nfunction isTokenEntry(value: unknown): value is TokenEntry {\n return (\n isRecord(value) &&\n typeof value.token === \"string\" &&\n typeof value.login === \"string\" &&\n typeof value.id === \"number\" &&\n Array.isArray(value.scopes)\n );\n}\n\nfunction isWebhookSnapshot(value: unknown): value is WebhookDispatcherSnapshot {\n return (\n isRecord(value) &&\n Array.isArray(value.subscriptions) &&\n value.subscriptions.every(\n (sub) =>\n isRecord(sub) &&\n typeof sub.id === \"number\" &&\n typeof sub.url === \"string\" &&\n Array.isArray(sub.events) &&\n typeof sub.active === \"boolean\" &&\n typeof sub.owner === \"string\",\n ) &&\n Number.isSafeInteger(value.nextSubscriptionId) &&\n Number.isSafeInteger(value.nextDeliveryId)\n );\n}\n","import { createPublicKey } from \"node:crypto\";\nimport { jwtVerify } from \"jose\";\nimport { debug } from \"../debug.js\";\nimport type { Context, Next } from \"../http.js\";\n\nconst AUTH_SCHEME_PREFIX = /^(Bearer|token)\\s+/i;\n\nexport interface AuthUser {\n login: string;\n id: number;\n scopes: string[];\n installation?: AuthInstallation;\n}\n\nexport interface AuthApp {\n appId: number;\n slug: string;\n name: string;\n}\n\nexport interface AuthInstallation {\n installationId: number;\n appId: number;\n accountId: number;\n accountType: \"User\" | \"Organization\";\n permissions: Record<string, string>;\n repositoryIds: number[];\n repositorySelection: \"all\" | \"selected\";\n}\n\nexport type TokenMap = Map<string, AuthUser>;\n\nexport interface TokenEntry {\n token: string;\n login: string;\n id: number;\n scopes: string[];\n installation?: AuthInstallation;\n}\n\nexport function serializeTokenMap(tokenMap: TokenMap): TokenEntry[] {\n return [...tokenMap.entries()].map(([token, user]) => ({\n token,\n login: user.login,\n id: user.id,\n scopes: user.scopes,\n ...(user.installation ? { installation: user.installation } : {}),\n }));\n}\n\nexport function restoreTokenMap(tokenMap: TokenMap, tokens: TokenEntry[]): void {\n tokenMap.clear();\n for (const t of tokens) {\n tokenMap.set(t.token, {\n login: t.login,\n id: t.id,\n scopes: t.scopes,\n ...(t.installation ? { installation: t.installation } : {}),\n });\n }\n}\n\nexport interface AppEnv {\n Variables: {\n authUser?: AuthUser;\n authApp?: AuthApp;\n authToken?: string;\n authScopes?: string[];\n docsUrl?: string;\n };\n}\n\nexport type AppKeyResolver = (appId: number) => { privateKey: string; slug: string; name: string } | null;\n\nexport interface AuthFallback {\n login: string;\n id: number;\n scopes: string[];\n}\n\nexport function authMiddleware(tokens: TokenMap, appKeyResolver?: AppKeyResolver, fallbackUser?: AuthFallback) {\n return async (c: Context, next: Next) => {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader) {\n const token = authHeader.replace(AUTH_SCHEME_PREFIX, \"\").trim();\n\n if (token.startsWith(\"eyJ\") && appKeyResolver) {\n try {\n const [, payloadB64] = token.split(\".\");\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64url\").toString());\n const appId = typeof payload.iss === \"string\" ? Number.parseInt(payload.iss, 10) : payload.iss;\n\n if (typeof appId === \"number\" && !Number.isNaN(appId)) {\n const appInfo = appKeyResolver(appId);\n if (appInfo) {\n const publicKey = createPublicKey(appInfo.privateKey);\n await jwtVerify(token, publicKey, { algorithms: [\"RS256\"] });\n c.set(\"authApp\", {\n appId,\n slug: appInfo.slug,\n name: appInfo.name,\n } satisfies AuthApp);\n }\n }\n } catch {\n // JWT verification failed\n }\n } else {\n let user = tokens.get(token);\n if (!user && fallbackUser && token.length > 0) {\n debug(\"auth\", \"fallback user for unknown token\", { login: fallbackUser.login, id: fallbackUser.id });\n user = { login: fallbackUser.login, id: fallbackUser.id, scopes: fallbackUser.scopes };\n }\n if (user) {\n c.set(\"authUser\", user);\n c.set(\"authToken\", token);\n c.set(\"authScopes\", user.scopes);\n }\n }\n }\n await next();\n };\n}\n\nexport function requireAuth() {\n return async (c: Context, next: Next) => {\n if (!c.get(\"authUser\")) {\n const docsUrl = (c.get(\"docsUrl\") as string | undefined) ?? \"https://docs.deploybaseline.com\";\n return c.json(\n {\n message: \"Requires authentication\",\n documentation_url: docsUrl,\n },\n 401,\n );\n }\n await next();\n };\n}\n\nexport function requireAppAuth() {\n return async (c: Context, next: Next) => {\n if (!c.get(\"authApp\")) {\n const docsUrl = (c.get(\"docsUrl\") as string | undefined) ?? \"https://docs.deploybaseline.com\";\n return c.json(\n {\n message: \"A JSON web token could not be decoded\",\n documentation_url: docsUrl,\n },\n 401,\n );\n }\n await next();\n };\n}\n","const isDebug =\n typeof process !== \"undefined\" &&\n (process.env.DEBUG === \"1\" || process.env.DEBUG === \"true\" || process.env.BASELINE_DEBUG === \"1\");\n\nexport function debug(label: string, ...args: unknown[]): void {\n if (isDebug) {\n console.log(`[${label}]`, ...args);\n }\n}\n","export function escapeHtml(s: string): string {\n return s.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\").replace(/\"/g, \""\");\n}\n\nexport function escapeAttr(s: string): string {\n return escapeHtml(s).replace(/'/g, \"'\");\n}\n\nconst CSS = `\n.inspector-json{white-space:pre-wrap;overflow-wrap:anywhere;font-size:.8125rem;line-height:1.6;max-height:70vh;overflow:auto}\n.inspector-detail{padding:14px 0;border-bottom:1px solid #0a3300}\n.inspector-detail summary{cursor:pointer;overflow-wrap:anywhere}\n.email-preview{width:100%;min-height:300px;border:1px solid #0a3300;border-radius:8px;background:#fff;margin-top:10px}\n.email-text{white-space:pre-wrap;overflow-wrap:anywhere}\n.inspector-action{display:inline-block;margin-top:12px;padding:8px 12px;border:1px solid #0a3300;border-radius:6px;background:#001a00;color:#33ff00;font:inherit;font-size:.8125rem;cursor:pointer}\n.inspector-action:hover{background:#0a3300}\n.inspector-scroll{overflow-x:auto}\n.inspector-inline-form{display:inline-flex;gap:8px;align-items:center;margin:0}\n.inspector-inline-form .inspector-action,.inspector-inline-form .btn-revoke{margin-top:0}\n.inspector-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:12px}\n.inspector-actions .inspector-action,.inspector-actions .inspector-input{margin-top:0}\na.inspector-action{text-decoration:none}\n.inspector-actions .btn-revoke{padding:8px 12px;font-size:.8125rem;font-weight:400}\ntd .inspector-actions{margin-top:0}\n.inspector-input{padding:8px 10px;border:1px solid #0a3300;border-radius:6px;background:#000;color:#33ff00;font:inherit;font-size:.8125rem;margin-top:12px}\n.inspector-input:focus{outline:none;border-color:#33ff00}\n.inspector-textarea{display:block;width:100%;min-height:96px;resize:vertical;box-sizing:border-box;white-space:pre-wrap}\n.inspector-notice{padding:10px 12px;margin-bottom:16px;border:1px solid #0a3300;border-radius:6px;background:#001a00;font-size:.8125rem;overflow-wrap:anywhere}\n.inspector-notice-error{border-color:#ff4444;color:#ff4444;background:#1a0a0a}\n.inspector-section code{font-size:.8125rem;overflow-wrap:anywhere}\n@font-face{\n font-family:'Geist';font-style:normal;font-weight:100 900;font-display:swap;\n src:url('/_baseline/fonts/geist-sans.woff2') format('woff2');\n}\n@font-face{\n font-family:'Geist Pixel';font-style:normal;font-weight:400;font-display:swap;\n src:url('/_baseline/fonts/GeistPixel-Square.woff2') format('woff2');\n}\n*{box-sizing:border-box;margin:0;padding:0}\nbody{\n font-family:'Geist',-apple-system,BlinkMacSystemFont,sans-serif;\n background:#000;color:#33ff00;min-height:100vh;\n -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;\n}\n.brand-bar{\n border-bottom:1px solid #0a3300;padding:10px 20px;\n display:flex;align-items:center;gap:10px;font-size:.8125rem;color:#1a8c00;\n}\n.brand-bar.sticky{position:sticky;top:0;z-index:1000;background:#000;height:42px;}\n.brand-bar-title{font-weight:600;color:#33ff00;font-family:'Geist Pixel',monospace;}\n.brand-bar-links{margin-left:auto;display:flex;gap:16px;}\n.brand-bar-links a{\n color:#1a8c00;font-size:.75rem;text-decoration:none;transition:color .15s;\n}\n.brand-bar-links a:hover{color:#33ff00;}\n.brand-bar-links a .full{display:inline;}\n.brand-bar-links a .short{display:none;}\n@media(max-width:600px){\n .brand-bar-links a .full{display:none;}\n .brand-bar-links a .short{display:inline;}\n}\n\n.content{\n display:flex;align-items:center;justify-content:center;\n min-height:calc(100vh - 42px);padding:24px 16px;\n}\n.content-inner{width:100%;max-width:420px;}\n.card-title{\n font-family:'Geist Pixel',monospace;\n font-size:1.125rem;font-weight:600;margin-bottom:4px;color:#33ff00;\n}\n.card-subtitle{color:#1a8c00;font-size:.8125rem;margin-bottom:18px;line-height:1.45;}\n.powered-by{\n position:fixed;bottom:0;left:0;right:0;\n text-align:center;padding:12px;font-size:.6875rem;color:#0a3300;\n font-family:'Geist Pixel',monospace;\n}\n.powered-by a{color:#1a8c00;text-decoration:none;transition:color .15s;}\n.powered-by a:hover{color:#33ff00;}\n\n.error-title{\n font-family:'Geist Pixel',monospace;\n color:#ff4444;font-size:1.125rem;font-weight:600;margin-bottom:8px;\n}\n.error-msg{color:#1a8c00;font-size:.875rem;line-height:1.5;}\n.error-card{text-align:center;}\n\n.user-form{margin-bottom:8px;}\n.user-form:last-of-type{margin-bottom:0;}\n.user-btn{\n width:100%;display:flex;align-items:center;gap:12px;\n padding:10px 12px;border:1px solid #0a3300;border-radius:8px;\n background:#000;color:inherit;cursor:pointer;text-align:left;\n font:inherit;transition:border-color .15s;\n}\n.user-btn:hover{border-color:#33ff00;}\n.avatar{\n width:36px;height:36px;border-radius:50%;\n background:#0a3300;color:#33ff00;font-weight:600;font-size:.875rem;\n display:flex;align-items:center;justify-content:center;flex-shrink:0;\n font-family:'Geist Pixel',monospace;\n}\n.user-text{min-width:0;}\n.user-login{font-weight:600;font-size:.875rem;display:block;color:#33ff00;}\n.user-meta{color:#1a8c00;font-size:.75rem;margin-top:1px;}\n.user-email{font-size:.6875rem;color:#116600;word-break:break-all;margin-top:1px;}\n\n.settings-layout{\n max-width:920px;margin:0 auto;padding:28px 20px;\n display:flex;gap:28px;\n}\n.settings-sidebar{width:200px;flex-shrink:0;}\n.settings-sidebar a{\n display:block;padding:6px 10px;border-radius:6px;color:#1a8c00;\n text-decoration:none;font-size:.8125rem;transition:color .15s;\n}\n.settings-sidebar a:hover{color:#33ff00;}\n.settings-sidebar a.active{color:#33ff00;font-weight:600;}\n.settings-main{flex:1;min-width:0;}\n\n.s-card{\n padding:18px 0;margin-bottom:14px;border-bottom:1px solid #0a3300;\n}\n.s-card:last-child{border-bottom:none;}\n.s-card-header{display:flex;align-items:center;gap:14px;margin-bottom:14px;}\n.s-icon{\n width:42px;height:42px;border-radius:8px;\n background:#0a3300;display:flex;align-items:center;justify-content:center;\n font-size:1.125rem;font-weight:700;color:#116600;flex-shrink:0;\n font-family:'Geist Pixel',monospace;\n}\n.s-title{\n font-family:'Geist Pixel',monospace;\n font-size:1.25rem;font-weight:600;color:#33ff00;\n}\n.s-subtitle{font-size:.75rem;color:#1a8c00;margin-top:2px;}\n.section-heading{\n font-size:.9375rem;font-weight:600;margin-bottom:10px;color:#33ff00;\n display:flex;align-items:center;justify-content:space-between;\n}\n.perm-list{list-style:none;}\n.perm-list li{padding:5px 0;font-size:.8125rem;display:flex;align-items:center;gap:6px;color:#1a8c00;}\n.check{color:#33ff00;}\n.org-row{\n display:flex;align-items:center;gap:8px;padding:7px 0;\n border-bottom:1px solid #0a3300;font-size:.8125rem;\n}\n.org-row:last-child{border-bottom:none;}\n.org-icon{\n width:22px;height:22px;border-radius:4px;background:#0a3300;\n display:flex;align-items:center;justify-content:center;\n font-size:.625rem;font-weight:700;color:#116600;flex-shrink:0;\n font-family:'Geist Pixel',monospace;\n}\n.org-name{font-weight:600;color:#33ff00;}\n.badge{font-size:.6875rem;padding:1px 7px;border-radius:999px;font-weight:500;}\n.badge-granted{background:#0a3300;color:#33ff00;}\n.badge-denied{background:#1a0a0a;color:#ff4444;}\n.badge-requested{background:#0a3300;color:#1a8c00;}\n.btn-revoke{\n display:inline-block;padding:5px 14px;border-radius:6px;\n border:1px solid #0a3300;background:transparent;color:#ff4444;\n font-size:.75rem;font-weight:600;cursor:pointer;transition:border-color .15s;\n}\n.btn-revoke:hover{border-color:#ff4444;}\n.info-text{color:#1a8c00;font-size:.75rem;line-height:1.5;margin-top:10px;}\n.app-link{\n display:flex;align-items:center;gap:12px;padding:12px;\n border:1px solid #0a3300;border-radius:8px;background:#000;\n text-decoration:none;color:inherit;margin-bottom:8px;transition:border-color .15s;\n}\n.app-link:hover{border-color:#33ff00;}\n.app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}\n.app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}\n.empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}\n\n.inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}\n.inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}\n.inspector-tabs a{\n padding:7px 16px;border-radius:6px;text-decoration:none;\n font-size:.8125rem;color:#1a8c00;border:1px solid transparent;\n transition:color .15s,border-color .15s;\n}\n.inspector-tabs a:hover{color:#33ff00;}\n.inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}\n.inspector-section{margin-bottom:24px;}\n.inspector-section h2{\n font-family:'Geist Pixel',monospace;\n font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;\n}\n.inspector-section h3{\n font-family:'Geist Pixel',monospace;\n font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;\n}\n.inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}\n.inspector-table th,.inspector-table td{\n text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;\n font-size:.8125rem;\n}\n.inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}\n.inspector-table td{color:#33ff00;}\n.inspector-table tbody tr{transition:background .1s;}\n.inspector-table tbody tr:hover{background:#0a3300;}\n.inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}\n\n.checkout-layout{\n display:flex;min-height:calc(100vh - 42px);\n}\n.checkout-summary{\n flex:1;background:#020;padding:48px 40px 48px 10%;\n display:flex;flex-direction:column;justify-content:center;\n border-right:1px solid #0a3300;\n}\n.checkout-form-side{\n flex:1;background:#000;padding:48px 10% 48px 40px;\n display:flex;flex-direction:column;justify-content:center;\n}\n.checkout-merchant{\n display:flex;align-items:center;gap:10px;margin-bottom:6px;\n}\n.checkout-merchant-name{\n font-family:'Geist Pixel',monospace;\n font-size:.9375rem;font-weight:600;color:#33ff00;\n}\n.checkout-test-badge{\n font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;\n background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;\n}\n.checkout-total{\n font-family:'Geist Pixel',monospace;\n font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;\n}\n.checkout-line-item{\n display:flex;align-items:center;gap:14px;padding:14px 0;\n border-bottom:1px solid #0a3300;\n}\n.checkout-line-item:first-child{border-top:1px solid #0a3300;}\n.checkout-item-icon{\n width:42px;height:42px;border-radius:6px;background:#0a3300;\n display:flex;align-items:center;justify-content:center;flex-shrink:0;\n font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;\n}\n.checkout-item-details{flex:1;min-width:0;}\n.checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}\n.checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}\n.checkout-item-price{\n font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;\n}\n.checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}\n.checkout-totals{margin-top:20px;}\n.checkout-totals-row{\n display:flex;justify-content:space-between;padding:6px 0;\n font-size:.8125rem;color:#1a8c00;\n}\n.checkout-totals-row.total{\n border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;\n font-size:.9375rem;font-weight:600;color:#33ff00;\n}\n.checkout-form-section{margin-bottom:24px;}\n.checkout-form-label{\n font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;\n}\n.checkout-input{\n width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;\n background:#020;color:#33ff00;font:inherit;font-size:.875rem;\n transition:border-color .15s;outline:none;\n}\n.checkout-input:focus{border-color:#33ff00;}\n.checkout-input::placeholder{color:#116600;}\n.checkout-card-box{\n border:1px solid #0a3300;border-radius:6px;padding:14px;\n background:#020;\n}\n.checkout-card-row{\n display:flex;gap:12px;margin-top:10px;\n}\n.checkout-card-row .checkout-input{flex:1;}\n.checkout-error{font-size:.75rem;color:#ff5555;margin-top:6px;}\n.checkout-sim-note{\n font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;\n font-style:italic;\n}\n.checkout-pay-btn{\n width:100%;padding:14px;border:none;border-radius:8px;\n background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;\n cursor:pointer;transition:background .15s;\n font-family:'Geist Pixel',monospace;\n}\n.checkout-pay-btn:hover{background:#44ff22;}\n.checkout-cancel{\n text-align:center;margin-top:14px;\n}\n.checkout-cancel a{\n color:#1a8c00;text-decoration:none;font-size:.8125rem;\n transition:color .15s;\n}\n.checkout-cancel a:hover{color:#33ff00;}\n.consent-scopes{list-style:none;margin:0 0 18px;padding:0;border:1px solid #0a3300;}\n.consent-scopes li{padding:10px 14px;border-bottom:1px solid #0a3300;}\n.consent-scopes li:last-child{border-bottom:none;}\n.consent-scope-name{display:block;font-size:.8125rem;color:#33ff00;}\n.consent-scope-key{display:block;font-size:.6875rem;color:#116600;margin-top:2px;word-break:break-all;}\n.card-cancel{text-align:center;margin-top:14px;}\n.card-cancel a{color:#1a8c00;text-decoration:none;font-size:.8125rem;transition:color .15s;}\n.card-cancel a:hover{color:#33ff00;}\n.card-form{margin:0 0 8px;}\n.card-field{margin-bottom:14px;}\n.card-label{display:block;font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:6px;}\n.card-hint{display:block;font-size:.6875rem;color:#116600;margin-top:4px;}\n.card-input{\n width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;\n background:#020;color:#33ff00;font:inherit;font-size:.875rem;outline:none;transition:border-color .15s;\n}\n.card-input:focus{border-color:#33ff00;}\n.card-choices{list-style:none;margin:0;padding:0;border:1px solid #0a3300;border-radius:8px;}\n.card-choices li{border-bottom:1px solid #0a3300;}\n.card-choices li:last-child{border-bottom:none;}\n.card-choice{display:flex;align-items:center;gap:10px;padding:10px 12px;cursor:pointer;font-size:.8125rem;color:#33ff00;}\n.card-choice input{accent-color:#33ff00;flex-shrink:0;}\n.card-choice-detail{display:block;font-size:.6875rem;color:#1a8c00;margin-top:1px;}\n.card-submit{\n width:100%;padding:12px;border:none;border-radius:8px;background:#33ff00;color:#000;\n font:inherit;font-size:.875rem;font-weight:700;cursor:pointer;transition:background .15s;\n font-family:'Geist Pixel',monospace;\n}\n.card-submit:hover{background:#44ff22;}\n.card-notice{padding:10px 12px;margin-bottom:14px;border:1px solid #0a3300;border-radius:6px;background:#001a00;font-size:.8125rem;color:#1a8c00;overflow-wrap:anywhere;}\n.card-notice-error{border-color:#ff4444;color:#ff4444;background:#1a0a0a;}\n.card-code{display:block;padding:10px 12px;margin-bottom:14px;border:1px solid #0a3300;border-radius:6px;font-size:.75rem;color:#33ff00;overflow-wrap:anywhere;font-family:monospace;}\n@media(max-width:768px){\n .checkout-layout{flex-direction:column;}\n .checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}\n .checkout-form-side{padding:32px 20px;}\n}\n`;\n\nconst POWERED_BY = `<div class=\"powered-by\">Powered by <a href=\"https://docs.deploybaseline.com\" target=\"_blank\" rel=\"noopener\">baseline</a></div>`;\n\nfunction brandBar(service?: string): string {\n const title = service ? `${escapeHtml(service)} Emulator` : \"Emulator\";\n return `<div class=\"brand-bar\">\n <span class=\"brand-bar-title\">${title}</span>\n <nav class=\"brand-bar-links\">\n <a href=\"https://github.com/deploybaseline/baseline-cli/issues\" target=\"_blank\" rel=\"noopener\"><span class=\"full\">Report Issue</span><span class=\"short\">Report</span></a>\n <a href=\"https://github.com/deploybaseline/baseline-cli\" target=\"_blank\" rel=\"noopener\"><span class=\"full\">Source Code</span><span class=\"short\">Source</span></a>\n <a href=\"https://docs.deploybaseline.com\" target=\"_blank\" rel=\"noopener\"><span class=\"full\">Learn More</span><span class=\"short\">Learn</span></a>\n </nav>\n</div>`;\n}\n\nfunction head(title: string): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\"/>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>\n<link rel=\"icon\" href=\"/_baseline/favicon.ico\"/>\n<title>${escapeHtml(title)} | baseline</title>\n<style>${CSS}</style>\n</head>`;\n}\n\nexport function renderCardPage(title: string, subtitle: string, body: string, service?: string): string {\n return `${head(title)}\n<body>\n${brandBar(service)}\n<div class=\"content\">\n <div class=\"content-inner\">\n <div class=\"card-title\">${escapeHtml(title)}</div>\n <div class=\"card-subtitle\">${subtitle}</div>\n ${body}\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport function renderErrorPage(title: string, message: string, service?: string): string {\n return `${head(title)}\n<body>\n${brandBar(service)}\n<div class=\"content\">\n <div class=\"content-inner error-card\">\n <div class=\"error-title\">${escapeHtml(title)}</div>\n <div class=\"error-msg\">${escapeHtml(message)}</div>\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport function renderSettingsPage(title: string, sidebarHtml: string, bodyHtml: string, service?: string): string {\n return `${head(title)}\n<body>\n${brandBar(service)}\n<div class=\"settings-layout\">\n <nav class=\"settings-sidebar\">${sidebarHtml}</nav>\n <div class=\"settings-main\">${bodyHtml}</div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport interface ApiReferenceSource {\n title: string;\n slug: string;\n /** URL of the OpenAPI document. */\n url: string;\n}\n\nexport interface ApiReferencePageOptions {\n title: string;\n sources: ApiReferenceSource[];\n /** Where the page loads the Scalar standalone bundle from. */\n scriptUrl: string;\n}\n\n// Scalar's theme variables, set to the house palette. The brand bar stays on\n// top (.brand-bar.sticky), so Scalar's sticky header and sidebar start below it.\nconst SCALAR_CSS = `\n.dark-mode,.light-mode{\n --scalar-custom-header-height:42px;\n --scalar-font:'Geist',-apple-system,BlinkMacSystemFont,sans-serif;\n --scalar-background-1:#000;--scalar-background-2:#001a00;--scalar-background-3:#0a3300;\n --scalar-background-accent:#0a3300;\n --scalar-color-1:#33ff00;--scalar-color-2:#1a8c00;--scalar-color-3:#116600;\n --scalar-color-accent:#33ff00;--scalar-border-color:#0a3300;\n --scalar-sidebar-background-1:#000;--scalar-sidebar-color-1:#33ff00;--scalar-sidebar-color-2:#1a8c00;\n --scalar-sidebar-color-active:#33ff00;--scalar-sidebar-item-active-background:#0a3300;\n --scalar-sidebar-border-color:#0a3300;--scalar-sidebar-search-background:#001a00;\n --scalar-sidebar-search-border-color:#0a3300;\n}\n`;\n\n/** An OpenAPI reference rendered by Scalar, one source per document, for the CLI console's /docs. */\nexport function renderApiReferencePage(opts: ApiReferencePageOptions): string {\n const config = {\n sources: opts.sources,\n theme: \"none\",\n forceDarkModeState: \"dark\",\n hideDarkModeToggle: true,\n withDefaultFonts: false,\n telemetry: false,\n agent: { disabled: true },\n mcp: { disabled: true },\n showDeveloperTools: \"never\",\n customCss: SCALAR_CSS,\n };\n // JSON inside a script element: escape \"<\" so a title cannot close the element.\n // The mount is not #api-reference: Scalar auto-mounts an unconfigured copy on that id.\n const json = JSON.stringify(config).replace(/</g, \"\\\\u003c\");\n return `${head(opts.title)}\n<body>\n${brandBar().replace('class=\"brand-bar\"', 'class=\"brand-bar sticky\"')}\n<div id=\"reference\"></div>\n<script src=\"${escapeAttr(opts.scriptUrl)}\"></script>\n<script>Scalar.createApiReference(\"#reference\", ${json});</script>\n</body></html>`;\n}\n\nexport interface InspectorTab {\n id: string;\n label: string;\n href: string;\n}\n\nexport function renderJsonDetails(label: string, value: unknown, open = false): string {\n const text = JSON.stringify(value, null, 2) ?? \"\";\n const bounded = text.length > 65_536 ? `${text.slice(0, 65_536)}\\n[remaining data omitted from preview]` : text;\n return `<details class=\"inspector-detail\"${open ? \" open\" : \"\"}><summary>${escapeHtml(label)}</summary><pre class=\"inspector-json\">${escapeHtml(bounded)}</pre></details>`;\n}\n\nexport function renderStateView(value: unknown): string {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return renderJsonDetails(\"Current state\", value, true);\n }\n return Object.entries(value)\n .map(([key, item]) => {\n if (\n Array.isArray(item) &&\n item.length &&\n item.every((row) => row && typeof row === \"object\" && !Array.isArray(row))\n ) {\n const columns = [...new Set(item.slice(0, 100).flatMap(Object.keys))].slice(0, 12);\n const rows = item\n .slice(0, 100)\n .map(\n (row) =>\n `<tr>${columns.map((column) => `<td>${escapeHtml((typeof row[column] === \"string\" ? row[column] : JSON.stringify(row[column]))?.slice(0, 500) ?? \"\")}</td>`).join(\"\")}</tr>`,\n )\n .join(\"\");\n return `<div class=\"s-card\"><h2 class=\"section-heading\">${escapeHtml(key)} <span class=\"badge\">${item.length}</span></h2><div class=\"inspector-scroll\"><table class=\"inspector-table\"><thead><tr>${columns.map((column) => `<th>${escapeHtml(column)}</th>`).join(\"\")}</tr></thead><tbody>${rows}</tbody></table></div>${item.length > 100 ? '<p class=\"s-subtitle\">Showing the first 100 records.</p>' : \"\"}</div>`;\n }\n return renderJsonDetails(key, item, true);\n })\n .join(\"\");\n}\n\nexport function renderInspectorPage(\n title: string,\n tabs: InspectorTab[],\n activeTab: string,\n body: string,\n service?: string,\n): string {\n const tabLinks = tabs\n .map(\n (t) => `<a href=\"${escapeAttr(t.href)}\" class=\"${t.id === activeTab ? \"active\" : \"\"}\">${escapeHtml(t.label)}</a>`,\n )\n .join(\"\");\n\n return `${head(title)}\n<body>\n${brandBar(service)}\n<div class=\"inspector-layout\">\n <nav class=\"inspector-tabs\">${tabLinks}</nav>\n ${body}\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport function renderFormPostPage(action: string, fields: Record<string, string>, service?: string): string {\n const hiddens = Object.entries(fields)\n .filter(([, v]) => v !== null && v !== undefined)\n .map(([k, v]) => `<input type=\"hidden\" name=\"${escapeAttr(k)}\" value=\"${escapeAttr(v)}\"/>`)\n .join(\"\\n\");\n\n return `${head(\"Redirecting\")}\n<body onload=\"document.forms[0].submit()\">\n${brandBar(service)}\n<div class=\"content\">\n <div class=\"content-inner\" style=\"text-align:center\">\n <div class=\"card-subtitle\">Redirecting…</div>\n <form method=\"POST\" action=\"${escapeAttr(action)}\">\n${hiddens}\n <noscript><button type=\"submit\" class=\"user-btn\" style=\"margin-top:12px;justify-content:center\">\n <span class=\"user-login\">Continue</span>\n </button></noscript>\n </form>\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport interface CheckoutLineItem {\n name: string;\n quantity: number;\n unitPrice: number;\n totalPrice: number;\n currency: string;\n}\n\nexport interface CheckoutPageOptions {\n merchantName?: string;\n lineItems: CheckoutLineItem[];\n subtotal: number;\n total: number;\n currency: string;\n sessionId: string;\n cancelUrl?: string | null;\n /** A discount taken off the subtotal, shown as its own row. */\n discount?: { label: string; amount: number };\n /** Tax added to (or, for inclusive rates, included in) the total. */\n tax?: { label: string; amount: number };\n /** Show a promotion code field; `error` explains why the last code was refused. */\n promotionCode?: { error: string | null };\n}\n\nexport function renderCheckoutPage(opts: CheckoutPageOptions, service?: string): string {\n const fmt = (cents: number, cur: string) => `$${(cents / 100).toFixed(2)} ${cur.toUpperCase()}`;\n const fmtShort = (cents: number) => `$${(cents / 100).toFixed(2)}`;\n\n const itemsHtml =\n opts.lineItems.length > 0\n ? opts.lineItems\n .map((li) => {\n const initial = li.name.charAt(0).toUpperCase();\n const unitNote =\n li.quantity > 1 ? `<div class=\"checkout-item-unit\">${fmtShort(li.unitPrice)} each</div>` : \"\";\n return `<div class=\"checkout-line-item\">\n <div class=\"checkout-item-icon\">${escapeHtml(initial)}</div>\n <div class=\"checkout-item-details\">\n <div class=\"checkout-item-name\">${escapeHtml(li.name)}</div>\n <div class=\"checkout-item-qty\">Qty ${li.quantity}</div>\n </div>\n <div>\n <div class=\"checkout-item-price\">${fmtShort(li.totalPrice)}</div>\n ${unitNote}\n </div>\n</div>`;\n })\n .join(\"\")\n : '<p class=\"empty\">No line items</p>';\n\n const totalsHtml = `<div class=\"checkout-totals\">\n <div class=\"checkout-totals-row\">\n <span>Subtotal</span><span>${fmtShort(opts.subtotal)}</span>\n </div>\n ${\n opts.discount\n ? `<div class=\"checkout-totals-row\"><span>${escapeHtml(opts.discount.label)}</span><span>-${fmtShort(opts.discount.amount)}</span></div>`\n : \"\"\n }\n ${\n opts.tax\n ? `<div class=\"checkout-totals-row\"><span>${escapeHtml(opts.tax.label)}</span><span>${fmtShort(opts.tax.amount)}</span></div>`\n : \"\"\n }\n <div class=\"checkout-totals-row total\">\n <span>Total due</span><span>${fmt(opts.total, opts.currency)}</span>\n </div>\n</div>`;\n\n const cancelHtml = opts.cancelUrl\n ? `<div class=\"checkout-cancel\"><a href=\"${escapeAttr(opts.cancelUrl)}\">Cancel</a></div>`\n : \"\";\n\n const merchant = opts.merchantName ? escapeHtml(opts.merchantName) : \"Checkout\";\n\n return `${head(\"Checkout\")}\n<body>\n${brandBar(service)}\n<div class=\"checkout-layout\">\n <div class=\"checkout-summary\">\n <div class=\"checkout-merchant\">\n <span class=\"checkout-merchant-name\">${merchant}</span>\n <span class=\"checkout-test-badge\">Test Mode</span>\n </div>\n <div class=\"checkout-total\">${fmtShort(opts.total)}</div>\n ${itemsHtml}\n ${totalsHtml}\n </div>\n <div class=\"checkout-form-side\">\n <form method=\"post\" action=\"/checkout/${escapeAttr(opts.sessionId)}/complete\">\n <div class=\"checkout-form-section\">\n <label class=\"checkout-form-label\">Email</label>\n <input type=\"email\" name=\"email\" class=\"checkout-input\" placeholder=\"you@example.com\"/>\n </div>\n ${\n opts.promotionCode\n ? `<div class=\"checkout-form-section\">\n <label class=\"checkout-form-label\">Promotion code</label>\n <input type=\"text\" name=\"promotion_code\" class=\"checkout-input\" placeholder=\"Add promotion code\"/>\n ${opts.promotionCode.error ? `<div class=\"checkout-error\">${escapeHtml(opts.promotionCode.error)}</div>` : \"\"}\n </div>`\n : \"\"\n }\n <div class=\"checkout-form-section\">\n <label class=\"checkout-form-label\">Card information</label>\n <div class=\"checkout-card-box\">\n <input type=\"text\" class=\"checkout-input\" placeholder=\"1234 1234 1234 1234\" disabled/>\n <div class=\"checkout-card-row\">\n <input type=\"text\" class=\"checkout-input\" placeholder=\"MM / YY\" disabled/>\n <input type=\"text\" class=\"checkout-input\" placeholder=\"CVC\" disabled/>\n </div>\n </div>\n <div class=\"checkout-sim-note\">Card fields are simulated. Payment will be auto-approved.</div>\n </div>\n <button type=\"submit\" class=\"checkout-pay-btn\">Pay ${fmtShort(opts.total)}</button>\n </form>\n ${cancelHtml}\n </div>\n</div>\n${POWERED_BY}\n</body></html>`;\n}\n\nexport interface UserButtonOptions {\n letter: string;\n login: string;\n name?: string;\n email?: string;\n formAction: string;\n hiddenFields: Record<string, string>;\n}\n\nexport function renderUserButton(opts: UserButtonOptions): string {\n const hiddens = Object.entries(opts.hiddenFields)\n .map(([k, v]) => `<input type=\"hidden\" name=\"${escapeAttr(k)}\" value=\"${escapeAttr(v)}\"/>`)\n .join(\"\");\n\n const nameLine = opts.name ? `<div class=\"user-meta\">${escapeHtml(opts.name)}</div>` : \"\";\n const emailLine = opts.email ? `<div class=\"user-email\">${escapeHtml(opts.email)}</div>` : \"\";\n\n return `<form class=\"user-form\" method=\"post\" action=\"${escapeAttr(opts.formAction)}\">\n${hiddens}\n<button type=\"submit\" class=\"user-btn\">\n <span class=\"avatar\">${escapeHtml(opts.letter)}</span>\n <span class=\"user-text\">\n <span class=\"user-login\">${escapeHtml(opts.login)}</span>\n ${nameLine}${emailLine}\n </span>\n</button>\n</form>`;\n}\n\n/** The permissions an OAuth consent screen asks for, one per row with its scope key. */\nexport function renderConsentScopes(scopes: ReadonlyArray<{ scope: string; description: string }>): string {\n if (scopes.length === 0) {\n return \"\";\n }\n const items = scopes\n .map(\n (item) =>\n `<li><span class=\"consent-scope-name\">${escapeHtml(item.description)}</span><span class=\"consent-scope-key\">${escapeHtml(item.scope)}</span></li>`,\n )\n .join(\"\");\n return `<ul class=\"consent-scopes\">${items}</ul>`;\n}\n\n/**\n * A sent email's body for an inbox page: HTML in a sandboxed iframe (scripts\n * off, links open in a new tab), else the plain text, else an empty note.\n */\nexport function renderEmailPreview(html: string | null, text: string | null): string {\n if (html) {\n return `<iframe class=\"email-preview\" sandbox=\"allow-popups allow-popups-to-escape-sandbox\" srcdoc=\"${escapeAttr(`<base target=\"_blank\">${html}`)}\"></iframe>`;\n }\n if (text) {\n return `<div class=\"s-card\"><pre class=\"info-text email-text\">${escapeHtml(text)}</pre></div>`;\n }\n return '<div class=\"empty\">No content</div>';\n}\n\nexport type CardFormField =\n | {\n type: \"text\" | \"password\";\n name: string;\n label: string;\n value?: string;\n placeholder?: string;\n hint?: string;\n required?: boolean;\n }\n | {\n type: \"checkbox\" | \"radio\";\n name: string;\n label: string;\n options: ReadonlyArray<{ value: string; label: string; detail?: string; checked?: boolean }>;\n };\n\nexport interface CardFormOptions {\n action: string;\n submitLabel: string;\n fields: readonly CardFormField[];\n hiddenFields?: Record<string, string>;\n /** A message above the fields; `error` shows it in red. */\n notice?: { text: string; error?: boolean };\n}\n\n/**\n * A POST form for a card page: text and password inputs, checkbox or radio\n * lists, and one submit button. Used by hosted flows that collect input,\n * such as Plaid Link's credentials, MFA, and account selection steps.\n */\nexport function renderCardForm(opts: CardFormOptions): string {\n const hiddens = Object.entries(opts.hiddenFields ?? {})\n .map(([k, v]) => `<input type=\"hidden\" name=\"${escapeAttr(k)}\" value=\"${escapeAttr(v)}\"/>`)\n .join(\"\");\n const notice = opts.notice\n ? `<div class=\"card-notice${opts.notice.error ? \" card-notice-error\" : \"\"}\">${escapeHtml(opts.notice.text)}</div>`\n : \"\";\n const fields = opts.fields\n .map((field) => {\n if (!(\"options\" in field)) {\n const id = `field-${field.name}`;\n return `<div class=\"card-field\"><label class=\"card-label\" for=\"${escapeAttr(id)}\">${escapeHtml(field.label)}</label><input class=\"card-input\" id=\"${escapeAttr(id)}\" type=\"${field.type}\" name=\"${escapeAttr(field.name)}\" value=\"${escapeAttr(field.value ?? \"\")}\"${field.placeholder ? ` placeholder=\"${escapeAttr(field.placeholder)}\"` : \"\"}${field.required ? \" required\" : \"\"} autocomplete=\"off\"/>${field.hint ? `<span class=\"card-hint\">${escapeHtml(field.hint)}</span>` : \"\"}</div>`;\n }\n const options = field.options\n .map(\n (option) =>\n `<li><label class=\"card-choice\"><input type=\"${field.type}\" name=\"${escapeAttr(field.name)}\" value=\"${escapeAttr(option.value)}\"${option.checked ? \" checked\" : \"\"}/><span>${escapeHtml(option.label)}${option.detail ? `<span class=\"card-choice-detail\">${escapeHtml(option.detail)}</span>` : \"\"}</span></label></li>`,\n )\n .join(\"\");\n return `<div class=\"card-field\"><span class=\"card-label\">${escapeHtml(field.label)}</span><ul class=\"card-choices\">${options}</ul></div>`;\n })\n .join(\"\");\n return `<form class=\"card-form\" method=\"post\" action=\"${escapeAttr(opts.action)}\">${hiddens}${notice}${fields}<button type=\"submit\" class=\"card-submit\">${escapeHtml(opts.submitLabel)}</button></form>`;\n}\n\n/** A labelled value to copy from a card page, such as a token. */\nexport function renderCardCode(label: string, value: string): string {\n return `<span class=\"card-label\">${escapeHtml(label)}</span><code class=\"card-code\">${escapeHtml(value)}</code>`;\n}\n\n/** A quiet link under a card's actions, for declining a consent screen. */\nexport function renderCardCancel(href: string, label = \"Cancel\"): string {\n return `<div class=\"card-cancel\"><a href=\"${escapeAttr(href)}\">${escapeHtml(label)}</a></div>`;\n}\n\n/** Table of recent webhook deliveries for an inspector tab. Newest first. */\nexport function renderWebhookDeliveries(\n deliveries: ReadonlyArray<{\n id: number;\n hook_id: number;\n event: string;\n action?: string;\n status_code: number | null;\n success: boolean;\n delivered_at: string;\n duration: number | null;\n attempt?: number;\n retry_of?: number;\n redelivery_of?: number;\n }>,\n /** Target URL for a subscription id, e.g. `(id) => webhooks.getSubscription(id)?.url`. */\n urlFor: (hookId: number) => string | undefined = () => undefined,\n): string {\n if (deliveries.length === 0) {\n return '<p class=\"empty\">No webhook deliveries yet.</p>';\n }\n const rows = [...deliveries]\n .reverse()\n .map((delivery) => {\n const status = delivery.status_code === null ? \"no response\" : String(delivery.status_code);\n const badge = delivery.success ? \"badge-granted\" : \"badge-denied\";\n let note = \"\";\n if (delivery.retry_of) {\n note = `retry ${delivery.attempt} of #${delivery.retry_of}`;\n } else if (delivery.redelivery_of) {\n note = `redelivery of #${delivery.redelivery_of}`;\n }\n const event = delivery.action ? `${delivery.event}.${delivery.action}` : delivery.event;\n return `<tr><td>#${delivery.id}</td><td>${escapeHtml(event)}</td><td>${escapeHtml(urlFor(delivery.hook_id) ?? \"\")}</td><td><span class=\"badge ${badge}\">${escapeHtml(status)}</span></td><td>${delivery.duration ?? 0} ms</td><td>${escapeHtml(delivery.delivered_at)}</td><td>${escapeHtml(note)}</td></tr>`;\n })\n .join(\"\");\n return `<table class=\"inspector-table\"><thead><tr><th>Delivery</th><th>Event</th><th>URL</th><th>Status</th><th>Time</th><th>Sent</th><th></th></tr></thead><tbody>${rows}</tbody></table>`;\n}\n","import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Hono } from \"./http.js\";\nimport type { AppEnv } from \"./middleware/auth.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nconst FONTS: Record<string, Buffer> = {\n \"geist-sans.woff2\": readFileSync(join(__dirname, \"fonts\", \"geist-sans.woff2\")),\n \"GeistPixel-Square.woff2\": readFileSync(join(__dirname, \"fonts\", \"GeistPixel-Square.woff2\")),\n};\n\nconst FAVICON = readFileSync(join(__dirname, \"fonts\", \"favicon.ico\"));\n\nexport function registerFontRoutes(app: Hono<AppEnv>): void {\n app.get(\"/_baseline/fonts/:name\", (c) => {\n const name = c.req.param(\"name\");\n const buf = FONTS[name];\n if (!buf) {\n return c.notFound();\n }\n return new Response(buf, {\n headers: {\n \"Content-Type\": \"font/woff2\",\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n });\n\n app.get(\n \"/_baseline/favicon.ico\",\n (_c) =>\n new Response(FAVICON, {\n headers: {\n \"Content-Type\": \"image/x-icon\",\n \"Cache-Control\": \"public, max-age=31536000, immutable\",\n },\n }),\n );\n}\n","/*!\n * This HTTP compatibility layer builds on Hono's API and design.\n * https://github.com/honojs/hono\n * Copyright (c) 2021 - present, Yusuke Wada and Hono contributors\n * MIT license: see THIRD_PARTY_NOTICES.md in the repository and npm packages.\n */\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport { createServer as createNodeServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { join } from \"node:path\";\nimport type { Duplex } from \"node:stream\";\nimport { threadId } from \"node:worker_threads\";\n\nconst MATCH_ANYTHING = /^.*$/;\nconst PARAM_NAME_CHAR = /[A-Za-z0-9_]/;\n\ntype BodyInit = ConstructorParameters<typeof Response>[0];\ntype HeadersInit = ConstructorParameters<typeof Headers>[0];\ntype FormDataEntryValue = string | File;\n\nexport type ContentfulStatusCode = number;\nexport type Next = () => Promise<void>;\n\n// biome-ignore lint/suspicious/noExplicitAny: reaches the public Context.get/set types; untyped variables must stay assignable to anything, as in Hono\ntype UntypedVariables = Record<string, any>;\ntype VariablesOf<E> = unknown extends E ? UntypedVariables : E extends { Variables: infer V } ? V : UntypedVariables;\ntype HandlerResult = Response | void | Promise<Response | void>;\n\nexport type Handler<E = unknown, P extends string = string> = (c: Context<E, P>, next: Next) => HandlerResult;\nexport type MiddlewareHandler<E = unknown> = Handler<E>;\nexport type ErrorHandler<E = unknown> = (err: unknown, c: Context<E>) => Response | Promise<Response>;\nexport type FetchHandler = (request: Request) => Response | Promise<Response>;\n\nexport interface HttpOptions {\n strictRoutes?: boolean;\n strictJson?: boolean;\n onError?: (error: unknown, request: Request) => void;\n}\n\nexport interface RouteInfo {\n method: string;\n path: string;\n source?: string;\n}\n\ninterface CompiledPath {\n pattern: string;\n regex: RegExp;\n paramNames: string[];\n}\n\ninterface Route<E> {\n method: string;\n compiled: CompiledPath;\n handlers: Handler<E>[];\n source?: string;\n}\n\ninterface MatchedHandler<E> {\n handler: Handler<E>;\n params: Record<string, string>;\n}\n\n/** An upgrade request (a WebSocket handshake) matched to a route registered with `app.upgrade`. */\nexport interface UpgradeRequest {\n /** Node's request. Its `url` is the raw path; use `url` below for the path the service sees. */\n request: IncomingMessage;\n socket: Duplex;\n head: Buffer;\n /** The request URL as the service sees it: a single-port `/<service>` prefix is already removed. */\n url: URL;\n params: Record<string, string>;\n}\n\nexport type UpgradeHandler = (upgrade: UpgradeRequest) => void | Promise<void>;\n\n/**\n * Handles Node's `upgrade` event. Returns false when no route matched, so the\n * caller can try another listener or reject the socket. `path` overrides the\n * request's path and query (single-port mode passes it without the prefix).\n */\nexport type UpgradeListener = (request: IncomingMessage, socket: Duplex, head: Buffer, path?: string) => boolean;\n\nconst STATUS_TEXT: Record<number, string> = {\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 500: \"Internal Server Error\",\n 501: \"Not Implemented\",\n 503: \"Service Unavailable\",\n};\n\n/** Refuse an upgrade with a plain HTTP response and close the socket. */\nexport function rejectUpgrade(socket: Duplex, status: number, message = STATUS_TEXT[status] ?? \"\"): void {\n if (socket.destroyed) {\n return;\n }\n const body = Buffer.from(message);\n socket.end(\n `HTTP/1.1 ${status} ${STATUS_TEXT[status] ?? \"Error\"}\\r\\nConnection: close\\r\\nContent-Type: text/plain; charset=utf-8\\r\\nContent-Length: ${body.length}\\r\\n\\r\\n${message}`,\n () => socket.destroy(),\n );\n}\n\nexport interface ServeOptions {\n fetch: FetchHandler;\n port?: number;\n /** Listening address. Defaults to IPv4 loopback (127.0.0.1). */\n hostname?: string;\n /** Handles upgrade requests (WebSocket handshakes), e.g. `app.handleUpgrade`. Unhandled ones get 404. */\n upgrade?: UpgradeListener;\n}\n\nexport interface CorsOptions {\n origin?: string;\n allowMethods?: string[];\n allowHeaders?: string[];\n credentials?: boolean;\n maxAge?: number;\n /** Lets a plain (non-preflight) OPTIONS request through to the routes when this returns true. */\n passThrough?: (c: Context) => boolean;\n}\n\n// biome-ignore lint/correctness/noUnusedVariables: P mirrors Hono's HonoRequest signature so handler types line up.\nexport class HonoRequest<P extends string = string> {\n readonly raw: Request;\n readonly url: string;\n readonly method: string;\n readonly path: string;\n private readonly params: Record<string, string>;\n private readonly strictJson: boolean;\n\n constructor(request: Request, params: Record<string, string>, strictJson = false) {\n this.params = params;\n this.strictJson = strictJson;\n this.raw = request;\n this.url = request.url;\n this.method = request.method;\n this.path = new URL(request.url).pathname;\n }\n\n header(): Record<string, string>;\n header(name: string): string | undefined;\n header(name?: string): Record<string, string> | string | undefined {\n if (name) {\n return this.raw.headers.get(name) ?? undefined;\n }\n const headers: Record<string, string> = {};\n this.raw.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return headers;\n }\n\n query(name: string): string | undefined {\n return new URL(this.url).searchParams.get(name) ?? undefined;\n }\n\n queries(name: string): string[] | undefined {\n const values = new URL(this.url).searchParams.getAll(name);\n return values.length > 0 ? values : undefined;\n }\n\n param(): Record<string, string>;\n param(name: string): string;\n param(name?: string): Record<string, string> | string {\n if (!name) {\n return { ...this.params };\n }\n return this.params[name] ?? \"\";\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: public default, as in Hono; callers read untyped JSON bodies without a cast\n async json<T = any>(): Promise<T> {\n try {\n return (await this.raw.json()) as T;\n } catch (error) {\n if (!this.strictJson) {\n throw error;\n }\n throw Object.assign(new Error(\"Invalid JSON request body\", { cause: error }), { status: 400 });\n }\n }\n\n text(): Promise<string> {\n return this.raw.text();\n }\n\n arrayBuffer(): Promise<ArrayBuffer> {\n return this.raw.arrayBuffer();\n }\n\n async parseBody(): Promise<Record<string, FormDataEntryValue | FormDataEntryValue[]>> {\n const contentType = this.header(\"Content-Type\") ?? \"\";\n if (contentType.includes(\"multipart/form-data\")) {\n return formDataToObject(await this.raw.formData());\n }\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const params = new URLSearchParams(await this.raw.text());\n const out: Record<string, string | string[]> = {};\n for (const [key, value] of params) {\n appendBodyValue(out, key, value);\n }\n return out;\n }\n if (contentType.includes(\"application/json\")) {\n const body = this.strictJson ? await this.json() : await this.raw.json().catch(() => ({}));\n return body && typeof body === \"object\" && !Array.isArray(body)\n ? (body as Record<string, FormDataEntryValue | FormDataEntryValue[]>)\n : {};\n }\n return {};\n }\n}\n\nexport class Context<E = unknown, P extends string = string> {\n readonly req: HonoRequest<P>;\n private readonly vars = new Map<string, unknown>();\n private readonly responseHeaders = new Headers();\n private readonly headerOperations: Array<{ name: string; value: string; append: boolean }> = [];\n private readonly appliedHeaders = new WeakMap<Response, number>();\n private responseStatus = 200;\n /** In middleware, after `await next()`: the response the rest of the chain produced, as in Hono. */\n res: Response | undefined;\n private readonly notFoundHandler: (c: Context<E>) => Response | Promise<Response>;\n\n constructor(\n request: Request,\n params: Record<string, string>,\n notFoundHandler: (c: Context<E>) => Response | Promise<Response>,\n strictJson = false,\n ) {\n this.notFoundHandler = notFoundHandler;\n this.req = new HonoRequest<P>(request, params, strictJson);\n }\n\n get<K extends keyof VariablesOf<E> & string>(key: K): VariablesOf<E>[K] | undefined {\n return this.vars.get(key) as VariablesOf<E>[K] | undefined;\n }\n\n set<K extends keyof VariablesOf<E> & string>(key: K, value: VariablesOf<E>[K]): void {\n this.vars.set(key, value);\n }\n\n header(name: string, value: string, options?: { append?: boolean }): void {\n if (options?.append) {\n this.responseHeaders.append(name, value);\n } else {\n this.responseHeaders.set(name, value);\n }\n this.headerOperations.push({ name, value, append: options?.append === true });\n }\n\n status(status: number): void {\n this.responseStatus = status;\n }\n\n json(data: unknown, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(JSON.stringify(data), status, defaultContentType(headers, \"application/json; charset=UTF-8\"));\n }\n\n text(text: string, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(text, status, defaultContentType(headers, \"text/plain; charset=UTF-8\"));\n }\n\n html(html: string, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(html, status, defaultContentType(headers, \"text/html; charset=UTF-8\"));\n }\n\n body(body: BodyInit | null, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n return this.response(body, status, headers);\n }\n\n redirect(location: string, status: ContentfulStatusCode = 302): Response {\n return this.response(null, status, { Location: location });\n }\n\n notFound(): Response | Promise<Response> {\n return this.notFoundHandler(this);\n }\n\n finalize(response: Response): Response {\n const applied = this.appliedHeaders.get(response) ?? 0;\n if (applied === this.headerOperations.length) {\n return response;\n }\n const headers = new Headers(response.headers);\n mergeHeaders(headers, this.headerOperations.slice(applied));\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n private response(body: BodyInit | null, status?: ContentfulStatusCode, headers?: HeadersInit): Response {\n const merged = new Headers(headers);\n mergeHeaders(merged, this.headerOperations);\n const response = new Response(body, {\n status: status ?? this.responseStatus,\n headers: merged,\n });\n this.appliedHeaders.set(response, this.headerOperations.length);\n return response;\n }\n}\n\n// Route-hit recording for the test coverage gate (@deploybaseline/testing).\n// Off unless BASELINE_COVERAGE_DIR is set. Each process appends every route\n// pattern it matches once, so the cost is one small write per distinct route.\nconst recordedRoutes = new Set<string>();\n\nfunction recordRouteHit(method: string, pattern: string): void {\n recordCoverageHit(`${method} ${pattern}`);\n}\n\n/**\n * Record that a test reached a coverage key: a route (`\"GET /repos/:owner/:repo\"`,\n * recorded by the router) or an operation such as a GraphQL root field\n * (`\"Query.issues\"`, recorded by `@deploybaseline/graphql`). A no-op unless\n * BASELINE_COVERAGE_DIR is set.\n */\nexport function recordCoverageHit(key: string): void {\n const dir = process.env.BASELINE_COVERAGE_DIR;\n if (!dir) {\n return;\n }\n if (recordedRoutes.has(key)) {\n return;\n }\n recordedRoutes.add(key);\n try {\n mkdirSync(dir, { recursive: true });\n appendFileSync(join(dir, `${process.pid}-${threadId}.jsonl`), `${JSON.stringify(key)}\\n`);\n } catch {\n // Coverage recording must never break a request.\n }\n}\n\n// Response sampling for the spec gate (@deploybaseline/testing). Off unless\n// BASELINE_RESPONSE_DIR is set. Keeps a few JSON bodies per route and status in\n// each process, so every test doubles as a response shape check.\nconst SAMPLES_PER_KEY = 3;\nconst sampleCounts = new Map<string, number>();\n\nasync function recordResponseSample(method: string, pattern: string, response: Response): Promise<void> {\n if (!process.env.BASELINE_RESPONSE_DIR) {\n return;\n }\n if (!((response.headers.get(\"content-type\") ?? \"\").includes(\"json\") && response.body)) {\n return;\n }\n if (!sampleSlot(method, pattern, response.status)) {\n return;\n }\n try {\n writeResponseSample(method, pattern, response.status, JSON.parse(await response.clone().text()));\n } catch {\n // Sampling must never break a request.\n }\n}\n\n/**\n * Record a JSON response body for the spec gate under a route key, for\n * services that dispatch many vendor routes inside one registered route (a\n * coverage key recorded with `recordCoverageHit`). A no-op unless\n * BASELINE_RESPONSE_DIR is set. Keeps a few bodies per route and status.\n */\nexport function recordResponseBody(method: string, pattern: string, status: number, body: unknown): void {\n if (!process.env.BASELINE_RESPONSE_DIR || body === null || body === undefined) {\n return;\n }\n if (!sampleSlot(method, pattern, status)) {\n return;\n }\n try {\n writeResponseSample(method, pattern, status, body);\n } catch {\n // Sampling must never break a request.\n }\n}\n\n/**\n * Start a fresh sample budget. `@deploybaseline/testing` calls this before each\n * test file, so a worker that runs several files samples each one the way a\n * fresh process would.\n */\nexport function resetResponseSamples(): void {\n sampleCounts.clear();\n}\n\nfunction sampleSlot(method: string, pattern: string, status: number): boolean {\n const key = `${method} ${pattern} ${status}`;\n const count = sampleCounts.get(key) ?? 0;\n if (count >= SAMPLES_PER_KEY) {\n return false;\n }\n sampleCounts.set(key, count + 1);\n return true;\n}\n\nfunction writeResponseSample(method: string, pattern: string, status: number, body: unknown): void {\n const dir = process.env.BASELINE_RESPONSE_DIR!;\n mkdirSync(dir, { recursive: true });\n appendFileSync(\n join(dir, `${process.pid}-${threadId}.jsonl`),\n `${JSON.stringify({ method, route: pattern, status, body })}\\n`,\n );\n}\n\nfunction mergeHeaders(target: Headers, operations: Array<{ name: string; value: string; append: boolean }>): void {\n for (const { name, value, append } of operations) {\n if (append) {\n target.append(name, value);\n } else {\n target.set(name, value);\n }\n }\n}\n\nexport class Hono<E = unknown> {\n private readonly options: HttpOptions;\n\n constructor(options: HttpOptions = {}) {\n this.options = options;\n }\n\n get routeTable(): RouteInfo[] {\n return this.routes.map((r) => ({ method: r.method, path: r.compiled.pattern, source: r.source }));\n }\n\n /**\n * Operations served inside routes, such as GraphQL root fields\n * (`\"Query.issues\"`, `\"Mutation.issueCreate\"`) or vendor routes a service\n * dispatches itself (`\"GET /v1.0/me/events\"`, Microsoft Graph). The\n * coverage matrix lists them next to routes.\n */\n get operationTable(): string[] {\n return [...this.operations];\n }\n\n /** Upgrade routes (WebSocket endpoints) as registered paths. */\n get upgradeTable(): string[] {\n return this.upgrades.map((route) => route.compiled.pattern);\n }\n\n /**\n * Accept upgrade requests (WebSocket handshakes) on `path`. The handler gets\n * Node's request and socket; `@deploybaseline/ws` completes the handshake.\n * Upgrades skip middleware, so the handler checks its own credentials.\n * A request that reaches `fetch` without going through an upgrading server answers 501.\n */\n upgrade(path: string, handler: UpgradeHandler): this {\n if (this.options.strictRoutes && (path === \"/_baseline\" || path.startsWith(\"/_baseline/\"))) {\n throw new Error(`Upgrade route ${path} uses the reserved /_baseline namespace`);\n }\n this.upgrades.push({ compiled: compilePath(path), handler });\n return this;\n }\n\n /** Node `upgrade` event handler for this app's upgrade routes. Sockets it accepts are closed by `dispose()`. */\n handleUpgrade: UpgradeListener = (request, socket, head, path) => {\n const url = new URL(path ?? request.url ?? \"/\", `http://${request.headers.host ?? \"localhost\"}`);\n const route = this.upgrades.find((candidate) => pathMatches(candidate.compiled, url.pathname));\n if (!route) {\n return false;\n }\n recordCoverageHit(`WS ${route.compiled.pattern}`);\n this.upgradedSockets.add(socket);\n socket.once(\"close\", () => this.upgradedSockets.delete(socket));\n const params = matchPath(route.compiled, url.pathname) ?? {};\n Promise.resolve()\n .then(() => route.handler({ request, socket, head, url, params }))\n .catch((error) => {\n this.options.onError?.(error, new Request(url));\n rejectUpgrade(socket, 500);\n });\n return true;\n };\n\n /** Run cleanup when the service stops, e.g. closing WebSocket connections. */\n onDispose(callback: () => void | Promise<void>): this {\n this.disposers.push(callback);\n return this;\n }\n\n /** Run `onDispose` callbacks, then close any upgraded socket still open. Safe to call more than once. */\n async dispose(): Promise<void> {\n const callbacks = this.disposers.splice(0);\n await Promise.allSettled(callbacks.map((callback) => Promise.resolve().then(callback)));\n for (const socket of this.upgradedSockets) {\n socket.destroy();\n }\n this.upgradedSockets.clear();\n }\n private readonly upgrades: Array<{ compiled: CompiledPath; handler: UpgradeHandler }> = [];\n private readonly upgradedSockets = new Set<Duplex>();\n private readonly disposers: Array<() => void | Promise<void>> = [];\n\n /** Declare operations served by this app's routes (see `operationTable`). Duplicates are ignored. */\n declareOperations(keys: Iterable<string>): this {\n for (const key of keys) {\n if (!this.operations.includes(key)) {\n this.operations.push(key);\n }\n }\n return this;\n }\n private readonly operations: string[] = [];\n\n matchedRoute(method: string, path: string): RouteInfo | undefined {\n const route =\n this.routes.find((r) => r.method === method && matchPath(r.compiled, path)) ??\n (method === \"HEAD\" ? this.routes.find((r) => r.method === \"GET\" && matchPath(r.compiled, path)) : undefined);\n return route && { method: route.method, path: route.compiled.pattern, source: route.source };\n }\n private readonly middleware: Route<E>[] = [];\n private readonly routes: Route<E>[] = [];\n private errorHandler: ErrorHandler<E> = (err) => {\n const message = err instanceof Error ? err.message : \"Internal Server Error\";\n return new Response(message, { status: 500 });\n };\n private notFoundHandler: (c: Context<E>) => Response | Promise<Response> = () =>\n new Response(\"404 Not Found\", { status: 404 });\n\n use<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this;\n use(...handlers: Handler<E>[]): this;\n use<P extends string = string>(pathOrHandler: string | Handler<E>, ...handlers: Handler<E, P>[]): this {\n if (typeof pathOrHandler === \"string\") {\n this.middleware.push({ method: \"ALL\", compiled: compilePath(pathOrHandler), handlers: handlers as Handler<E>[] });\n } else {\n this.middleware.push({ method: \"ALL\", compiled: compilePath(\"*\"), handlers: [pathOrHandler, ...handlers] });\n }\n return this;\n }\n\n on<P extends string = string>(method: string, path: string, ...handlers: Handler<E, P>[]): this {\n const compiled = compilePath(path);\n // biome-ignore lint/suspicious/useErrorMessage: the Error only captures the registration stack.\n const source = this.options.strictRoutes ? new Error().stack?.split(\"\\n\").slice(2).join(\"\\n\") : undefined;\n if (this.options.strictRoutes) {\n if (path === \"/_baseline\" || path.startsWith(\"/_baseline/\")) {\n throw new Error(`Route ${method} ${path} uses the reserved /_baseline namespace`);\n }\n const existing = this.routes.find(\n (r) => r.method === method.toUpperCase() && r.compiled.regex.source === compiled.regex.source,\n );\n if (existing) {\n throw new Error(\n `Duplicate route ${method} ${path}\\nFirst registration:${existing.source}\\nSecond registration:${source}`,\n );\n }\n }\n this.routes.push({ method: method.toUpperCase(), compiled, handlers: handlers as Handler<E>[], source });\n return this;\n }\n\n get<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"GET\", path, ...handlers);\n }\n\n post<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"POST\", path, ...handlers);\n }\n\n put<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"PUT\", path, ...handlers);\n }\n\n patch<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"PATCH\", path, ...handlers);\n }\n\n delete<P extends string = string>(path: string, ...handlers: Handler<E, P>[]): this {\n return this.on(\"DELETE\", path, ...handlers);\n }\n\n onError(handler: ErrorHandler<E>): this {\n this.errorHandler = handler;\n return this;\n }\n\n notFound(handler: (c: Context<E>) => Response | Promise<Response>): this {\n this.notFoundHandler = handler;\n return this;\n }\n\n async request(input: string | Request, init?: RequestInit): Promise<Response> {\n if (input instanceof Request) {\n return this.fetch(input);\n }\n const url = input.startsWith(\"/\") ? `http://localhost${input}` : input;\n return this.fetch(new Request(url, init));\n }\n\n fetch = async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const path = url.pathname;\n const method = request.method.toUpperCase();\n // A WebSocket handshake that arrived as a plain request (e.g. through `app.request` or a\n // plain fetch handler): nothing here can upgrade it. Some fetch handlers drop a trailing\n // slash, so `/link` still matches an upgrade route on `/link/`.\n if (\n request.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\" &&\n this.upgrades.some((route) => pathMatches(route.compiled, path) || pathMatches(route.compiled, `${path}/`))\n ) {\n return Response.json(\n {\n error:\n \"WebSocket endpoints need a server that can upgrade connections. Run this service with the Baseline CLI or createEmulator; a plain fetch handler serves HTTP only.\",\n documentation_url: \"https://docs.deploybaseline.com/websockets\",\n },\n { status: 501 },\n );\n }\n const matched = this.match(method, path);\n const context = new Context<E>(request, matched.params, this.notFoundHandler, this.options.strictJson);\n\n try {\n const response = await this.dispatch(context, matched.handlers);\n const finalized = context.finalize(response ?? (await this.notFoundHandler(context)));\n if (matched.route && process.env.BASELINE_RESPONSE_DIR) {\n await recordResponseSample(matched.route.method, matched.route.compiled.pattern, finalized);\n }\n return finalized;\n } catch (err) {\n this.options.onError?.(err, request);\n return context.finalize(await this.errorHandler(err, context));\n }\n };\n\n private match(\n method: string,\n path: string,\n ): { handlers: MatchedHandler<E>[]; params: Record<string, string>; route?: Route<E> } {\n const handlers: MatchedHandler<E>[] = [];\n const params: Record<string, string> = {};\n\n for (const route of this.middleware) {\n const match = matchPath(route.compiled, path);\n if (!match) {\n continue;\n }\n Object.assign(params, match);\n for (const handler of route.handlers) {\n handlers.push({ handler, params: match });\n }\n }\n\n const route =\n this.routes.find((candidate) => candidate.method === method && pathMatches(candidate.compiled, path)) ??\n (method === \"HEAD\"\n ? this.routes.find((candidate) => candidate.method === \"GET\" && pathMatches(candidate.compiled, path))\n : undefined);\n\n if (route) {\n recordRouteHit(route.method, route.compiled.pattern);\n const match = matchPath(route.compiled, path) ?? {};\n Object.assign(params, match);\n for (const handler of route.handlers) {\n handlers.push({ handler, params: match });\n }\n }\n\n return { handlers, params, route };\n }\n\n private async dispatch(context: Context<E>, handlers: MatchedHandler<E>[]): Promise<Response | void> {\n let index = -1;\n const run = async (nextIndex: number): Promise<Response | void> => {\n if (nextIndex <= index) {\n throw new Error(\"next() called multiple times\");\n }\n index = nextIndex;\n const matched = handlers[nextIndex];\n if (!matched) {\n return undefined;\n }\n\n const originalParams = context.req.param();\n Object.assign(originalParams, matched.params);\n\n let nextResponse: Response | undefined | void;\n let nextCalled = false;\n const next: Next = async () => {\n nextCalled = true;\n nextResponse = await run(nextIndex + 1);\n if (nextResponse instanceof Response) {\n context.res = nextResponse;\n }\n };\n\n const response = await matched.handler(context, next);\n if (response instanceof Response) {\n return response;\n }\n if (nextCalled) {\n return nextResponse;\n }\n return response;\n };\n\n return run(0);\n }\n}\n\nexport function cors(options: CorsOptions = {}): MiddlewareHandler {\n const origin = options.origin ?? \"*\";\n const allowMethods = options.allowMethods ?? [\"GET\", \"HEAD\", \"PUT\", \"POST\", \"DELETE\", \"PATCH\", \"OPTIONS\"];\n\n return async (c, next) => {\n c.header(\"Access-Control-Allow-Origin\", origin);\n if (options.credentials) {\n c.header(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n if (c.req.method.toUpperCase() === \"OPTIONS\") {\n // An OPTIONS request that is not a browser preflight (no Access-Control-Request-Method)\n // may be an API call in its own right, when a plugin registers an OPTIONS route.\n if (!c.req.header(\"Access-Control-Request-Method\") && options.passThrough?.(c)) {\n await next();\n return;\n }\n c.header(\"Access-Control-Allow-Methods\", allowMethods.join(\",\"));\n const allowHeaders = options.allowHeaders?.join(\",\") ?? c.req.header(\"Access-Control-Request-Headers\");\n if (allowHeaders) {\n c.header(\"Access-Control-Allow-Headers\", allowHeaders);\n }\n if (options.maxAge !== null && options.maxAge !== undefined) {\n c.header(\"Access-Control-Max-Age\", String(options.maxAge));\n }\n return c.body(null, 204);\n }\n\n await next();\n };\n}\n\nexport function serve(options: ServeOptions): Server {\n const port = options.port ?? 3000;\n const { upgrade } = options;\n const server = createNodeServer(async (req, res) => {\n try {\n const request = nodeRequestToFetchRequest(req);\n const response = await options.fetch(request);\n await writeFetchResponse(res, response, req.method?.toUpperCase() === \"HEAD\");\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Internal Server Error\";\n res.statusCode = 500;\n res.setHeader(\"Content-Type\", \"text/plain; charset=UTF-8\");\n res.end(message);\n }\n });\n // Without a listener, Node drops upgrade requests silently; answer 404 instead.\n server.on(\"upgrade\", (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n socket.on(\"error\", () => {\n // No-op.\n });\n let handled = false;\n try {\n handled = upgrade?.(req, socket, head) ?? false;\n } catch {\n rejectUpgrade(socket, 500);\n return;\n }\n if (!handled) {\n rejectUpgrade(socket, 404);\n }\n });\n server.listen(port, options.hostname ?? \"127.0.0.1\");\n return server;\n}\n\nfunction compilePath(pattern: string): CompiledPath {\n if (pattern === \"*\" || pattern === \"/*\") {\n return { pattern, regex: MATCH_ANYTHING, paramNames: [] };\n }\n\n const paramNames: string[] = [];\n let source = \"^\";\n for (let i = 0; i < pattern.length; i += 1) {\n const char = pattern[i];\n // A trailing `/*` matches the path itself and everything below it, as in\n // Hono: `/v1/*` covers `/v1` and `/v1/users/1`. Any other `*` matches\n // anything, slashes included.\n if (char === \"/\" && pattern[i + 1] === \"*\" && i + 2 === pattern.length) {\n source += \"(?:/.*)?\";\n break;\n }\n if (char === \"*\") {\n source += \".*\";\n continue;\n }\n if (char !== \":\") {\n source += escapeRegex(char);\n continue;\n }\n\n let name = \"\";\n i += 1;\n while (i < pattern.length && PARAM_NAME_CHAR.test(pattern[i])) {\n name += pattern[i];\n i += 1;\n }\n i -= 1;\n paramNames.push(name);\n\n if (pattern[i + 1] === \"{\") {\n const close = pattern.indexOf(\"}\", i + 2);\n if (close < 0) {\n throw new Error(`Invalid route pattern: ${pattern}`);\n }\n const expr = pattern.slice(i + 2, close);\n source += `(${expr})`;\n i = close;\n } else {\n source += \"([^/]+)\";\n }\n }\n source += \"$\";\n return { pattern, regex: new RegExp(source), paramNames };\n}\n\nfunction pathMatches(compiled: CompiledPath, path: string): boolean {\n const match = matchPath(compiled, path);\n return match !== null && match !== undefined;\n}\n\nfunction matchPath(compiled: CompiledPath, path: string): Record<string, string> | null {\n const match = compiled.regex.exec(path);\n if (!match) {\n return null;\n }\n const params: Record<string, string> = {};\n for (let i = 0; i < compiled.paramNames.length; i += 1) {\n params[compiled.paramNames[i]] = decodePathParam(match[i + 1] ?? \"\");\n }\n return params;\n}\n\nfunction decodePathParam(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[|\\\\{}()[\\]^$+*?.]/g, \"\\\\$&\");\n}\n\nfunction defaultContentType(headers: HeadersInit | undefined, contentType: string): Headers {\n const out = new Headers(headers);\n if (!out.has(\"Content-Type\")) {\n out.set(\"Content-Type\", contentType);\n }\n return out;\n}\n\nfunction formDataToObject(formData: FormData): Record<string, FormDataEntryValue | FormDataEntryValue[]> {\n const out: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};\n for (const [key, value] of formData) {\n appendBodyValue(out, key, value);\n }\n return out;\n}\n\nfunction appendBodyValue<T>(target: Record<string, T | T[]>, key: string, value: T): void {\n // Fields named after Object.prototype members are not body fields.\n if (key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") {\n return;\n }\n const existing = Object.hasOwn(target, key) ? target[key] : undefined;\n if (existing === undefined) {\n target[key] = value;\n } else if (Array.isArray(existing)) {\n existing.push(value);\n } else {\n target[key] = [existing, value];\n }\n}\n\nfunction nodeRequestToFetchRequest(req: IncomingMessage): Request {\n const host = req.headers.host ?? \"localhost\";\n const url = new URL(req.url ?? \"/\", `http://${host}`);\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value === null || value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(key, item);\n }\n } else {\n headers.set(key, value);\n }\n }\n\n const method = req.method ?? \"GET\";\n const hasBody = method !== \"GET\" && method !== \"HEAD\";\n return new Request(url.toString(), {\n method,\n headers,\n body: hasBody ? (req as unknown as BodyInit) : undefined,\n duplex: \"half\",\n } as RequestInit & { duplex: string });\n}\n\nasync function writeFetchResponse(res: ServerResponse, response: Response, headOnly: boolean): Promise<void> {\n res.statusCode = response.status;\n res.statusMessage = response.statusText;\n\n const headersWithCookies = response.headers as Headers & { getSetCookie?: () => string[] };\n const cookies = headersWithCookies.getSetCookie?.();\n response.headers.forEach((value, key) => {\n if (key.toLowerCase() === \"set-cookie\" && cookies && cookies.length > 0) {\n return;\n }\n res.setHeader(key, value);\n });\n if (cookies && cookies.length > 0) {\n res.setHeader(\"Set-Cookie\", cookies);\n }\n\n if (headOnly || !response.body) {\n res.end();\n return;\n }\n\n // Send the status and headers now, so clients see a streamed response\n // before its first chunk.\n res.flushHeaders();\n const reader = response.body.getReader();\n // A client that disconnects mid-stream cancels the body, like a fetch runtime.\n const onClose = () => {\n if (!res.writableFinished) {\n reader.cancel().catch(() => {\n // Best effort: the failure is ignored.\n });\n }\n };\n res.once(\"close\", onClose);\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n if (res.destroyed) {\n break;\n }\n if (!res.write(value)) {\n // Remove both listeners whichever fires, so a slow client does not pile up close listeners.\n await new Promise<void>((resolve) => {\n const settle = () => {\n res.off(\"drain\", settle);\n res.off(\"close\", settle);\n resolve();\n };\n res.once(\"drain\", settle);\n res.once(\"close\", settle);\n });\n }\n }\n res.end();\n } catch (err) {\n res.destroy(err instanceof Error ? err : undefined);\n } finally {\n res.off(\"close\", onClose);\n }\n}\n","import { registerFontRoutes } from \"./fonts.js\";\nimport { Hono, type RouteInfo } from \"./http.js\";\nimport { escapeAttr, escapeHtml, renderInspectorPage, renderJsonDetails, renderStateView } from \"./ui.js\";\n\nconst TEXT_CONTENT_TYPE = /application\\/(json|[^;]+\\+json)|text\\/(plain|html)|application\\/x-www-form-urlencoded/;\nconst SENSITIVE_KEY_SUFFIX = /(?:^|_)(?:token|secret|password|api_key|private_key|cookie)$/;\n\nexport interface InspectorOptions {\n maxRequests?: number;\n maxBodyBytes?: number;\n redact?: string[];\n}\n\ninterface Trace {\n id: number;\n method: string;\n path: string;\n status?: number;\n duration?: number;\n route?: string;\n error?: string;\n request: { headers: Record<string, string>; body?: unknown };\n response?: { headers: Record<string, string>; body?: unknown };\n}\n\nexport function createCustomInspector(name: string, baseUrl: string, options: InspectorOptions) {\n for (const key of Object.keys(options)) {\n if (![\"maxRequests\", \"maxBodyBytes\", \"redact\"].includes(key)) {\n throw new Error(`Unknown inspector option: ${key}`);\n }\n }\n for (const key of [\"maxRequests\", \"maxBodyBytes\"] as const) {\n if (\n options[key] !== undefined &&\n (!Number.isSafeInteger(options[key]) || options[key]! < (key === \"maxRequests\" ? 1 : 0))\n ) {\n throw new Error(`inspector.${key} must be ${key === \"maxRequests\" ? \"a positive\" : \"a nonnegative\"} integer`);\n }\n }\n if (\n options.redact !== undefined &&\n (!Array.isArray(options.redact) || options.redact.some((key) => typeof key !== \"string\"))\n ) {\n throw new Error(\"inspector.redact must be an array of field names\");\n }\n const maxRequests = Math.max(1, Math.min(options.maxRequests ?? 100, 1000));\n const maxBytes = Math.max(0, Math.min(options.maxBodyBytes ?? 8192, 65_536));\n const sensitive = new Set([\n \"authorization\",\n \"proxy-authorization\",\n \"cookie\",\n \"set-cookie\",\n \"password\",\n \"secret\",\n \"token\",\n \"api_key\",\n \"apikey\",\n \"private_key\",\n ...(options.redact ?? []).map((s) => s.toLowerCase()),\n ]);\n function isSensitive(key: string): boolean {\n if (sensitive.has(key.toLowerCase())) {\n return true;\n }\n const normalized = key\n .replace(/([a-z0-9])([A-Z])/g, \"$1_$2\")\n .replace(/[-\\s]/g, \"_\")\n .toLowerCase();\n return sensitive.has(normalized) || SENSITIVE_KEY_SUFFIX.test(normalized);\n }\n const traces: Trace[] = [];\n const active = new WeakMap<Request, { trace: Trace; start: number; preview: Promise<unknown>; epoch: number }>();\n let epoch = 0;\n let nextId = 1;\n const assets = new Hono();\n registerFontRoutes(assets);\n const root = `${baseUrl}/_baseline`;\n function redact(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(redact);\n }\n if (!value || typeof value !== \"object\") {\n return value;\n }\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, isSensitive(key) ? \"[redacted]\" : redact(item)]),\n );\n }\n function headers(value: Headers): Record<string, string> {\n return Object.fromEntries(\n [...value].map(([key, val]) => [key, isSensitive(key) ? \"[redacted]\" : val.slice(0, maxBytes)]),\n );\n }\n async function preview(value: Request | Response): Promise<unknown> {\n if (!value.body || maxBytes === 0) {\n return undefined;\n }\n const type = value.headers.get(\"content-type\") ?? \"\";\n if (!TEXT_CONTENT_TYPE.test(type)) {\n return `[${type || \"binary/streaming\"} body omitted]`;\n }\n if (Number(value.headers.get(\"content-length\")) > maxBytes) {\n return \"[body exceeds preview limit]\";\n }\n const reader = value.clone().body!.getReader();\n const parts: Uint8Array[] = [];\n let size = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const bytes = await Promise.race([\n (async () => {\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) {\n break;\n }\n size += chunk.value.length;\n if (size > maxBytes) {\n throw new Error(\"limit\");\n }\n parts.push(chunk.value);\n }\n return Buffer.concat(parts);\n })(),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(\"stream\")), 50);\n }),\n ]);\n const text = bytes.toString(\"utf8\");\n if (type.includes(\"json\")) {\n try {\n return redact(JSON.parse(text));\n } catch {\n return \"[invalid JSON omitted]\";\n }\n }\n if (type.includes(\"x-www-form-urlencoded\")) {\n return redact(Object.fromEntries(new URLSearchParams(text)));\n }\n return text;\n } catch {\n return \"[large or streaming body omitted]\";\n } finally {\n clearTimeout(timer);\n reader.cancel().catch(() => {\n // Best effort: the failure is ignored.\n });\n }\n }\n function safePath(url: URL): string {\n for (const key of [...url.searchParams.keys()]) {\n if (isSensitive(key)) {\n url.searchParams.set(key, \"[redacted]\");\n }\n }\n return `${url.pathname}${url.search}`;\n }\n const api = {\n clear() {\n epoch += 1;\n traces.length = 0;\n },\n begin(request: Request, route?: RouteInfo): number {\n const id = nextId;\n nextId += 1;\n const trace: Trace = {\n id,\n method: request.method,\n path: safePath(new URL(request.url)),\n route: route?.path,\n request: { headers: headers(request.headers) },\n };\n active.set(request, { trace, start: performance.now(), preview: preview(request), epoch });\n return trace.id;\n },\n recordError(request: Request, error: unknown) {\n const entry = active.get(request);\n if (entry) {\n entry.trace.error = (error instanceof Error ? (error.stack ?? error.message) : String(error)).slice(\n 0,\n maxBytes,\n );\n }\n },\n async finish(request: Request, response: Response, _started?: number) {\n const entry = active.get(request);\n if (!entry) {\n return;\n }\n entry.trace.duration = Math.round((performance.now() - entry.start) * 100) / 100;\n entry.trace.status = response.status;\n entry.trace.request.body = await entry.preview;\n entry.trace.response = { headers: headers(response.headers), body: await preview(response) };\n if (entry.epoch !== epoch) {\n return;\n }\n traces.push(entry.trace);\n if (traces.length > maxRequests) {\n traces.splice(0, traces.length - maxRequests);\n }\n active.delete(request);\n },\n async handle(\n request: Request,\n runtime: { snapshot(): unknown; reset(): Promise<void>; routes(): RouteInfo[] },\n ): Promise<Response> {\n const url = new URL(request.url);\n if (url.pathname.startsWith(\"/_baseline/fonts/\") || url.pathname === \"/_baseline/favicon.ico\") {\n return assets.fetch(request);\n }\n if (request.method === \"POST\" && url.pathname === \"/_baseline/reset\") {\n const origin = request.headers.get(\"origin\");\n if (origin && origin !== new URL(baseUrl).origin) {\n return Response.json({ error: \"Origin does not match this emulator\" }, { status: 403 });\n }\n await runtime.reset();\n return new Response(null, { status: 303, headers: { Location: `${root}?tab=state` } });\n }\n if (request.method !== \"GET\" || (url.pathname !== \"/_baseline\" && url.pathname !== \"/_baseline/\")) {\n return Response.json({ error: \"Not Found\" }, { status: 404 });\n }\n const tab = [\"requests\", \"routes\", \"state\"].includes(url.searchParams.get(\"tab\") ?? \"\")\n ? url.searchParams.get(\"tab\")!\n : \"requests\";\n const tabs = [\"requests\", \"routes\", \"state\"].map((id) => ({\n id,\n label: id[0].toUpperCase() + id.slice(1),\n href: `${root}?tab=${id}`,\n }));\n let body = `<div class=\"s-card\"><div class=\"s-title\">${escapeHtml(name)}</div><p class=\"s-subtitle\">${escapeHtml(baseUrl)}</p><form method=\"post\" action=\"${escapeAttr(root)}/reset\"><button type=\"submit\" class=\"inspector-action\">Reset to seed</button></form></div>`;\n if (tab === \"state\") {\n body += renderStateView(redact((runtime.snapshot() as { state: unknown }).state));\n }\n if (tab === \"routes\") {\n body += `<div class=\"inspector-scroll\"><table class=\"inspector-table\"><thead><tr><th>Method</th><th>Path</th><th>Request</th></tr></thead><tbody>${runtime\n .routes()\n .map((route) => {\n const target = `${baseUrl}${route.path.replace(/:([a-zA-Z0-9_]+)/g, \"example\")}`;\n const command = `curl -X ${route.method} '${target.replace(/'/g, \"'\\\\''\")}'`;\n return `<tr><td>${escapeHtml(route.method)}</td><td>${escapeHtml(route.path)}</td><td><code>${escapeHtml(command)}</code></td></tr>`;\n })\n .join(\"\")}</tbody></table></div>`;\n }\n if (tab === \"requests\") {\n body += traces.length\n ? [...traces]\n .reverse()\n .map((trace) =>\n renderJsonDetails(\n `${trace.method} ${trace.path} · ${trace.status} · ${trace.duration} ms${trace.route ? \"\" : \" · unmatched\"}`,\n trace,\n ),\n )\n .join(\"\")\n : `<div class=\"empty\">No API requests yet. Send a request to ${escapeHtml(baseUrl)} to see it here.</div>`;\n }\n let html = renderInspectorPage(`${name} inspector`, tabs, tab, body, name);\n // Core assets use absolute paths; a custom emulator can be served below a path prefix.\n html = html.replaceAll('\"/_baseline/', `\"${root}/`).replaceAll(\"'/_baseline/\", `'${root}/`);\n return new Response(html, {\n headers: { \"Content-Type\": \"text/html; charset=utf-8\", \"Cache-Control\": \"no-store\" },\n });\n },\n };\n return api;\n}\n","import { createHmac, type KeyLike, sign as signData, timingSafeEqual, verify as verifyData } from \"node:crypto\";\n\nconst HEX_DIGITS = /^[0-9a-f]+$/i;\n\n// Webhook signing schemes, each with a matching verify for tests. New\n// providers sign with these instead of building their own HMAC headers.\n\ntype Body = string | Uint8Array;\n\nconst toBuffer = (body: Body) => (typeof body === \"string\" ? Buffer.from(body) : Buffer.from(body));\nconst unixNow = () => Math.floor(Date.now() / 1000);\n\nfunction safeEqual(a: string, b: string): boolean {\n const left = Buffer.from(a);\n const right = Buffer.from(b);\n return left.length === right.length && timingSafeEqual(left, right);\n}\n\nfunction withinTolerance(timestamp: number, toleranceSeconds: number, now = unixNow()): boolean {\n return Number.isFinite(timestamp) && Math.abs(now - timestamp) <= toleranceSeconds;\n}\n\n/** HMAC-SHA256 of the body, hex encoded (Linear `Linear-Signature`, generic hooks). */\nexport function hmacSha256Hex(secret: string | Uint8Array, body: Body): string {\n return createHmac(\"sha256\", secret).update(toBuffer(body)).digest(\"hex\");\n}\n\nexport function verifyHmacSha256Hex(secret: string | Uint8Array, body: Body, signature: string): boolean {\n return safeEqual(hmacSha256Hex(secret, body), signature);\n}\n\n/** HMAC-SHA256 of the body, base64 encoded (Shopify, Twilio style). */\nexport function hmacSha256Base64(secret: string | Uint8Array, body: Body): string {\n return createHmac(\"sha256\", secret).update(toBuffer(body)).digest(\"base64\");\n}\n\nexport function verifyHmacSha256Base64(secret: string | Uint8Array, body: Body, signature: string): boolean {\n return safeEqual(hmacSha256Base64(secret, body), signature);\n}\n\n/** GitHub `X-Hub-Signature-256`: `sha256=<hex HMAC of the body>`. */\nexport function githubSignature256(secret: string, body: Body): string {\n return `sha256=${hmacSha256Hex(secret, body)}`;\n}\n\nexport function verifyGithubSignature256(secret: string, body: Body, header: string): boolean {\n return safeEqual(githubSignature256(secret, body), header);\n}\n\n/**\n * Svix / Standard Webhooks (Resend, Clerk): `svix-signature: v1,<base64 HMAC of \"<id>.<ts>.<body>\">`.\n * The secret is `whsec_<base64 key>`; the key is the decoded part.\n */\nexport function svixSignature(\n secret: string,\n body: Body,\n options: { id: string; timestamp?: number },\n): Record<string, string> {\n const timestamp = options.timestamp ?? unixNow();\n const key = Buffer.from(secret.startsWith(\"whsec_\") ? secret.slice(\"whsec_\".length) : secret, \"base64\");\n const payload = Buffer.concat([Buffer.from(`${options.id}.${timestamp}.`), toBuffer(body)]);\n return {\n \"svix-id\": options.id,\n \"svix-timestamp\": String(timestamp),\n \"svix-signature\": `v1,${hmacSha256Base64(key, payload)}`,\n };\n}\n\nexport function verifySvixSignature(\n secret: string,\n body: Body,\n headers: { id: string; timestamp: string; signature: string },\n toleranceSeconds = 300,\n): boolean {\n const timestamp = Number(headers.timestamp);\n if (!withinTolerance(timestamp, toleranceSeconds)) {\n return false;\n }\n const expected = svixSignature(secret, body, { id: headers.id, timestamp })[\"svix-signature\"];\n // The header may carry several space-separated signatures during key rotation.\n return headers.signature.split(\" \").some((candidate) => safeEqual(expected, candidate));\n}\n\n/**\n * Ed25519 over `<timestamp><body>`, hex encoded (Discord interactions:\n * `X-Signature-Ed25519` and `X-Signature-Timestamp`).\n */\nexport function ed25519Signature(privateKey: KeyLike, body: Body, timestamp = unixNow()): Record<string, string> {\n const payload = Buffer.concat([Buffer.from(String(timestamp)), toBuffer(body)]);\n return {\n \"X-Signature-Ed25519\": signData(null, payload, privateKey).toString(\"hex\"),\n \"X-Signature-Timestamp\": String(timestamp),\n };\n}\n\nexport function verifyEd25519Signature(\n publicKey: KeyLike,\n body: Body,\n headers: { signature: string; timestamp: string },\n): boolean {\n if (!HEX_DIGITS.test(headers.signature)) {\n return false;\n }\n const payload = Buffer.concat([Buffer.from(headers.timestamp), toBuffer(body)]);\n try {\n return verifyData(null, payload, publicKey, Buffer.from(headers.signature, \"hex\"));\n } catch {\n return false;\n }\n}\n","import { githubSignature256 } from \"./webhook-signing.js\";\n\nconst TRAILING_COLON = /:$/;\nconst URL_SCHEME = /^[a-z][a-z0-9+.-]*:/i;\n\nexport interface WebhookSubscription {\n id: number;\n url: string;\n events: string[];\n active: boolean;\n secret?: string;\n owner: string;\n repo?: string;\n}\n\nexport interface WebhookDelivery {\n id: number;\n hook_id: number;\n event: string;\n action?: string;\n payload: unknown;\n status_code: number | null;\n delivered_at: string;\n duration: number | null;\n success: boolean;\n redelivery_of?: number;\n redelivery_count?: number;\n /** 1 for the first try. Later tries carry `retry_of`, the first try's delivery id. */\n attempt?: number;\n retry_of?: number;\n}\n\n/**\n * Automatic retries for failed deliveries (network errors, 429, and 5xx).\n * Retries run in the background with exponential backoff, so a slow receiver\n * never delays the API response. Off unless set.\n */\nexport interface WebhookRetryPolicy {\n /** Total tries including the first, e.g. 3. */\n attempts: number;\n /** Delay before the first retry. Doubles each time. Default 1000. */\n backoffMs?: number;\n /** Cap for one delay. Default 60000. */\n maxBackoffMs?: number;\n}\n\nexport interface WebhookHeaderContext {\n event: string;\n action?: string;\n body: string;\n subscription: Readonly<WebhookSubscription>;\n deliveryId: number;\n}\n\n/**\n * Subscriptions and ID counters, the part of a dispatcher that saved state\n * keeps. Delivery history and scheduled retries are not saved.\n */\nexport interface WebhookDispatcherSnapshot {\n subscriptions: WebhookSubscription[];\n nextSubscriptionId: number;\n nextDeliveryId: number;\n}\n\nexport type WebhookHeaderFactory = (context: WebhookHeaderContext) => Record<string, string>;\n\n/** One delivery handed to a transport instead of an HTTP POST. */\nexport interface WebhookTransportDelivery {\n subscription: WebhookSubscription;\n event: string;\n payload: unknown;\n body: string;\n /** The headers an HTTP delivery would send, including redelivery headers such as `X-Slack-Retry-Num`. */\n headers: Record<string, string>;\n deliveryId: number;\n /** 1 for the first try of an automatic retry sequence. */\n attempt: number;\n /** Set when this is a manual redelivery. */\n redeliveryCount?: number;\n}\n\n/**\n * Delivers to subscriptions whose URL uses a custom scheme (e.g. Slack Socket\n * Mode's `slack-socket-mode://A123`). The result fills the delivery record the\n * same way an HTTP response would; `status_code: null` counts as a network error.\n */\nexport type WebhookTransport = (\n delivery: WebhookTransportDelivery,\n) => Promise<{ status_code: number | null; success: boolean }>;\n\nconst MAX_DELIVERIES = 1000;\n\nfunction githubHeaders({ event, body, subscription, deliveryId }: WebhookHeaderContext): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-GitHub-Event\": event,\n \"X-GitHub-Delivery\": String(deliveryId),\n };\n\n if (subscription.secret) {\n headers[\"X-Hub-Signature-256\"] = githubSignature256(subscription.secret, body);\n }\n\n return headers;\n}\n\nexport class WebhookDispatcher {\n private readonly options: { signal?: AbortSignal; neutral?: boolean; retry?: WebhookRetryPolicy };\n\n constructor(options: { signal?: AbortSignal; neutral?: boolean; retry?: WebhookRetryPolicy } = {}) {\n this.options = options;\n if (options.neutral) {\n this.headerFactory = () => ({ \"Content-Type\": \"application/json\" });\n }\n this.setRetryPolicy(options.retry);\n }\n private retryPolicy: WebhookRetryPolicy | undefined;\n private readonly pendingRetries = new Map<ReturnType<typeof setTimeout>, () => void>();\n private subscriptions: WebhookSubscription[] = [];\n private readonly deliveries: WebhookDelivery[] = [];\n private subscriptionIdCounter = 1;\n private deliveryIdCounter = 1;\n private headerFactory: WebhookHeaderFactory = githubHeaders;\n\n /**\n * Deliver to subscriptions whose URL starts with `<scheme>:` through\n * `transport` instead of HTTP. Delivery records, retries, and redelivery work\n * the same way.\n */\n setTransport(scheme: string, transport: WebhookTransport): void {\n this.transports.set(`${scheme.replace(TRAILING_COLON, \"\")}:`, transport);\n }\n private readonly transports = new Map<string, WebhookTransport>();\n\n setHeaderFactory(factory: WebhookHeaderFactory): void {\n this.headerFactory = factory;\n }\n\n setRetryPolicy(policy: WebhookRetryPolicy | undefined): void {\n if (policy && (!Number.isInteger(policy.attempts) || policy.attempts < 1)) {\n throw new Error(\"Webhook retry attempts must be a positive integer\");\n }\n this.retryPolicy = policy;\n }\n\n /** Resolves once no retries are scheduled. For tests. */\n async settled(): Promise<void> {\n while (this.pendingRetries.size > 0 || this.inFlight.size > 0) {\n await Promise.allSettled([...this.inFlight]);\n if (this.pendingRetries.size > 0) {\n await new Promise((resolve) => setTimeout(resolve, 5));\n }\n }\n }\n private readonly inFlight = new Set<Promise<unknown>>();\n\n register(sub: Omit<WebhookSubscription, \"id\"> & { id?: number }): WebhookSubscription {\n const { id: explicitId, ...rest } = sub;\n let id: number;\n if (explicitId === undefined) {\n id = this.subscriptionIdCounter;\n this.subscriptionIdCounter += 1;\n } else {\n id = explicitId;\n }\n if (id >= this.subscriptionIdCounter) {\n this.subscriptionIdCounter = id + 1;\n }\n const subscription: WebhookSubscription = { ...rest, id };\n this.subscriptions.push(subscription);\n return subscription;\n }\n\n unregister(id: number): boolean {\n const idx = this.subscriptions.findIndex((s) => s.id === id);\n if (idx === -1) {\n return false;\n }\n this.subscriptions.splice(idx, 1);\n return true;\n }\n\n getSubscription(id: number): WebhookSubscription | undefined {\n return this.subscriptions.find((s) => s.id === id);\n }\n\n getSubscriptions(owner?: string, repo?: string): WebhookSubscription[] {\n return this.subscriptions.filter((s) => {\n if (owner && s.owner !== owner) {\n return false;\n }\n if (repo !== undefined && s.repo !== repo) {\n return false;\n }\n return true;\n });\n }\n\n updateSubscription(\n id: number,\n data: Partial<Pick<WebhookSubscription, \"url\" | \"events\" | \"active\" | \"secret\">>,\n ): WebhookSubscription | undefined {\n const sub = this.subscriptions.find((s) => s.id === id);\n if (!sub) {\n return undefined;\n }\n Object.assign(sub, data);\n return sub;\n }\n\n async dispatch(\n event: string,\n action: string | undefined,\n payload: unknown,\n owner: string,\n repo?: string,\n ): Promise<void> {\n const matchingSubs = this.subscriptions.filter((s) => {\n if (!s.active) {\n return false;\n }\n if (s.owner !== owner) {\n return false;\n }\n if (repo !== undefined) {\n if (s.repo !== repo) {\n return false;\n }\n } else if (s.repo !== undefined) {\n return false;\n }\n return event === \"ping\" || s.events.includes(\"*\") || s.events.includes(event);\n });\n\n for (const sub of matchingSubs) {\n const first = await this.deliver(sub, event, action, payload);\n if (this.retryPolicy && !first.success && retryable(first)) {\n this.scheduleRetry(sub, first, 2);\n }\n }\n }\n\n private scheduleRetry(sub: WebhookSubscription, first: WebhookDelivery, attempt: number): void {\n const policy = this.retryPolicy;\n if (!policy || attempt > policy.attempts || this.options.signal?.aborted) {\n return;\n }\n const delay = Math.min((policy.backoffMs ?? 1000) * 2 ** (attempt - 2), policy.maxBackoffMs ?? 60_000);\n const timer = setTimeout(() => {\n this.pendingRetries.delete(timer);\n // The subscription may have been removed or disabled meanwhile.\n if (!(this.subscriptions.includes(sub) && sub.active)) {\n return;\n }\n const run = this.deliver(sub, first.event, first.action, first.payload, { attempt, retry_of: first.id }).then(\n (delivery) => {\n if (!delivery.success && retryable(delivery)) {\n this.scheduleRetry(sub, first, attempt + 1);\n }\n },\n );\n this.inFlight.add(run);\n run.finally(() => this.inFlight.delete(run));\n }, delay);\n timer.unref?.();\n this.pendingRetries.set(timer, () => clearTimeout(timer));\n }\n\n async redeliver(\n deliveryId: number,\n options: { headers?: Record<string, string> } = {},\n ): Promise<WebhookDelivery | undefined> {\n const original = this.deliveries.find((delivery) => delivery.id === deliveryId);\n if (!original) {\n return undefined;\n }\n const sub = this.getSubscription(original.hook_id);\n if (!sub?.active) {\n return undefined;\n }\n return this.deliver(sub, original.event, original.action, original.payload, {\n headers: options.headers,\n redelivery_of: original.id,\n redelivery_count: (original.redelivery_count ?? 0) + 1,\n });\n }\n\n private async deliver(\n sub: WebhookSubscription,\n event: string,\n action: string | undefined,\n payload: unknown,\n options: {\n headers?: Record<string, string>;\n redelivery_of?: number;\n redelivery_count?: number;\n attempt?: number;\n retry_of?: number;\n } = {},\n ): Promise<WebhookDelivery> {\n const body = JSON.stringify(payload);\n const id = this.deliveryIdCounter;\n this.deliveryIdCounter += 1;\n const delivery: WebhookDelivery = {\n id,\n hook_id: sub.id,\n event,\n action,\n payload: body === undefined ? undefined : JSON.parse(body),\n status_code: null,\n delivered_at: new Date().toISOString(),\n duration: null,\n success: false,\n ...(options.redelivery_of === undefined\n ? {}\n : { redelivery_of: options.redelivery_of, redelivery_count: options.redelivery_count }),\n ...(options.attempt === undefined ? {} : { attempt: options.attempt, retry_of: options.retry_of }),\n };\n\n // Reserve the attempt before sending so concurrent retries can see it.\n this.deliveries.push(delivery);\n if (this.deliveries.length > MAX_DELIVERIES) {\n this.deliveries.splice(0, this.deliveries.length - MAX_DELIVERIES);\n }\n\n try {\n const headers = {\n ...this.headerFactory({ event, action, body, subscription: sub, deliveryId: delivery.id }),\n ...options.headers,\n };\n const start = Date.now();\n const transport = this.transports.get(URL_SCHEME.exec(sub.url)?.[0].toLowerCase() ?? \"\");\n if (transport) {\n const result = await transport({\n subscription: sub,\n event,\n payload: delivery.payload,\n body,\n headers,\n deliveryId: delivery.id,\n attempt: options.attempt ?? 1,\n redeliveryCount: options.redelivery_count,\n });\n delivery.duration = Date.now() - start;\n delivery.status_code = result.status_code;\n delivery.success = result.success;\n return delivery;\n }\n const response = await fetch(sub.url, {\n method: \"POST\",\n headers,\n body,\n signal: this.options.signal\n ? AbortSignal.any([this.options.signal, AbortSignal.timeout(10_000)])\n : AbortSignal.timeout(10_000),\n });\n delivery.duration = Date.now() - start;\n delivery.status_code = response.status;\n delivery.success = response.ok;\n } catch {\n delivery.duration = 0;\n delivery.success = false;\n }\n return delivery;\n }\n\n snapshot(): WebhookDispatcherSnapshot {\n return {\n subscriptions: this.subscriptions.map((sub) => ({ ...sub, events: [...sub.events] })),\n nextSubscriptionId: this.subscriptionIdCounter,\n nextDeliveryId: this.deliveryIdCounter,\n };\n }\n\n /**\n * Replace subscriptions and counters with saved ones. Delivery history and\n * scheduled retries are dropped, as after a restart. The header factory and\n * retry policy stay as configured.\n */\n restore(snapshot: WebhookDispatcherSnapshot): void {\n this.clear();\n this.subscriptions = snapshot.subscriptions.map((sub) => ({ ...sub, events: [...sub.events] }));\n const highest = this.subscriptions.reduce((max, sub) => Math.max(max, sub.id), 0);\n this.subscriptionIdCounter = Math.max(snapshot.nextSubscriptionId, highest + 1);\n this.deliveryIdCounter = Math.max(snapshot.nextDeliveryId, 1);\n }\n\n getDeliveries(hookId?: number): WebhookDelivery[] {\n if (hookId !== undefined) {\n return this.deliveries.filter((d) => d.hook_id === hookId);\n }\n return [...this.deliveries];\n }\n\n clear(): void {\n for (const cancel of this.pendingRetries.values()) {\n cancel();\n }\n this.pendingRetries.clear();\n this.subscriptions.length = 0;\n this.deliveries.length = 0;\n this.subscriptionIdCounter = 1;\n this.deliveryIdCounter = 1;\n }\n}\n\nfunction retryable(delivery: WebhookDelivery): boolean {\n return delivery.status_code === null || delivery.status_code === 429 || delivery.status_code >= 500;\n}\n","import { createCustomInspector, type InspectorOptions } from \"./custom-inspector.js\";\nimport { type CorsOptions, cors, Hono } from \"./http.js\";\nimport type { PersistenceAdapter } from \"./persistence.js\";\nimport { WebhookDispatcher } from \"./webhooks.js\";\n\nconst CUSTOM_NAME = /^[a-z][a-z0-9-]*$/;\nconst TRAILING_SLASH = /\\/$/;\n\nexport interface EmulatorContext<State extends object> {\n app: Hono;\n state: State;\n baseUrl: string;\n signal: AbortSignal;\n webhooks: WebhookDispatcher;\n onDispose(callback: () => void | Promise<void>): void;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: public default type argument; an unparameterized type must keep accepting any state shape\nexport interface EmulatorDefinition<State extends object = any> {\n readonly kind: \"baseline.http\";\n readonly apiVersion: 1;\n readonly name: string;\n readonly stateVersion?: number;\n readonly state: () => State;\n readonly setup: (context: EmulatorContext<State>) => void;\n readonly validateSeed?: (value: unknown) => State;\n readonly cors?: false | CorsOptions;\n}\n\nexport function defineEmulator<State extends object>(definition: {\n name: string;\n stateVersion?: number;\n state: () => State;\n setup: (context: EmulatorContext<NoInfer<State>>) => void;\n validateSeed?: (value: unknown) => NoInfer<State>;\n cors?: false | CorsOptions;\n}): EmulatorDefinition<State> {\n const result = { ...definition, kind: \"baseline.http\" as const, apiVersion: 1 as const };\n assertEmulatorDefinition(result);\n return Object.freeze(result);\n}\n\nexport function isEmulatorDefinition(value: unknown): value is EmulatorDefinition {\n return !!value && typeof value === \"object\" && \"kind\" in value && value.kind === \"baseline.http\";\n}\n\nexport function assertEmulatorDefinition(value: unknown): asserts value is EmulatorDefinition {\n if (!isEmulatorDefinition(value)) {\n throw new Error(\"Expected a default export created with defineEmulator()\");\n }\n if (value.apiVersion !== 1) {\n throw new Error(`Unsupported emulator API version ${value.apiVersion}. Update baseline to match this plugin.`);\n }\n if (typeof value.name !== \"string\" || !CUSTOM_NAME.test(value.name)) {\n throw new Error(\n \"Emulator name must start with a lowercase letter and contain only lowercase letters, digits, and hyphens\",\n );\n }\n if (typeof value.state !== \"function\" || typeof value.setup !== \"function\") {\n throw new Error(`Emulator ${value.name} must provide state() and setup()`);\n }\n if (value.validateSeed !== undefined && typeof value.validateSeed !== \"function\") {\n throw new Error(\"validateSeed must be a function\");\n }\n if (\n value.cors !== undefined &&\n value.cors !== false &&\n (!value.cors || typeof value.cors !== \"object\" || Array.isArray(value.cors))\n ) {\n throw new Error(\"cors must be false or a CORS options object\");\n }\n if (value.stateVersion !== undefined && (!Number.isSafeInteger(value.stateVersion) || value.stateVersion < 1)) {\n throw new Error(\"stateVersion must be a positive integer\");\n }\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: public default type argument; an unparameterized type must keep accepting any state shape\nexport interface EmulatorSnapshot<State extends object = any> {\n formatVersion: 1;\n definition: string;\n stateVersion: number;\n state: State;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: public default type argument; an unparameterized type must keep accepting any state shape\nexport interface CustomRuntimeOptions<State extends object = any> {\n seed?: State;\n baseUrl?: string;\n inspector?: boolean | InspectorOptions;\n persistence?: PersistenceAdapter;\n resetPersistence?: boolean;\n shutdownTimeout?: number;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: public default type argument; an unparameterized type must keep accepting any state shape\nexport interface CustomRuntime<State extends object = any> {\n readonly baseUrl: string;\n readonly inspectorUrl?: string;\n fetch(request: Request): Promise<Response>;\n request(path: string, init?: RequestInit): Promise<Response>;\n snapshot(): EmulatorSnapshot<State>;\n reset(): Promise<void>;\n restore(snapshot: EmulatorSnapshot<State>): Promise<void>;\n close(): Promise<void>;\n}\n\nexport function cloneState<T>(value: T): T {\n const ancestors = new Set<object>();\n function check(item: unknown, path: string): void {\n if (item === null || typeof item === \"string\" || typeof item === \"boolean\") {\n return;\n }\n if (typeof item === \"number\" && Number.isFinite(item)) {\n return;\n }\n if (!item || typeof item !== \"object\") {\n throw new Error(`State at ${path} must be JSON-compatible`);\n }\n if (ancestors.has(item)) {\n throw new Error(`Circular state at ${path}`);\n }\n const proto = Object.getPrototypeOf(item);\n if (!Array.isArray(item) && proto !== Object.prototype && proto !== null) {\n throw new Error(`State at ${path} must be a plain object or array`);\n }\n ancestors.add(item);\n for (const key of Reflect.ownKeys(item)) {\n if (Array.isArray(item) && key === \"length\") {\n continue;\n }\n if (typeof key !== \"string\") {\n throw new Error(`Symbol state key at ${path}`);\n }\n const descriptor = Object.getOwnPropertyDescriptor(item, key)!;\n if (!(descriptor.enumerable && \"value\" in descriptor)) {\n throw new Error(`State at ${path}.${key} must be an enumerable data property`);\n }\n check(descriptor.value, `${path}.${key}`);\n }\n if (Array.isArray(item)) {\n for (let i = 0; i < item.length; i += 1) {\n if (!(i in item)) {\n throw new Error(`Sparse state array at ${path}[${i}]`);\n }\n }\n if (Object.keys(item).length !== item.length) {\n throw new Error(`Extra array properties at ${path}`);\n }\n }\n ancestors.delete(item);\n }\n check(value, \"state\");\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nasync function bounded<T>(promise: Promise<T>, milliseconds: number, description: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`${description} exceeded ${milliseconds}ms`)), milliseconds);\n }),\n ]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function createCustomRuntime<State extends object>(\n definition: EmulatorDefinition<State>,\n options: CustomRuntimeOptions<State> = {},\n): Promise<CustomRuntime<State>> {\n assertEmulatorDefinition(definition);\n const baseUrl = (options.baseUrl ?? `http://${definition.name}.localhost`).replace(TRAILING_SLASH, \"\");\n const timeout = options.shutdownTimeout ?? 5000;\n if (!Number.isFinite(timeout) || timeout < 1) {\n throw new Error(\"shutdownTimeout must be a positive number\");\n }\n if (\n options.inspector !== undefined &&\n typeof options.inspector !== \"boolean\" &&\n (!options.inspector || typeof options.inspector !== \"object\" || Array.isArray(options.inspector))\n ) {\n throw new Error(\"inspector must be a boolean or an inspector options object\");\n }\n function validate(value: unknown): State {\n const state = cloneState(definition.validateSeed ? definition.validateSeed(cloneState(value)) : value);\n if (!state || typeof state !== \"object\" || Array.isArray(state)) {\n throw new Error(\"Initial state must be a JSON-compatible object\");\n }\n return state as State;\n }\n const baseline = validate(options.seed === undefined ? definition.state() : options.seed);\n function readSnapshot(value: unknown): State {\n const snap = value as EmulatorSnapshot<State> | undefined;\n if (\n snap?.formatVersion !== 1 ||\n snap.definition !== definition.name ||\n snap.stateVersion !== (definition.stateVersion ?? 1)\n ) {\n throw new Error(\n `Incompatible snapshot for ${definition.name}. Supply a matching stateVersion or migrate the saved snapshot.`,\n );\n }\n return validate(snap.state);\n }\n const inspector = options.inspector\n ? createCustomInspector(definition.name, baseUrl, typeof options.inspector === \"object\" ? options.inspector : {})\n : undefined;\n interface Generation {\n app: Hono;\n state: State;\n controller: AbortController;\n disposers: Array<() => void | Promise<void>>;\n active: Set<Promise<unknown>>;\n webhooks: WebhookDispatcher;\n disposed?: Promise<void>;\n }\n function dispose(gen: Generation): Promise<void> {\n gen.disposed ??= disposeGeneration(gen);\n return gen.disposed;\n }\n async function disposeGeneration(gen: Generation): Promise<void> {\n gen.controller.abort();\n const errors: unknown[] = [];\n try {\n await bounded(\n (async () => {\n while (gen.active.size) {\n await Promise.allSettled([...gen.active]);\n }\n })(),\n timeout,\n \"Requests draining\",\n );\n } catch (error) {\n errors.push(error);\n }\n for (const callback of [...gen.disposers].reverse()) {\n try {\n await bounded(Promise.resolve().then(callback), timeout, \"Emulator cleanup\");\n } catch (error) {\n errors.push(error);\n }\n }\n gen.webhooks.clear();\n if (errors.length) {\n throw new AggregateError(errors, `Cleanup failed for ${definition.name}`);\n }\n }\n async function makeGeneration(state: State): Promise<Generation> {\n const controller = new AbortController();\n const gen: Generation = {\n app: new Hono({\n strictRoutes: true,\n strictJson: true,\n onError(error, req) {\n inspector?.recordError(req, error);\n if (!(error && typeof error === \"object\" && \"status\" in error && Number(error.status) < 500)) {\n console.error(`[${definition.name}]`, error);\n }\n },\n }),\n state: cloneState(state),\n controller,\n disposers: [],\n active: new Set(),\n webhooks: new WebhookDispatcher({ signal: controller.signal, neutral: true }),\n };\n gen.app.onError((error, c) => {\n const status = error && typeof error === \"object\" && \"status\" in error ? Number(error.status) : 500;\n return c.json(\n { error: error instanceof Error ? error.message : \"Internal Server Error\" },\n Number.isInteger(status) && status >= 400 && status <= 599 ? status : 500,\n );\n });\n gen.app.notFound((c) => c.json({ error: \"Not Found\" }, 404));\n if (definition.cors !== false) {\n gen.app.use(cors(definition.cors));\n }\n try {\n const result: unknown = definition.setup({\n app: gen.app,\n state: gen.state,\n baseUrl,\n signal: controller.signal,\n webhooks: gen.webhooks,\n onDispose: (fn) => gen.disposers.push(fn),\n });\n if (result && typeof (result as Promise<unknown>).then === \"function\") {\n Promise.resolve(result).catch(() => {\n // Best effort: the failure is ignored.\n });\n throw new Error(\"setup() must be synchronous; register asynchronous cleanup with onDispose()\");\n }\n if (gen.app.upgradeTable.length > 0) {\n throw new Error(\n `${definition.name}: custom emulators cannot serve WebSocket endpoints yet (app.upgrade ${gen.app.upgradeTable[0]}). Built-in services can; see https://docs.deploybaseline.com/websockets`,\n );\n }\n cloneState(gen.state);\n return gen;\n } catch (error) {\n await dispose(gen).catch((cleanup) => console.error(cleanup));\n throw error;\n }\n }\n let initial = baseline;\n if (options.persistence && !options.resetPersistence) {\n const raw = await options.persistence.load();\n if (raw !== null) {\n try {\n initial = readSnapshot(JSON.parse(raw));\n } catch (error) {\n throw new Error(`Cannot restore ${definition.name}: ${error instanceof Error ? error.message : error}`, {\n cause: error,\n });\n }\n }\n }\n let generation = await makeGeneration(initial);\n let closed = false;\n let transition: Promise<void> = Promise.resolve();\n let saving: Promise<void> = Promise.resolve();\n let saveRevision = 0;\n let closing: Promise<void> | undefined;\n const snapshot = (): EmulatorSnapshot<State> => ({\n formatVersion: 1,\n definition: definition.name,\n stateVersion: definition.stateVersion ?? 1,\n state: cloneState(generation.state),\n });\n function save(serialized?: string): Promise<void> {\n if (!options.persistence) {\n return Promise.resolve();\n }\n const data = serialized ?? JSON.stringify(snapshot());\n saveRevision += 1;\n saving = saving\n .catch(() => {\n // Best effort: the failure is ignored.\n })\n .then(() => options.persistence!.save(data));\n return saving;\n }\n function trackBody(gen: Generation, response: Response, savedSnapshot?: string, savedRevision?: number): Response {\n if (!response.body) {\n return response;\n }\n const reader = response.body.getReader();\n let resolveDone!: () => void;\n const done = new Promise<void>((resolve) => {\n resolveDone = resolve;\n });\n gen.active.add(done);\n done.then(() => gen.active.delete(done));\n let settled = false;\n let stopped = false;\n let abort: () => void;\n async function finish(persist: boolean): Promise<void> {\n if (settled) {\n return;\n }\n settled = true;\n gen.controller.signal.removeEventListener(\"abort\", abort);\n try {\n if (persist && savedSnapshot !== undefined && gen === generation && !gen.controller.signal.aborted) {\n const current = JSON.stringify(snapshot());\n if (current !== savedSnapshot || saveRevision !== savedRevision) {\n await save(current);\n }\n }\n } catch (error) {\n console.error(`[${definition.name}] persistence failed`, error);\n throw new Error(\"Could not persist emulator state\", { cause: error });\n } finally {\n resolveDone();\n }\n }\n const body = new ReadableStream<Uint8Array>({\n start(controller) {\n abort = () => {\n if (stopped) {\n return;\n }\n stopped = true;\n controller.error(gen.controller.signal.reason);\n reader\n .cancel(gen.controller.signal.reason)\n .catch(() => {\n // Best effort: the failure is ignored.\n })\n .finally(() => {\n finish(false);\n });\n };\n gen.controller.signal.addEventListener(\"abort\", abort, { once: true });\n if (gen.controller.signal.aborted) {\n abort();\n }\n },\n async pull(controller) {\n try {\n const chunk = await reader.read();\n if (stopped) {\n return;\n }\n if (chunk.done) {\n await finish(true);\n controller.close();\n } else {\n controller.enqueue(chunk.value);\n }\n } catch (error) {\n if (stopped) {\n return;\n }\n await finish(true).catch(() => {\n // Best effort: the failure is ignored.\n });\n controller.error(error);\n }\n },\n async cancel(reason) {\n stopped = true;\n try {\n await reader.cancel(reason);\n } finally {\n await finish(true);\n }\n },\n });\n return new Response(body, { status: response.status, statusText: response.statusText, headers: response.headers });\n }\n function replace(state: State): Promise<void> {\n if (closed) {\n return Promise.reject(new Error(\"Emulator is closed\"));\n }\n const pending = transition\n .catch(() => {\n // Best effort: the failure is ignored.\n })\n .then(async () => {\n const next = await makeGeneration(state);\n const old = generation;\n let cleanupError: unknown;\n try {\n await dispose(old);\n } catch (error) {\n cleanupError = error;\n }\n generation = next;\n inspector?.clear();\n await save();\n if (cleanupError) {\n throw cleanupError;\n }\n });\n transition = pending.catch(() => {\n // Best effort: the failure is ignored.\n });\n return pending;\n }\n const runtime: CustomRuntime<State> = {\n baseUrl,\n inspectorUrl: inspector ? `${baseUrl}/_baseline` : undefined,\n snapshot,\n reset: () => replace(baseline),\n restore(value) {\n try {\n return replace(readSnapshot(value));\n } catch (error) {\n return Promise.reject(error);\n }\n },\n async fetch(request) {\n if (closed) {\n return Response.json({ error: \"Emulator is closed\" }, { status: 503 });\n }\n // Wait for the most recent transition, including ones queued while waiting.\n let observed: Promise<void>;\n do {\n observed = transition;\n await observed;\n } while (observed !== transition);\n if (closed) {\n return Response.json({ error: \"Emulator is closed\" }, { status: 503 });\n }\n const { pathname } = new URL(request.url);\n if (pathname === \"/_baseline\" || pathname.startsWith(\"/_baseline/\")) {\n return inspector\n ? inspector.handle(request, { snapshot, reset: runtime.reset, routes: () => generation.app.routeTable })\n : Response.json({ error: \"Not Found\" }, { status: 404 });\n }\n const gen = generation;\n const task = (async () => {\n const req = new Request(request, { signal: AbortSignal.any([request.signal, gen.controller.signal]) });\n const started = inspector?.begin(req, gen.app.matchedRoute(req.method, pathname));\n let response = await gen.app.fetch(req);\n let savedSnapshot: string | undefined;\n let savedRevision: number | undefined;\n if (gen === generation && !gen.controller.signal.aborted) {\n try {\n savedSnapshot = options.persistence ? JSON.stringify(snapshot()) : undefined;\n const pendingSave = save(savedSnapshot);\n savedRevision = saveRevision;\n await pendingSave;\n } catch (error) {\n console.error(`[${definition.name}] persistence failed`, error);\n response.body?.cancel().catch(() => {\n // Best effort: the failure is ignored.\n });\n savedSnapshot = undefined;\n savedRevision = undefined;\n response = Response.json({ error: \"Could not persist emulator state\" }, { status: 500 });\n }\n }\n response = trackBody(gen, response, savedSnapshot, savedRevision);\n if (request.method === \"HEAD\") {\n // Cancellation is best effort; a streaming body can reject or never settle.\n response.body?.cancel().catch(() => {\n // Best effort: the failure is ignored.\n });\n response = new Response(null, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n }\n if (gen === generation && !gen.controller.signal.aborted) {\n await inspector?.finish(req, response, started);\n }\n return response;\n })();\n gen.active.add(task);\n try {\n return await task;\n } finally {\n gen.active.delete(task);\n }\n },\n request(path, init) {\n return runtime.fetch(new Request(new URL(path, `${baseUrl}/`), init));\n },\n close() {\n if (closing) {\n return closing;\n }\n closed = true;\n closing = (async () => {\n await transition.catch(() => {\n // Best effort: the failure is ignored.\n });\n const errors: unknown[] = [];\n try {\n await dispose(generation);\n } catch (error) {\n errors.push(error);\n }\n try {\n await bounded(save(), timeout, \"Persistence flush\");\n } catch (error) {\n errors.push(error);\n }\n if (errors.length) {\n throw new AggregateError(errors, `Could not close ${definition.name}`);\n }\n })();\n return closing;\n },\n };\n if (options.persistence) {\n try {\n await save();\n } catch (error) {\n await runtime.close().catch(() => {\n // Best effort: the failure is ignored.\n });\n throw error;\n }\n }\n return runtime;\n}\n","/**\n * One fault rule. `match` is `\"*\"`, a path, or `\"METHOD /path\"`. Paths may use\n * `*` (any characters) and `:param` (one segment), e.g. `\"POST /v1/payment_intents\"`\n * or `\"GET /repos/:owner/:repo\"`.\n */\nexport interface FaultRule {\n match: string;\n /** Chance from 0 to 1 that the rule fires on a matching request. Default 1. */\n rate?: number;\n /** Delay before the request is handled. */\n latency_ms?: number;\n /** Respond with this instead of calling the emulator. */\n response?: { status: number; body?: unknown; headers?: Record<string, string> };\n}\n\nexport type FaultProfile = \"degraded\" | \"throttled\";\n\n/** Per-service fault config: a list of rules, or an object with a seed, a profile, and rules. */\nexport type FaultConfig = FaultRule[] | { seed?: number; profile?: FaultProfile; rules?: FaultRule[] };\n\nexport const FAULT_PROFILES: Record<FaultProfile, FaultRule[]> = {\n degraded: [\n { match: \"*\", latency_ms: 300 },\n { match: \"*\", rate: 0.1, response: { status: 503, body: { error: \"Service Unavailable (injected fault)\" } } },\n ],\n throttled: [\n {\n match: \"*\",\n rate: 0.3,\n response: { status: 429, headers: { \"Retry-After\": \"1\" }, body: { error: \"Too Many Requests (injected fault)\" } },\n },\n ],\n};\n\nexport interface ActiveFaults {\n seed?: number;\n profile?: FaultProfile;\n rules: FaultRule[];\n}\n\n/** Validate and expand a fault config. Throws with a readable message. */\nexport function normalizeFaults(service: string, config: unknown): ActiveFaults {\n const raw = Array.isArray(config) ? { rules: config } : config;\n if (!raw || typeof raw !== \"object\") {\n throw new Error(`${service}.faults must be a list of rules or an object`);\n }\n const { seed, profile, rules = [] } = raw as { seed?: unknown; profile?: unknown; rules?: unknown };\n if (seed !== undefined && !Number.isInteger(seed)) {\n throw new Error(`${service}.faults.seed must be an integer`);\n }\n if (profile !== undefined && !Object.hasOwn(FAULT_PROFILES, profile as string)) {\n throw new Error(`${service}.faults.profile must be one of ${Object.keys(FAULT_PROFILES).join(\", \")}`);\n }\n if (!Array.isArray(rules)) {\n throw new Error(`${service}.faults.rules must be a list`);\n }\n for (const [index, rule] of rules.entries()) {\n validateRule(`${service}.faults.rules[${index}]`, rule);\n }\n return {\n ...(seed === undefined ? {} : { seed: seed as number }),\n ...(profile === undefined ? {} : { profile: profile as FaultProfile }),\n rules: [...(profile ? FAULT_PROFILES[profile as FaultProfile] : []), ...(rules as FaultRule[])],\n };\n}\n\nfunction validateRule(where: string, rule: unknown): asserts rule is FaultRule {\n if (!rule || typeof rule !== \"object\") {\n throw new Error(`${where} must be an object`);\n }\n const { match, rate, latency_ms, response } = rule as Record<string, unknown>;\n if (typeof match !== \"string\" || !match) {\n throw new Error(`${where}.match must be \"*\" or \"METHOD /path\"`);\n }\n if (rate !== undefined && (typeof rate !== \"number\" || rate < 0 || rate > 1)) {\n throw new Error(`${where}.rate must be a number from 0 to 1`);\n }\n if (latency_ms !== undefined && (typeof latency_ms !== \"number\" || latency_ms < 0 || latency_ms > 60_000)) {\n throw new Error(`${where}.latency_ms must be from 0 to 60000`);\n }\n if (latency_ms === undefined && response === undefined) {\n throw new Error(`${where} needs latency_ms, response, or both`);\n }\n if (response !== undefined) {\n const status = (response as { status?: unknown })?.status;\n if (!Number.isInteger(status) || (status as number) < 100 || (status as number) > 599) {\n throw new Error(`${where}.response.status must be an HTTP status code`);\n }\n const { headers } = response as { headers?: unknown };\n if (headers !== undefined) {\n try {\n // biome-ignore lint/correctness/noUnusedInstantiation: constructing Headers is the validation; it throws on invalid names or values\n new Headers(headers as Record<string, string>);\n } catch (error) {\n throw new Error(`${where}.response.headers must map valid header names to strings`, { cause: error });\n }\n }\n }\n}\n\n// Several matching rules add their latency; the total is capped like one rule.\nconst MAX_DELAY_MS = 60_000;\n\nconst WHITESPACE = /\\s+/;\n\n/** Seeded PRNG (mulberry32) so a fault seed gives the same sequence every run. */\nfunction seededRandom(seed: number): () => number {\n let state = seed >>> 0;\n return () => {\n state = (state + 0x6d_2b_79_f5) >>> 0;\n let t = state;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4_294_967_296;\n };\n}\n\nfunction compileMatch(match: string): (method: string, path: string) => boolean {\n if (match === \"*\") {\n return () => true;\n }\n const [first, ...rest] = match.trim().split(WHITESPACE);\n const method = rest.length ? first.toUpperCase() : undefined;\n const pattern = rest.length ? rest.join(\" \") : first;\n const source = pattern\n .split(\"/\")\n .map((segment) =>\n segment.startsWith(\":\")\n ? \"[^/]+\"\n : segment\n .split(\"*\")\n .map((part) => part.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\"))\n .join(\".*\"),\n )\n .join(\"/\");\n const regex = new RegExp(`^${source}/?$`);\n return (requestMethod, path) => (!method || method === requestMethod) && regex.test(path);\n}\n\n/** Fault rules for one service. Lives as long as the server; rules can change at runtime. */\nexport class FaultInjector {\n readonly service: string;\n private active: ActiveFaults = { rules: [] };\n private compiled: Array<{ rule: FaultRule; test: (method: string, path: string) => boolean }> = [];\n private random: () => number = Math.random;\n\n constructor(service: string, config?: unknown) {\n this.service = service;\n if (config !== undefined) {\n this.set(config);\n }\n }\n\n set(config: unknown): ActiveFaults {\n this.active = normalizeFaults(this.service, config);\n this.compiled = this.active.rules.map((rule) => ({ rule, test: compileMatch(rule.match) }));\n this.random = this.active.seed === undefined ? Math.random : seededRandom(this.active.seed);\n return this.current();\n }\n\n clear(): void {\n this.set([]);\n }\n\n current(): ActiveFaults {\n return structuredClone(this.active);\n }\n\n /**\n * Wrap a fetch handler: delay and short-circuit matching requests. Control,\n * inspector, and font paths are exempt, so opening the inspector never\n * shifts the seeded sequence.\n */\n wrap(fetch: (request: Request) => Response | Promise<Response>) {\n return async (request: Request): Promise<Response> => {\n if (this.compiled.length === 0) {\n return fetch(request);\n }\n const path = new URL(request.url).pathname;\n if (path.startsWith(\"/_baseline\") || path.startsWith(\"/_inspector\") || path.startsWith(\"/fonts/\")) {\n return fetch(request);\n }\n let delay = 0;\n let response: FaultRule[\"response\"];\n for (const { rule, test } of this.compiled) {\n if (!test(request.method, path)) {\n continue;\n }\n if (rule.rate !== undefined && rule.rate < 1 && this.random() >= rule.rate) {\n continue;\n }\n delay += rule.latency_ms ?? 0;\n if (rule.response && !response) {\n ({ response } = rule);\n }\n }\n if (delay > 0) {\n await new Promise((resolve) => setTimeout(resolve, Math.min(delay, MAX_DELAY_MS)));\n }\n if (!response) {\n return fetch(request);\n }\n const headers = new Headers({ \"X-Baseline-Fault\": \"injected\", ...response.headers });\n if (response.body === undefined) {\n return new Response(null, { status: response.status, headers });\n }\n if (typeof response.body === \"string\") {\n return new Response(response.body, { status: response.status, headers });\n }\n headers.set(\"Content-Type\", \"application/json\");\n return new Response(JSON.stringify(response.body), { status: response.status, headers });\n };\n }\n}\n","// Shared identity fixtures: one person, declared once under `identities:` in the\n// config, seeded as a user in every provider that has users. The host validates\n// the list and sends each provider its share; the provider maps each person into\n// its own seed shape with its `IdentityMapping`.\n\n/** A person under the config's `identities:` key. */\nexport interface Identity {\n /** Full name, such as \"Ada Lovelace\". The first word becomes the given name, the rest the family name. */\n name: string;\n email: string;\n /** Login or username where a provider has one. Defaults to the part of the email before the \"@\". */\n username?: string;\n /** Avatar image URL, for providers whose users carry one. */\n avatar?: string;\n /** Per-provider fields merged over the mapped user, or `false` to leave the identity out of that provider. */\n providers?: Record<string, false | Record<string, unknown>>;\n}\n\n/** One identity as the host sends it to a provider: its override for that provider instead of all of them. */\nexport interface ProviderIdentity {\n name: string;\n email: string;\n username?: string;\n avatar?: string;\n /** Fields merged over the mapped user, or `false` to leave this person out. */\n override?: false | Record<string, unknown>;\n}\n\ntype User = Record<string, unknown>;\n\n/** How a provider turns a person into a user in its seed. */\nexport interface IdentityMapping {\n /** The seed's user list key. */\n key: string;\n /** Build the provider's user. */\n user(identity: ProviderIdentity & { username: string }): User;\n /** The field that identifies a user, used to skip identities already listed in the provider's own seed. */\n match(user: User): string | undefined;\n}\n\nconst WHITESPACE = /\\s+/;\n\n/** Given and family name from a full name: the first word, and the rest. */\nexport function splitName(name: string): { given: string; family: string | undefined } {\n const [given, ...rest] = name.trim().split(WHITESPACE);\n return { given, family: rest.join(\" \") || undefined };\n}\n\n/** A string lowercased, or undefined for anything else. For `match` functions. */\nexport const lowerCase = (value: unknown): string | undefined =>\n typeof value === \"string\" ? value.toLowerCase() : undefined;\n\n/** The identities one provider gets, in the order the config lists them. */\nexport function identitiesFor(provider: string, identities: readonly Identity[]): ProviderIdentity[] {\n return identities.map(({ providers, ...person }) => {\n const override = providers?.[provider];\n return override === undefined ? person : { ...person, override };\n });\n}\n\nconst defaultUsername = (email: string) =>\n email\n .split(\"@\")[0]\n .replace(/[^A-Za-z0-9-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\") || \"user\";\n\nconst compact = (user: User): User => Object.fromEntries(Object.entries(user).filter(([, v]) => v !== undefined));\n\n/**\n * Append identities to a provider's seed as users. Users the seed already lists come first, so the\n * provider's default token user does not change, and an identity whose email (or login) the seed\n * already lists is skipped. Returns the seed unchanged when there is no mapping or no identity.\n */\nexport function applyIdentities(\n seed: Record<string, unknown> | undefined,\n identities: readonly ProviderIdentity[],\n mapping: IdentityMapping | undefined,\n): Record<string, unknown> | undefined {\n if (!(mapping && identities.length)) {\n return seed;\n }\n const existing = seed?.[mapping.key];\n if (existing !== undefined && !Array.isArray(existing)) {\n return seed;\n }\n const users = [...((existing as User[] | undefined) ?? [])];\n const seen = new Set(users.map(mapping.match).filter((key): key is string => !!key));\n for (const identity of identities) {\n const { override, ...person } = identity;\n if (override === false) {\n continue;\n }\n const user = compact({\n ...mapping.user({ ...person, username: person.username ?? defaultUsername(person.email) }),\n ...(override ?? {}),\n });\n const key = mapping.match(user);\n if (key && seen.has(key)) {\n continue;\n }\n if (key) {\n seen.add(key);\n }\n users.push(user);\n }\n return { ...seed, [mapping.key]: users };\n}\n","import type { ContentfulStatusCode, Context, ErrorHandler, MiddlewareHandler } from \"../http.js\";\n\nconst DEFAULT_DOCS_URL = \"https://docs.deploybaseline.com\";\n\nfunction getDocsUrl(c: Context): string {\n return (c.get(\"docsUrl\") as string | undefined) ?? DEFAULT_DOCS_URL;\n}\n\nfunction errorStatus(err: unknown): number {\n if (err && typeof err === \"object\" && \"status\" in err) {\n const s = (err as { status: unknown }).status;\n if (typeof s === \"number\" && Number.isFinite(s)) {\n return s;\n }\n }\n return 500;\n}\n\n/**\n * Use with `app.onError(...)`. Route handlers throw to the app error handler.\n */\nexport function createApiErrorHandler(documentationUrl?: string): ErrorHandler {\n return (err, c) => {\n if (documentationUrl) {\n c.set(\"docsUrl\", documentationUrl);\n }\n const status = errorStatus(err);\n const message = err instanceof Error ? err.message : \"Internal Server Error\";\n const errors = err instanceof ApiError && err.errors?.length ? { errors: err.errors } : {};\n return c.json(\n {\n message,\n ...errors,\n documentation_url: getDocsUrl(c),\n },\n status as ContentfulStatusCode,\n );\n };\n}\n\n/** Sets `docsUrl` on the context for successful responses; register `createApiErrorHandler` for thrown `ApiError`s. */\nexport function createErrorHandler(documentationUrl?: string): MiddlewareHandler {\n return async (c, next) => {\n if (documentationUrl) {\n c.set(\"docsUrl\", documentationUrl);\n }\n await next();\n };\n}\n\nexport const errorHandler: MiddlewareHandler = createErrorHandler();\n\nexport class ApiError extends Error {\n status: number;\n /** Detail entries, sent as `errors`: GitHub's `{ resource, field, code }` objects, or plain messages. */\n errors?: Array<{ resource: string; field: string; code: string; message?: string } | string>;\n\n constructor(\n status: number,\n message: string,\n errors?: Array<{ resource: string; field: string; code: string; message?: string } | string>,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.status = status;\n this.errors = errors;\n this.name = \"ApiError\";\n }\n}\n\nexport function notFound(resource?: string): ApiError {\n return new ApiError(404, resource ? `${resource} not found` : \"Not Found\");\n}\n\nexport function validationError(message: string, errors?: ApiError[\"errors\"]): ApiError {\n return new ApiError(422, message, errors);\n}\n\nexport function unauthorized(): ApiError {\n return new ApiError(401, \"Requires authentication\");\n}\n\nexport function forbidden(): ApiError {\n return new ApiError(403, \"Forbidden\");\n}\n\nexport async function parseJsonBody(c: Context): Promise<Record<string, unknown>> {\n let body: unknown;\n try {\n const text = await c.req.text();\n // SDKs send no body for calls without parameters (Octokit's pulls.merge, issues.lock, repos.createFork).\n if (!text.trim()) {\n return {};\n }\n body = JSON.parse(text);\n } catch (error) {\n // biome-ignore lint/style/useErrorCause: the cause goes in ApiError's fourth (options) argument; the rule only reads the second\n throw new ApiError(400, \"Problems parsing JSON\", undefined, { cause: error });\n }\n if (body && typeof body === \"object\" && !Array.isArray(body)) {\n return body as Record<string, unknown>;\n }\n return {};\n}\n","import type { Context } from \"../http.js\";\n\nexport interface PaginationParams {\n page: number;\n per_page: number;\n}\n\nexport function parsePagination(c: Context): PaginationParams {\n const page = Math.max(1, Number.parseInt(c.req.query(\"page\") ?? \"1\", 10) || 1);\n const per_page = Math.min(100, Math.max(1, Number.parseInt(c.req.query(\"per_page\") ?? \"30\", 10) || 30));\n return { page, per_page };\n}\n\nexport function setLinkHeader(c: Context, totalCount: number, page: number, perPage: number): void {\n const lastPage = Math.max(1, Math.ceil(totalCount / perPage));\n const baseUrl = new URL(c.req.url);\n const links: string[] = [];\n\n const makeLink = (p: number, rel: string) => {\n baseUrl.searchParams.set(\"page\", String(p));\n baseUrl.searchParams.set(\"per_page\", String(perPage));\n return `<${baseUrl.toString()}>; rel=\"${rel}\"`;\n };\n\n if (page < lastPage) {\n links.push(makeLink(page + 1, \"next\"));\n links.push(makeLink(lastPage, \"last\"));\n }\n if (page > 1) {\n links.push(makeLink(1, \"first\"));\n links.push(makeLink(page - 1, \"prev\"));\n }\n\n if (links.length > 0) {\n c.header(\"Link\", links.join(\", \"));\n }\n}\n","// Serve a service below a path prefix, as the CLI's single-port mode does at\n// /<service>: requests arrive without the prefix and responses get it back.\n\nfunction prefixedLocation(location: string | null, servicePrefix: string): string | undefined {\n if (!location?.startsWith(\"/\") || location.startsWith(\"//\")) {\n return undefined;\n }\n if (\n location === servicePrefix ||\n location.startsWith(`${servicePrefix}/`) ||\n location.startsWith(`${servicePrefix}?`) ||\n location.startsWith(`${servicePrefix}#`)\n ) {\n return undefined;\n }\n return servicePrefix + location;\n}\n\n// Pagination `Link` headers carry absolute URLs built from the stripped request,\n// e.g. <http://localhost:4000/repos/o/r/issues?page=2>. Put the prefix back on\n// the ones that point at this origin.\nfunction prefixedLink(link: string | null, origin: string, servicePrefix: string): string | undefined {\n if (!link) {\n return undefined;\n }\n let changed = false;\n const rewritten = link.replace(/<([^>]*)>/g, (whole, target: string) => {\n let url: URL;\n try {\n url = new URL(target);\n } catch {\n return whole;\n }\n if (url.origin !== origin) {\n return whole;\n }\n if (url.pathname === servicePrefix || url.pathname.startsWith(`${servicePrefix}/`)) {\n return whole;\n }\n url.pathname = servicePrefix + url.pathname;\n changed = true;\n return `<${url.toString()}>`;\n });\n return changed ? rewritten : undefined;\n}\n\nasync function rewriteResponse(\n response: Response,\n servicePrefix: string,\n rewriteHtml: boolean,\n origin: string,\n): Promise<Response> {\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n const location = prefixedLocation(response.headers.get(\"Location\"), servicePrefix);\n const link = prefixedLink(response.headers.get(\"Link\"), origin, servicePrefix);\n if (!(rewriteHtml && contentType.includes(\"text/html\"))) {\n if (!(location || link)) {\n return response;\n }\n const headers = new Headers(response.headers);\n if (location) {\n headers.set(\"Location\", location);\n }\n if (link) {\n headers.set(\"Link\", link);\n }\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers });\n }\n let html = await response.text();\n html = html.replace(/(action|href)=\"(\\/[^\"]*?)\"/g, (_match, attr, path) =>\n path.startsWith(servicePrefix) ? `${attr}=\"${path}\"` : `${attr}=\"${servicePrefix}${path}\"`,\n );\n html = html.replace(/url\\('(\\/[^']*?)'\\)/g, (_match, path) =>\n path.startsWith(servicePrefix) ? `url('${path}')` : `url('${servicePrefix}${path}')`,\n );\n const headers = new Headers(response.headers);\n if (location) {\n headers.set(\"Location\", location);\n }\n if (link) {\n headers.set(\"Link\", link);\n }\n headers.delete(\"Content-Length\");\n return new Response(html, { status: response.status, statusText: response.statusText, headers });\n}\n/**\n * Serve an app under a path prefix: strip the prefix from the request and add\n * it back to redirects and pagination `Link` headers (and to links in HTML\n * pages when `rewriteHtml` is set).\n * `rest` is the path after the prefix, already split into segments.\n */\nexport function mountedFetch(\n fetch: (request: Request) => Response | Promise<Response>,\n servicePrefix: string,\n rewriteHtml: boolean,\n) {\n return async (req: Request, rest: string[]): Promise<Response> => {\n const url = new URL(req.url);\n const strippedUrl = new URL(`/${rest.join(\"/\")}${url.search}`, url.origin);\n const strippedReq = new Request(strippedUrl, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n duplex: \"half\",\n signal: req.signal,\n } as RequestInit & { duplex: string });\n return rewriteResponse(await fetch(strippedReq), servicePrefix, rewriteHtml, url.origin);\n };\n}\n","import {\n createHash,\n createPrivateKey,\n createPublicKey,\n generateKeyPair,\n type JsonWebKeyInput,\n type KeyObject,\n} from \"node:crypto\";\nimport { type JWK, type JWTPayload, SignJWT } from \"jose\";\nimport type { Store } from \"./store.js\";\n\nconst BASIC_SCHEME = /^basic /i;\n\n/**\n * Shared OIDC and JWT helpers. Signing keys live in the store as JWKs, so\n * they survive store snapshots and restores, and every instance restored\n * from the same snapshot signs with the same key.\n */\n\n/** RS256 (RSA 2048) for OIDC tokens; ES256 (P-256) for providers that sign with EC keys, such as Plaid webhooks. */\nexport type SigningAlg = \"RS256\" | \"ES256\";\n\nconst ALGS: readonly SigningAlg[] = [\"RS256\", \"ES256\"];\n\nexport interface SigningKeyOptions {\n /** Service name, used to namespace the store key (`<service>.signing_keys`). */\n service: string;\n /** Key ID for a generated key. A seeded JWK with its own `kid` keeps that `kid`. */\n kid: string;\n alg?: SigningAlg;\n}\n\n/** The JSON value kept in the store. */\nexport interface SigningKeyRecord {\n kid: string;\n alg: SigningAlg;\n private_jwk: JWK;\n public_jwk: JWK;\n}\n\n/** Seed config shape: `signing_key: { private_jwk }`. */\nexport interface SigningKeySeed {\n private_jwk: JWK;\n}\n\nexport interface SigningKey {\n kid: string;\n alg: SigningAlg;\n privateKey: KeyObject;\n /** Public JWK with `kid`, `use` and `alg`, ready for a JWKS document. */\n publicJwk: JWK;\n}\n\nexport interface JwksDocument {\n keys: JWK[];\n}\n\nexport function signingKeyStoreKey(service: string): string {\n return `${service}.signing_keys`;\n}\n\nconst inflight = new WeakMap<Store, Map<string, Promise<SigningKeyRecord>>>();\nconst privateKeys = new WeakMap<SigningKeyRecord, KeyObject>();\n\nfunction isRecord(value: unknown): value is SigningKeyRecord {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const v = value as Record<string, unknown>;\n return (\n typeof v.kid === \"string\" &&\n ALGS.includes(v.alg as SigningAlg) &&\n typeof v.private_jwk === \"object\" &&\n v.private_jwk !== null &&\n typeof v.public_jwk === \"object\" &&\n v.public_jwk !== null\n );\n}\n\nfunction importPrivateJwk(jwk: JWK): KeyObject {\n return createPrivateKey({ key: jwk as JsonWebKeyInput[\"key\"], format: \"jwk\" });\n}\n\nfunction publicJwkOf(privateKey: KeyObject): JWK {\n const jwk = createPublicKey(privateKey).export({ format: \"jwk\" }) as JWK;\n if (jwk.kty === \"EC\") {\n return { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };\n }\n return { kty: jwk.kty, n: jwk.n, e: jwk.e };\n}\n\nfunction toSigningKey(record: SigningKeyRecord): SigningKey {\n let privateKey = privateKeys.get(record);\n if (!privateKey) {\n privateKey = importPrivateJwk(record.private_jwk);\n privateKeys.set(record, privateKey);\n }\n return {\n kid: record.kid,\n alg: record.alg,\n privateKey,\n publicJwk: { ...record.public_jwk, kid: record.kid, use: \"sig\", alg: record.alg },\n };\n}\n\nasync function generateRecord(kid: string, alg: SigningAlg): Promise<SigningKeyRecord> {\n const privateKey = await new Promise<KeyObject>((resolve, reject) => {\n const done = (error: Error | null, _publicKey: KeyObject, key: KeyObject) => (error ? reject(error) : resolve(key));\n if (alg === \"ES256\") {\n generateKeyPair(\"ec\", { namedCurve: \"P-256\" }, done);\n } else {\n generateKeyPair(\"rsa\", { modulusLength: 2048 }, done);\n }\n });\n return {\n kid,\n alg,\n private_jwk: privateKey.export({ format: \"jwk\" }) as JWK,\n public_jwk: publicJwkOf(privateKey),\n };\n}\n\n/**\n * Return the service's signing key, generating and storing it on first use.\n * Concurrent first calls on one store share a single generation.\n */\nexport async function createSigningKeys(store: Store, options: SigningKeyOptions): Promise<SigningKey> {\n const storeKey = signingKeyStoreKey(options.service);\n const existing = store.getData<unknown>(storeKey);\n if (isRecord(existing)) {\n return toSigningKey(existing);\n }\n\n let pending = inflight.get(store);\n if (!pending) {\n pending = new Map();\n inflight.set(store, pending);\n }\n let generation = pending.get(storeKey);\n if (!generation) {\n const map = pending;\n generation = generateRecord(options.kid, options.alg ?? \"RS256\")\n .then((record) => {\n // A seed or restore may have stored a key while this one was generating.\n const current = store.getData<unknown>(storeKey);\n if (isRecord(current)) {\n return current;\n }\n store.setData(storeKey, record);\n return record;\n })\n .finally(() => map.delete(storeKey));\n pending.set(storeKey, generation);\n }\n return toSigningKey(await generation);\n}\n\n/**\n * Store a user supplied private JWK as the service's signing key, replacing\n * any existing one: RSA for RS256, P-256 EC for ES256. Used for the\n * `signing_key` seed option.\n */\nexport function seedSigningKey(store: Store, options: SigningKeyOptions, seed: SigningKeySeed): SigningKeyRecord {\n const jwk = seed?.private_jwk;\n const alg = options.alg ?? \"RS256\";\n const ec = alg === \"ES256\";\n if (\n !jwk ||\n typeof jwk !== \"object\" ||\n jwk.kty !== (ec ? \"EC\" : \"RSA\") ||\n (ec && jwk.crv !== \"P-256\") ||\n typeof jwk.d !== \"string\"\n ) {\n throw new Error(\n ec\n ? `${options.service}.signing_key.private_jwk must be a P-256 EC private JWK (kty \"EC\", crv \"P-256\" with \"d\")`\n : `${options.service}.signing_key.private_jwk must be an RSA private JWK (kty \"RSA\" with \"d\")`,\n );\n }\n let privateKey: KeyObject;\n try {\n privateKey = importPrivateJwk(jwk);\n } catch (error) {\n throw new Error(`${options.service}.signing_key.private_jwk is not a valid ${ec ? \"EC\" : \"RSA\"} private key`, {\n cause: error,\n });\n }\n const kid = typeof jwk.kid === \"string\" && jwk.kid ? jwk.kid : options.kid;\n const record: SigningKeyRecord = {\n kid,\n alg,\n private_jwk: privateKey.export({ format: \"jwk\" }) as JWK,\n public_jwk: publicJwkOf(privateKey),\n };\n store.setData(signingKeyStoreKey(options.service), record);\n return record;\n}\n\n/** JWKS document with the service's public signing key. Never includes private fields. */\nexport async function jwksDocument(store: Store, options: SigningKeyOptions): Promise<JwksDocument> {\n const key = await createSigningKeys(store, options);\n return { keys: [key.publicJwk] };\n}\n\nexport interface SignJwtOptions {\n /** The `iss` claim. Omit it for JWTs that carry none, such as Plaid's webhook verification tokens. */\n issuer?: string;\n audience?: string | string[];\n subject?: string;\n /** Seconds since the epoch. Defaults to now. */\n issuedAt?: number;\n notBefore?: number;\n /** A jose duration string or an absolute epoch second. Default `1h`; `null` leaves out `exp`. */\n expiresIn?: string | number | null;\n}\n\n/** Sign a JWT with the service's key. The header carries `alg`, `kid` and `typ: \"JWT\"`. */\nexport async function signJwt(\n store: Store,\n key: SigningKeyOptions,\n claims: JWTPayload,\n options: SignJwtOptions,\n): Promise<string> {\n const { kid, alg, privateKey } = await createSigningKeys(store, key);\n const builder = new SignJWT(claims).setProtectedHeader({ alg, kid, typ: \"JWT\" });\n if (options.issuer !== undefined) {\n builder.setIssuer(options.issuer);\n }\n if (options.audience !== undefined) {\n builder.setAudience(options.audience);\n }\n if (options.subject !== undefined) {\n builder.setSubject(options.subject);\n }\n builder.setIssuedAt(options.issuedAt);\n if (options.notBefore !== undefined) {\n builder.setNotBefore(options.notBefore);\n }\n if (options.expiresIn !== null) {\n builder.setExpirationTime(options.expiresIn ?? \"1h\");\n }\n return builder.sign(privateKey);\n}\n\n/** Sign an OIDC ID token. Same as {@link signJwt} with a required audience. */\nexport function issueIdToken(\n store: Store,\n key: SigningKeyOptions,\n claims: JWTPayload,\n options: SignJwtOptions & { issuer: string; audience: string | string[] },\n): Promise<string> {\n return signJwt(store, key, claims, options);\n}\n\n/** The service's pending authorization codes, kept in the store under `<service>.oauth.pendingCodes`. */\nexport function pendingCodes<T>(store: Store, service: string): Map<string, T> {\n const storeKey = `${service}.oauth.pendingCodes`;\n let map = store.getData<Map<string, T>>(storeKey);\n if (!map) {\n map = new Map();\n store.setData(storeKey, map);\n }\n return map;\n}\n\n/**\n * Check a PKCE `code_verifier` against the stored challenge. Supports `S256`\n * and `plain` (case insensitive, default `plain`); any other method fails.\n */\n/**\n * Client credentials from `Authorization: Basic` (RFC 6749 section 2.3.1:\n * form-encoded id and secret, base64 joined by a colon), or null.\n */\nexport function basicClientCredentials(\n header: string | undefined | null,\n): { clientId: string; clientSecret: string } | null {\n if (!(header && BASIC_SCHEME.test(header))) {\n return null;\n }\n const decoded = Buffer.from(header.slice(6).trim(), \"base64\").toString(\"utf8\");\n const sep = decoded.indexOf(\":\");\n if (sep === -1) {\n return null;\n }\n const formDecode = (value: string) => {\n try {\n return decodeURIComponent(value.replace(/\\+/g, \" \"));\n } catch {\n return value;\n }\n };\n return { clientId: formDecode(decoded.slice(0, sep)), clientSecret: formDecode(decoded.slice(sep + 1)) };\n}\n\nexport function verifyPkce(\n verifier: string | undefined,\n challenge: string,\n method: string | null | undefined,\n): boolean {\n if (!verifier) {\n return false;\n }\n const m = (method ?? \"plain\").toLowerCase();\n if (m === \"s256\") {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\") === challenge;\n }\n if (m === \"plain\") {\n return verifier === challenge;\n }\n return false;\n}\n","import { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * Load an opt-in package (e.g. @deploybaseline/ws) that the CLI does not bundle.\n * Looks in the user's project first, so a devDependency works even when the CLI\n * runs from the npx cache, then in `searchFrom` folders (the CLI passes its\n * own), then next to the running script (npx -p a -p b installs them side by\n * side). The error names `feature` and shows both ways to install the package.\n */\nexport async function loadOptionalPackage<T = unknown>(\n name: string,\n feature: string,\n cwd = process.cwd(),\n searchFrom: string[] = [],\n): Promise<T> {\n const script = process.argv[1] ? [dirname(realpathOrSelf(process.argv[1]))] : [];\n for (const dir of [cwd, ...searchFrom, ...script]) {\n const resolved = resolveFromProject(name, dir);\n if (resolved) {\n return (await import(pathToFileURL(resolved).href)) as T;\n }\n }\n try {\n return (await import(name)) as T;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ERR_MODULE_NOT_FOUND\") {\n throw error;\n }\n throw new Error(\n `${feature} needs ${name}, which is not installed. Either:\\n` +\n ` npx -p @deploybaseline/cli -p ${name} baseline start ...\\n` +\n \"or install both in your project and run baseline from a package.json script:\\n\" +\n ` npm install -D @deploybaseline/cli ${name}\\n` +\n ` \"scripts\": { \"emulators\": \"baseline start\" }`,\n { cause: error },\n );\n }\n}\n\n/**\n * Find `name` in the node_modules folders from `cwd` up and return its ESM\n * entry. `require.resolve` cannot do this for packages that export only an\n * `import` condition, which all opt-in Baseline packages do.\n */\nexport function resolveFromProject(name: string, cwd: string): string | undefined {\n for (let dir = resolve(cwd); ; dir = dirname(dir)) {\n const root = join(dir, \"node_modules\", name);\n const manifestPath = join(root, \"package.json\");\n if (existsSync(manifestPath)) {\n const manifest = JSON.parse(readFileSync(manifestPath, \"utf8\")) as {\n exports?: unknown;\n module?: string;\n main?: string;\n };\n const exported =\n manifest.exports &&\n typeof manifest.exports === \"object\" &&\n !Array.isArray(manifest.exports) &&\n \".\" in manifest.exports\n ? (manifest.exports as Record<string, unknown>)[\".\"]\n : manifest.exports;\n return join(root, conditionTarget(exported) ?? manifest.module ?? manifest.main ?? \"index.js\");\n }\n if (dirname(dir) === dir) {\n return undefined;\n }\n }\n}\n\nfunction conditionTarget(value: unknown): string | undefined {\n if (typeof value === \"string\") {\n return value;\n }\n if (Array.isArray(value)) {\n for (const item of value) {\n const target = conditionTarget(item);\n if (target) {\n return target;\n }\n }\n return undefined;\n }\n if (value && typeof value === \"object\") {\n for (const condition of [\"import\", \"node\", \"default\"]) {\n const target = conditionTarget((value as Record<string, unknown>)[condition]);\n if (target) {\n return target;\n }\n }\n }\n return undefined;\n}\n\nfunction realpathOrSelf(path: string): string {\n try {\n return realpathSync(path);\n } catch {\n return path;\n }\n}\n","// The provider protocol: the only contract between the host (the Baseline CLI)\n// and a provider process. research/refactor/04-provider-protocol.md is the\n// design. Every message here is one every provider must handle for as long as\n// its protocol version is supported, so keep it small.\n//\n// Adding an optional field, or a provider-to-host message the host may ignore,\n// is not a protocol change. Adding a host-to-provider message, or changing what\n// a field means, is protocol 2.\nimport type { FaultConfig } from \"./faults.js\";\nimport type { ProviderIdentity } from \"./identities.js\";\nimport type { GeneratedSecret, ServiceState } from \"./state.js\";\n\nexport const PROTOCOL_VERSION = 1;\n\n/** Protocol versions this SDK's host side can talk to. */\nexport const SUPPORTED_PROTOCOLS: readonly number[] = [1];\n\n/** Fault kinds this SDK injects: `latency_ms` and a canned `response`. */\nexport const FAULT_KINDS = [\"latency\", \"response\"] as const;\n\nexport type ProviderSecret = Omit<GeneratedSecret, \"service\">;\n\nexport type ProviderErrorCode =\n | \"port_in_use\"\n | \"seed_invalid\"\n | \"state_incompatible\"\n | \"state_invalid\"\n | \"faults_invalid\"\n | \"bad_request\"\n | \"internal\";\n\n/** An HTTP request or response carried over IPC. Bodies are base64 so any bytes survive. */\nexport interface WireRequest {\n method: string;\n url: string;\n headers: [string, string][];\n body?: string;\n}\n\nexport interface WireResponse {\n status: number;\n headers: [string, string][];\n body?: string;\n}\n\n// Provider to host.\n\nexport interface HelloMessage {\n type: \"hello\";\n protocol: number;\n /** The provider's name, as in its `baseline` field. */\n name: string;\n /** The provider package's version. */\n version: string;\n /** The SDK (`@deploybaseline/core`) version the provider was built with. */\n sdk: string;\n stateVersion: number;\n /** Fault kinds this provider injects. */\n faults: readonly string[];\n}\n\nexport interface ReadyMessage {\n type: \"ready\";\n id: number;\n /** Every generated secret this service uses: the ones it was given, plus any it generated. */\n secrets: ProviderSecret[];\n /** The service's base URL. */\n url: string;\n /** The bound port, when `start` asked the provider to listen. */\n port?: number;\n}\n\nexport interface ListeningMessage {\n type: \"listening\";\n id: number;\n port: number;\n url: string;\n}\n\nexport interface SnapshotMessage {\n type: \"snapshot\";\n id: number;\n state: ServiceState;\n}\n\nexport interface OkMessage {\n type: \"ok\";\n id: number;\n}\n\nexport interface ErrorMessage {\n type: \"error\";\n /** The request this answers. Absent for an error the provider reports on its own. */\n id?: number;\n code: ProviderErrorCode;\n message: string;\n}\n\nexport interface StoppedMessage {\n type: \"stopped\";\n id: number;\n state?: ServiceState;\n}\n\n/** A request changed the provider's state. Sent at most once per request. */\nexport interface DirtyMessage {\n type: \"dirty\";\n}\n\n/** A request to `/_baseline/{control,faults,state}` arrived on the provider's port. */\nexport interface ControlMessage {\n type: \"control\";\n id: number;\n request: WireRequest;\n}\n\nexport type ProviderMessage =\n | HelloMessage\n | ReadyMessage\n | ListeningMessage\n | SnapshotMessage\n | OkMessage\n | ErrorMessage\n | StoppedMessage\n | DirtyMessage\n | ControlMessage;\n\n// Host to provider.\n\nexport interface WelcomeMessage {\n type: \"welcome\";\n protocol: number;\n /** The host's version. */\n host: string;\n}\n\nexport interface StartMessage {\n type: \"start\";\n id: number;\n /** The service's name in this project: the provider name, or the key under `services`. */\n service: string;\n /** Port to listen on. 0 picks a free one, and needs `listen: true`. */\n port: number;\n /** Listening address. Defaults to 127.0.0.1. */\n hostname?: string;\n /** The service's own `baseUrl`. Wins over `baseUrl`. */\n serviceBaseUrl?: string;\n /** The run's base URL option, which may hold `{service}`. */\n baseUrl?: string;\n /** The provider's section of the config, without identities merged in. */\n seed?: Record<string, unknown>;\n /** Accepted bearer tokens. */\n tokens: Record<string, { login: string; id: number; scopes?: string[] }>;\n /** Shared identities for this provider, with exclusions applied and overrides attached. */\n identities: ProviderIdentity[];\n faults?: FaultConfig;\n /** Restore this saved state instead of seeding. */\n state?: ServiceState;\n /** Secrets generated in an earlier run, to reuse. */\n secrets?: ProviderSecret[];\n /** Generate secrets the seed leaves out (GitHub App keys), reusing `secrets`. */\n generateSecrets?: boolean;\n /** Listen before answering `ready`. Needed for port 0, where the base URL depends on the bound port. */\n listen?: boolean;\n}\n\nexport interface ListenMessage {\n type: \"listen\";\n id: number;\n}\n\nexport interface SnapshotRequestMessage {\n type: \"snapshot\";\n id: number;\n}\n\nexport interface RestoreMessage {\n type: \"restore\";\n id: number;\n state: ServiceState;\n}\n\n/** Reseed from the `start` seed. */\nexport interface ResetMessage {\n type: \"reset\";\n id: number;\n}\n\n/** Replace the active faults. */\nexport interface FaultsMessage {\n type: \"faults\";\n id: number;\n faults: FaultConfig;\n}\n\nexport interface StopMessage {\n type: \"stop\";\n id: number;\n /** Answer with the final state. */\n snapshot: boolean;\n}\n\nexport interface ControlResponseMessage {\n type: \"control-response\";\n id: number;\n response: WireResponse;\n}\n\nexport type HostMessage =\n | WelcomeMessage\n | StartMessage\n | ListenMessage\n | SnapshotRequestMessage\n | RestoreMessage\n | ResetMessage\n | FaultsMessage\n | StopMessage\n | ControlResponseMessage;\n\n/** One side of the protocol's message channel. */\nexport interface ProtocolChannel<Out, In> {\n send(message: Out): void;\n onMessage(listener: (message: In) => void): void;\n /** Called once when the other side goes away. */\n onDisconnect(listener: () => void): void;\n disconnect(): void;\n}\n\n/** The provider's side of Node IPC to its host. Throws when the process was not started with an IPC channel. */\nexport function processChannel(): ProtocolChannel<ProviderMessage, HostMessage> {\n if (typeof process.send !== \"function\") {\n throw new Error(\n \"This is a Baseline provider entry. It is started by the Baseline CLI, which talks to it over IPC; run `npx @deploybaseline/cli` instead.\",\n );\n }\n return {\n send: (message) => {\n if (process.connected) {\n process.send!(message, undefined, {}, () => {\n // No-op.\n });\n }\n },\n onMessage: (listener) => process.on(\"message\", (message) => listener(message as HostMessage)),\n onDisconnect: (listener) => process.once(\"disconnect\", listener),\n disconnect: () => {\n if (process.connected) {\n process.disconnect();\n }\n },\n };\n}\n\n/**\n * A connected pair of in-memory channels, for running a provider and its host\n * in one process. Messages are cloned and delivered asynchronously, as IPC does.\n */\nexport function channelPair(): {\n host: ProtocolChannel<HostMessage, ProviderMessage>;\n provider: ProtocolChannel<ProviderMessage, HostMessage>;\n} {\n const listeners = { host: [] as Array<(message: never) => void>, provider: [] as Array<(message: never) => void> };\n const disconnects = { host: [] as Array<() => void>, provider: [] as Array<() => void> };\n let connected = true;\n const disconnect = () => {\n if (!connected) {\n return;\n }\n connected = false;\n setImmediate(() => {\n for (const listener of [...disconnects.host, ...disconnects.provider]) {\n listener();\n }\n });\n };\n const side = <Out, In>(self: \"host\" | \"provider\", other: \"host\" | \"provider\"): ProtocolChannel<Out, In> => ({\n send: (message) => {\n if (!connected) {\n return;\n }\n const copy = structuredClone(message);\n setImmediate(() => {\n if (connected) {\n for (const listener of listeners[other]) {\n (listener as (message: Out) => void)(copy);\n }\n }\n });\n },\n onMessage: (listener) => listeners[self].push(listener as (message: never) => void),\n onDisconnect: (listener) => disconnects[self].push(listener),\n disconnect,\n });\n return { host: side(\"host\", \"provider\"), provider: side(\"provider\", \"host\") };\n}\n\n/** Paths answered by the host's control router on every service port. */\nexport function isControlPath(pathname: string): boolean {\n return [\"control\", \"faults\", \"state\"].some(\n (root) => pathname === `/_baseline/${root}` || pathname.startsWith(`/_baseline/${root}/`),\n );\n}\n\nexport async function toWireRequest(request: Request): Promise<WireRequest> {\n const body = [\"GET\", \"HEAD\"].includes(request.method) ? undefined : Buffer.from(await request.arrayBuffer());\n return {\n method: request.method,\n url: request.url,\n headers: [...request.headers],\n ...(body?.length ? { body: body.toString(\"base64\") } : {}),\n };\n}\n\nexport function fromWireRequest(wire: WireRequest): Request {\n return new Request(wire.url, {\n method: wire.method,\n headers: wire.headers,\n ...(wire.body === undefined ? {} : { body: Buffer.from(wire.body, \"base64\") }),\n });\n}\n\nexport async function toWireResponse(response: Response): Promise<WireResponse> {\n const body = Buffer.from(await response.arrayBuffer());\n const headers: [string, string][] = [];\n response.headers.forEach((value, name) => {\n if (name !== \"set-cookie\") {\n headers.push([name, value]);\n }\n });\n for (const cookie of response.headers.getSetCookie()) {\n headers.push([\"set-cookie\", cookie]);\n }\n return { status: response.status, headers, ...(body.length ? { body: body.toString(\"base64\") } : {}) };\n}\n\nexport function fromWireResponse(wire: WireResponse): Response {\n const headers = new Headers();\n for (const [name, value] of wire.headers) {\n headers.append(name, value);\n }\n const body = wire.body !== undefined && ![204, 304].includes(wire.status) ? Buffer.from(wire.body, \"base64\") : null;\n return new Response(body, { status: wire.status, headers });\n}\n\n/** An error a provider reported, with its protocol code. */\nexport class ProviderError extends Error {\n readonly code: ProviderErrorCode;\n override name = \"ProviderError\";\n constructor(code: ProviderErrorCode, message: string, options?: ErrorOptions) {\n super(message, options);\n this.code = code;\n }\n}\n","// The host side of the protocol (protocol.ts): what the Baseline CLI uses to\n// drive a provider process, and what a provider's own tests can use to run\n// its built entry the way the CLI does.\nimport { type ChildProcess, fork } from \"node:child_process\";\nimport type { FaultConfig } from \"./faults.js\";\nimport {\n fromWireRequest,\n type HelloMessage,\n type HostMessage,\n type ListeningMessage,\n PROTOCOL_VERSION,\n type ProtocolChannel,\n ProviderError,\n type ProviderMessage,\n type ReadyMessage,\n type StartMessage,\n SUPPORTED_PROTOCOLS,\n toWireResponse,\n} from \"./protocol.js\";\nimport type { ServiceState } from \"./state.js\";\n\nconst LINE_BREAK = /\\r?\\n/;\n\n/** How long each step may take before the host gives up on the provider. */\nexport const PROVIDER_TIMEOUTS = {\n hello: 10_000,\n start: 30_000,\n listen: 30_000,\n snapshot: 10_000,\n request: 10_000,\n stop: 5000,\n};\n\nexport class ProviderTimeoutError extends Error {\n override name = \"ProviderTimeoutError\";\n}\n\ninterface Pending {\n expect: readonly ProviderMessage[\"type\"][];\n resolve: (message: ProviderMessage) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ntype Answer<T extends ProviderMessage[\"type\"]> = Extract<ProviderMessage, { type: T }>;\n\n/** Answers a control request a provider forwarded. */\nexport type ControlHandler = (request: Request) => Promise<Response>;\n\nexport interface ConnectOptions {\n /** The host's version, sent in `welcome`. */\n hostVersion: string;\n /** Used in error messages. Defaults to the name in `hello`. */\n label?: string;\n timeouts?: Partial<typeof PROVIDER_TIMEOUTS>;\n}\n\n/** One provider process, from the host's side. */\nexport class ProviderClient {\n private readonly channel: ProtocolChannel<HostMessage, ProviderMessage>;\n readonly hello: HelloMessage;\n readonly label: string;\n private nextId = 1;\n private readonly pending = new Map<number, Pending>();\n private readonly dirtyListeners: Array<() => void> = [];\n private readonly disconnectListeners: Array<() => void> = [];\n private control: ControlHandler | undefined;\n private connected = true;\n private readonly timeouts: typeof PROVIDER_TIMEOUTS;\n\n private constructor(\n channel: ProtocolChannel<HostMessage, ProviderMessage>,\n hello: HelloMessage,\n label: string,\n timeouts: Partial<typeof PROVIDER_TIMEOUTS>,\n ) {\n this.channel = channel;\n this.hello = hello;\n this.label = label;\n this.timeouts = { ...PROVIDER_TIMEOUTS, ...timeouts };\n }\n\n /**\n * Wait for the provider's `hello`, check its protocol version, and answer\n * `welcome`. Rejects when the provider speaks a protocol this host does not.\n */\n static connect(\n channel: ProtocolChannel<HostMessage, ProviderMessage>,\n options: ConnectOptions,\n ): Promise<ProviderClient> {\n const timeouts = { ...PROVIDER_TIMEOUTS, ...options.timeouts };\n return new Promise((resolve, reject) => {\n let client: ProviderClient | undefined;\n let settled = false;\n const settle = (error?: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n if (error) {\n reject(error);\n } else {\n resolve(client!);\n }\n };\n const timer = setTimeout(\n () =>\n settle(\n new ProviderTimeoutError(\n `${options.label ?? \"Provider\"} did not start: no hello within ${timeouts.hello / 1000} s`,\n ),\n ),\n timeouts.hello,\n );\n channel.onMessage((message) => {\n if (client) {\n return client.receive(message);\n }\n if (message.type !== \"hello\") {\n return settle(new Error(`Expected hello from the provider, got ${message.type}`));\n }\n if (!SUPPORTED_PROTOCOLS.includes(message.protocol)) {\n return settle(\n new Error(\n `${message.name} ${message.version} speaks provider protocol ${message.protocol}; this host supports ${SUPPORTED_PROTOCOLS.join(\", \")}. Use a version of ${message.name} built for this CLI, or upgrade the CLI.`,\n ),\n );\n }\n client = new ProviderClient(channel, message, options.label ?? message.name, timeouts);\n channel.send({ type: \"welcome\", protocol: PROTOCOL_VERSION, host: options.hostVersion });\n settle();\n });\n channel.onDisconnect(() => {\n if (client) {\n client.disconnected();\n } else {\n settle(new Error(`${options.label ?? \"Provider\"} exited before it said hello`));\n }\n });\n });\n }\n\n /** False once the provider has gone away. */\n get isConnected(): boolean {\n return this.connected;\n }\n\n /** Called after a request changed the provider's state. */\n onDirty(listener: () => void): void {\n this.dirtyListeners.push(listener);\n }\n\n /** Called once when the provider goes away, for whatever reason. */\n onDisconnect(listener: () => void): void {\n if (this.connected) {\n this.disconnectListeners.push(listener);\n } else {\n queueMicrotask(listener);\n }\n }\n\n /** Answer control requests (`/_baseline/{control,faults,state}`) that arrive on the provider's port. */\n setControlHandler(handler: ControlHandler): void {\n this.control = handler;\n }\n\n start(message: Omit<StartMessage, \"type\" | \"id\">): Promise<ReadyMessage> {\n return this.request({ type: \"start\", ...message } as StartMessage, [\"ready\"], this.timeouts.start);\n }\n\n listen(): Promise<ListeningMessage> {\n return this.request({ type: \"listen\", id: 0 }, [\"listening\"], this.timeouts.listen);\n }\n\n async snapshot(): Promise<ServiceState> {\n return (await this.request({ type: \"snapshot\", id: 0 }, [\"snapshot\"], this.timeouts.snapshot)).state;\n }\n\n async restore(state: ServiceState): Promise<void> {\n await this.request({ type: \"restore\", id: 0, state }, [\"ok\"], this.timeouts.request);\n }\n\n async reset(): Promise<void> {\n await this.request({ type: \"reset\", id: 0 }, [\"ok\"], this.timeouts.request);\n }\n\n async setFaults(faults: FaultConfig): Promise<void> {\n await this.request({ type: \"faults\", id: 0, faults }, [\"ok\"], this.timeouts.request);\n }\n\n /** Ask the provider to stop, and resolve with its final state when `snapshot` is set. */\n async stop(snapshot: boolean): Promise<ServiceState | undefined> {\n return (await this.request({ type: \"stop\", id: 0, snapshot }, [\"stopped\"], this.timeouts.stop)).state;\n }\n\n private request<T extends ProviderMessage[\"type\"]>(\n message: Exclude<HostMessage, { type: \"welcome\" | \"control-response\" }>,\n expect: readonly T[],\n timeoutMs: number,\n ): Promise<Answer<T>> {\n if (!this.connected) {\n return Promise.reject(new Error(`${this.label} is not running`));\n }\n const id = this.nextId;\n this.nextId += 1;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new ProviderTimeoutError(`${this.label} did not answer ${message.type} within ${timeoutMs / 1000} s`));\n }, timeoutMs);\n this.pending.set(id, {\n expect,\n resolve: resolve as (message: ProviderMessage) => void,\n reject,\n timer,\n });\n this.channel.send({ ...message, id } as HostMessage);\n });\n }\n\n private receive(message: ProviderMessage): void {\n if (message.type === \"dirty\") {\n for (const listener of this.dirtyListeners) {\n listener();\n }\n return;\n }\n if (message.type === \"control\") {\n this.answerControl(message.id, message.request);\n return;\n }\n if (message.type === \"hello\") {\n return;\n }\n if (message.id === undefined) {\n return;\n }\n const pending = this.pending.get(message.id);\n if (!pending) {\n return;\n }\n this.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.type === \"error\") {\n pending.reject(new ProviderError(message.code, message.message));\n } else if (pending.expect.includes(message.type)) {\n pending.resolve(message);\n } else {\n pending.reject(new Error(`${this.label} answered ${message.type}; expected ${pending.expect.join(\" or \")}`));\n }\n }\n\n private async answerControl(id: number, wire: Parameters<typeof fromWireRequest>[0]): Promise<void> {\n let response: Response;\n try {\n response = this.control\n ? await this.control(fromWireRequest(wire))\n : Response.json({ error: \"Control API is not available\" }, { status: 404 });\n } catch (error) {\n response = Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 500 });\n }\n if (this.connected) {\n this.channel.send({ type: \"control-response\", id, response: await toWireResponse(response) });\n }\n }\n\n private disconnected(): void {\n if (!this.connected) {\n return;\n }\n this.connected = false;\n for (const [id, pending] of this.pending) {\n clearTimeout(pending.timer);\n pending.reject(new Error(`${this.label} exited`));\n this.pending.delete(id);\n }\n for (const listener of this.disconnectListeners.splice(0)) {\n listener();\n }\n }\n\n /** Close the channel. The provider exits when its host goes away. */\n disconnect(): void {\n this.channel.disconnect();\n }\n}\n\nexport interface SpawnProviderOptions extends Omit<ConnectOptions, \"label\"> {\n /** Shown before each line of the provider's output, and in errors. */\n label: string;\n /** Arguments after the entry path. */\n args?: string[];\n env?: NodeJS.ProcessEnv;\n execArgv?: string[];\n /** Each line the provider prints. Defaults to the host's stdout and stderr with a `[label]` prefix. */\n onOutput?: (line: string, stream: \"stdout\" | \"stderr\") => void;\n}\n\n/** A forked provider and the client that drives it. */\nexport interface SpawnedProvider {\n client: ProviderClient;\n child: ChildProcess;\n /** The last lines the provider printed, newest last. */\n recentOutput(): string[];\n /** Resolves with the exit code or signal once the process has exited. */\n readonly exited: Promise<{ code: number | null; signal: NodeJS.Signals | null }>;\n /** Kill the process now. */\n kill(): void;\n}\n\nconst OUTPUT_LINES = 50;\n\n/** Fork a provider entry and connect to it. Kills the process if the handshake fails. */\nexport async function spawnProvider(entry: string, options: SpawnProviderOptions): Promise<SpawnedProvider> {\n const child = fork(entry, options.args ?? [], {\n serialization: \"advanced\",\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n env: options.env,\n execArgv: options.execArgv ?? [\"--enable-source-maps\"],\n });\n const lines: string[] = [];\n const output =\n options.onOutput ??\n ((line: string, stream: \"stdout\" | \"stderr\") =>\n (stream === \"stdout\" ? process.stdout : process.stderr).write(`[${options.label}] ${line}\\n`));\n for (const stream of [\"stdout\", \"stderr\"] as const) {\n let buffered = \"\";\n child[stream]!.setEncoding(\"utf8\");\n child[stream]!.on(\"data\", (chunk: string) => {\n buffered += chunk;\n const parts = buffered.split(LINE_BREAK);\n buffered = parts.pop()!;\n for (const line of parts) {\n lines.push(line);\n if (lines.length > OUTPUT_LINES) {\n lines.shift();\n }\n output(line, stream);\n }\n });\n child[stream]!.on(\"end\", () => {\n if (!buffered) {\n return;\n }\n lines.push(buffered);\n output(buffered, stream);\n buffered = \"\";\n });\n }\n const exited = new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve) => {\n if (child.exitCode !== null || child.signalCode !== null) {\n resolve({ code: child.exitCode, signal: child.signalCode as NodeJS.Signals | null });\n } else {\n child.once(\"exit\", (code, signal) => resolve({ code, signal }));\n }\n });\n const kill = () => {\n if (child.exitCode === null && child.signalCode === null) {\n child.kill(\"SIGKILL\");\n }\n };\n const disconnects: Array<() => void> = [];\n let gone = false;\n const goneOnce = () => {\n if (gone) {\n return;\n }\n gone = true;\n for (const listener of disconnects) {\n listener();\n }\n };\n child.once(\"disconnect\", goneOnce);\n child.once(\"exit\", goneOnce);\n child.once(\"error\", goneOnce);\n const channel: ProtocolChannel<HostMessage, ProviderMessage> = {\n send: (message) => {\n if (child.connected) {\n child.send(message, undefined, {}, () => {\n // No-op.\n });\n }\n },\n onMessage: (listener) => child.on(\"message\", (message) => listener(message as ProviderMessage)),\n onDisconnect: (listener) => disconnects.push(listener),\n disconnect: () => {\n if (child.connected) {\n child.disconnect();\n }\n },\n };\n try {\n const client = await ProviderClient.connect(channel, { ...options, label: options.label });\n return { client, child, recentOutput: () => [...lines], exited, kill };\n } catch (error) {\n kill();\n await exited;\n const tail = lines.length ? `\\n${lines.slice(-10).join(\"\\n\")}` : \"\";\n throw new Error(`${error instanceof Error ? error.message : error}${tail}`, { cause: error });\n }\n}\n","// The provider side of the protocol (protocol.ts). A provider package's entry\n// is one call to `runProvider(manifest)`; this does everything the host used to\n// do around a service in its own process: seed or restore, faults, dirty\n// tracking, forwarding control routes to the host, and listening on the port\n// the host gives it, WebSocket upgrades included.\nimport { readFileSync } from \"node:fs\";\nimport type { Server } from \"node:http\";\nimport { resolveBaseUrl } from \"./base-url.js\";\nimport { FaultInjector } from \"./faults.js\";\nimport { serve, type UpgradeListener } from \"./http.js\";\nimport { applyIdentities } from \"./identities.js\";\nimport type { LoadedService, ProviderManifest } from \"./manifest.js\";\nimport type { AppKeyResolver } from \"./middleware/auth.js\";\nimport {\n FAULT_KINDS,\n fromWireResponse,\n type HostMessage,\n isControlPath,\n PROTOCOL_VERSION,\n type ProtocolChannel,\n ProviderError,\n type ProviderMessage,\n type ProviderSecret,\n processChannel,\n type StartMessage,\n toWireRequest,\n type WireResponse,\n} from \"./protocol.js\";\nimport { createServer } from \"./server.js\";\nimport { captureServiceState, restoreServiceState, SDK_VERSION, type ServiceState } from \"./state.js\";\n\nexport interface RunProviderOptions {\n /** The provider package's package.json, for its version. Pass `new URL(\"../package.json\", import.meta.url)`. */\n packageUrl?: URL;\n /** The provider package's version, when there is no package.json to read. */\n version?: string;\n /** The channel to the host. Defaults to Node IPC. */\n channel?: ProtocolChannel<ProviderMessage, HostMessage>;\n /** Called when the provider is done: after `stop`, or when the host goes away. Defaults to `process.exit`. */\n exit?: (code: number) => void;\n}\n\n/** A running provider, for tests that drive it in process. */\nexport interface ProviderRun {\n /** Resolves once the provider has stopped. */\n readonly done: Promise<number>;\n}\n\nconst MUTATING_METHODS = new Set([\"POST\", \"PUT\", \"PATCH\", \"DELETE\"]);\nconst STOP_TIMEOUT_MS = 4000;\n\ninterface Running {\n config: Record<string, unknown> | undefined;\n baseUrl: string;\n server: ReturnType<typeof createServer>;\n faults: FaultInjector;\n seed(): void;\n listener?: Server;\n port?: number;\n}\n\n/**\n * Run a provider: speak the protocol to the host until it says stop. The\n * manifest's `load()` provides the plugin and its seed hooks, exactly as for\n * an in-process service.\n */\nexport function runProvider(manifest: ProviderManifest, options: RunProviderOptions = {}): ProviderRun {\n const channel = options.channel ?? processChannel();\n const exit = options.exit ?? ((code: number) => process.exit(code));\n const version = options.version ?? readVersion(options.packageUrl);\n let running: Running | undefined;\n let welcomed = false;\n let stopping = false;\n let finish!: (code: number) => void;\n const done = new Promise<number>((resolve) => {\n finish = resolve;\n });\n let nextControlId = 1;\n const controls = new Map<number, (response: WireResponse) => void>();\n // Host requests run one at a time, in order. Control responses skip the queue.\n let queue = Promise.resolve();\n\n const send = (message: ProviderMessage) => channel.send(message);\n const fail = (id: number | undefined, error: unknown) => {\n const code = error instanceof ProviderError ? error.code : \"internal\";\n send({ type: \"error\", ...(id === undefined ? {} : { id }), code, message: describe(error) });\n };\n\n const end = (code: number) => {\n channel.disconnect();\n finish(code);\n exit(code);\n };\n\n channel.onMessage((message) => {\n if (message.type === \"control-response\") {\n const resolve = controls.get(message.id);\n controls.delete(message.id);\n resolve?.(message.response);\n return;\n }\n if (message.type === \"welcome\") {\n welcomed = true;\n return;\n }\n queue = queue.then(async () => {\n if (stopping) {\n return;\n }\n try {\n if (!welcomed) {\n throw new ProviderError(\"bad_request\", `Expected welcome before ${message.type}`);\n }\n await handle(message);\n } catch (error) {\n fail(\"id\" in message ? message.id : undefined, error);\n }\n });\n });\n\n channel.onDisconnect(() => {\n // The host is gone: never outlive it.\n if (stopping) {\n return;\n }\n stopping = true;\n for (const resolve of controls.values()) {\n resolve(hostGone());\n }\n controls.clear();\n const timer = setTimeout(() => end(1), STOP_TIMEOUT_MS);\n timer.unref?.();\n shutdown()\n .catch(() => {\n // Best effort: the failure is ignored.\n })\n .finally(() => {\n clearTimeout(timer);\n end(0);\n });\n });\n\n send({\n type: \"hello\",\n protocol: PROTOCOL_VERSION,\n name: manifest.name,\n version,\n sdk: SDK_VERSION,\n stateVersion: manifest.stateVersion,\n faults: FAULT_KINDS,\n });\n\n async function handle(message: HostMessage): Promise<void> {\n switch (message.type) {\n case \"start\": {\n if (running) {\n throw new ProviderError(\"bad_request\", \"Already started\");\n }\n running = await start(message);\n const { port } = running;\n send({ type: \"ready\", id: message.id, secrets, url: running.baseUrl, ...(port === undefined ? {} : { port }) });\n return;\n }\n case \"listen\": {\n const service = started();\n const port = service.listener ? service.port! : await listen(service, startMessage!);\n send({ type: \"listening\", id: message.id, port, url: service.baseUrl });\n return;\n }\n case \"snapshot\":\n send({ type: \"snapshot\", id: message.id, state: capture(started()) });\n return;\n case \"restore\":\n restore(started(), message.state);\n send({ type: \"ok\", id: message.id });\n return;\n case \"reset\": {\n const { server, seed } = started();\n for (const [token, user] of server.tokenMap) {\n if (user.installation) {\n server.tokenMap.delete(token);\n }\n }\n server.store.reset();\n server.webhooks.clear();\n seed();\n send({ type: \"ok\", id: message.id });\n return;\n }\n case \"faults\":\n try {\n started().faults.set(message.faults);\n } catch (error) {\n // biome-ignore lint/style/useErrorCause: the cause goes in ProviderError's third (options) argument; the rule only reads the second\n throw new ProviderError(\"faults_invalid\", describe(error), { cause: error });\n }\n send({ type: \"ok\", id: message.id });\n return;\n case \"stop\": {\n stopping = true;\n const state = await shutdown(message.snapshot);\n send({ type: \"stopped\", id: message.id, ...(state ? { state } : {}) });\n // Let the answer reach the host before the channel closes.\n setImmediate(() => end(0));\n return;\n }\n default:\n throw new ProviderError(\"bad_request\", `Unknown message ${(message as { type: string }).type}`);\n }\n }\n\n let secrets: ProviderSecret[] = [];\n let startMessage: StartMessage | undefined;\n let loaded: LoadedService | undefined;\n\n function started(): Running {\n if (!running) {\n throw new ProviderError(\"bad_request\", \"Not started\");\n }\n return running;\n }\n\n async function start(message: StartMessage): Promise<Running> {\n startMessage = message;\n loaded = await manifest.load();\n const service = loaded;\n let config = applyIdentities(message.seed, message.identities ?? [], service.mapIdentity);\n secrets = (message.secrets ?? []).map((secret) => ({ ...secret }));\n if (message.generateSecrets && config && service.prepareSeed) {\n try {\n const prepared = await service.prepareSeed(config, secrets);\n ({ config } = prepared);\n secrets = prepared.generatedSecrets;\n } catch (error) {\n // biome-ignore lint/style/useErrorCause: the cause goes in ProviderError's third (options) argument; the rule only reads the second\n throw new ProviderError(\"seed_invalid\", describe(error), { cause: error });\n }\n }\n let listener: Server | undefined;\n let { port } = message;\n if (message.listen) {\n // The base URL names the bound port, so bind before building the app.\n listener = await bind(\n message,\n (request) => (handler ? handler(request) : starting()),\n (...args) => (upgrade ? upgrade(...args) : false),\n );\n port = boundPort(listener, message.port);\n }\n const baseUrl = resolveBaseUrl({\n service: message.service,\n port,\n baseUrl: message.baseUrl,\n seedBaseUrl: message.serviceBaseUrl,\n });\n // Assigned once the store exists; the resolver closure reads it later.\n let resolver: AppKeyResolver | undefined;\n const appKeyResolver: AppKeyResolver | undefined = service.createAppKeyResolver\n ? (appId) => resolver!(appId)\n : undefined;\n const server = createServer(service.plugin, {\n port,\n baseUrl,\n tokens: message.tokens,\n appKeyResolver,\n fallbackUser: manifest.defaultFallback(config),\n });\n resolver = service.createAppKeyResolver?.(server.store);\n const seed = () => {\n service.plugin.seed?.(server.store, baseUrl);\n if (config && service.seedFromConfig) {\n service.seedFromConfig(server.store, baseUrl, config, server.webhooks);\n }\n };\n let faults: FaultInjector;\n try {\n faults = new FaultInjector(message.service, message.faults);\n } catch (error) {\n // biome-ignore lint/style/useErrorCause: the cause goes in ProviderError's third (options) argument; the rule only reads the second\n throw new ProviderError(\"faults_invalid\", describe(error), { cause: error });\n }\n const result: Running = { config, baseUrl, server, faults, seed, listener, ...(listener ? { port } : {}) };\n if (message.state) {\n restore(result, message.state);\n } else {\n try {\n seed();\n } catch (error) {\n // biome-ignore lint/style/useErrorCause: the cause goes in ProviderError's third (options) argument; the rule only reads the second\n throw new ProviderError(\"seed_invalid\", describe(error), { cause: error });\n }\n }\n handler = fetchFor(result);\n upgrade = server.app.handleUpgrade;\n return result;\n }\n\n let handler: ((request: Request) => Promise<Response>) | undefined;\n let upgrade: UpgradeListener | undefined;\n\n // Control routes go to the host; everything else through faults to the app, noting changes.\n function fetchFor(service: Running): (request: Request) => Promise<Response> {\n const { store, app } = service.server;\n const inner = service.faults.wrap(async (request) => {\n const { revision } = store;\n const response = await app.fetch(request);\n if (MUTATING_METHODS.has(request.method) || store.revision !== revision) {\n send({ type: \"dirty\" });\n }\n return response;\n });\n return async (request) => (isControlPath(new URL(request.url).pathname) ? forward(request) : inner(request));\n }\n\n async function forward(request: Request): Promise<Response> {\n if (stopping) {\n return fromWireResponse(hostGone());\n }\n const id = nextControlId;\n nextControlId += 1;\n const wire = await toWireRequest(request);\n const response = await new Promise<WireResponse>((resolve) => {\n controls.set(id, resolve);\n send({ type: \"control\", id, request: wire });\n });\n return fromWireResponse(response);\n }\n\n async function listen(service: Running, message: StartMessage): Promise<number> {\n service.listener = await bind(\n message,\n (request) => (handler ? handler(request) : starting()),\n (...args) => (upgrade ? upgrade(...args) : false),\n );\n service.port = boundPort(service.listener, message.port);\n return service.port;\n }\n\n function capture(service: Running): ServiceState {\n const { store, tokenMap, webhooks } = service.server;\n return captureServiceState({ store, tokenMap, webhooks }, manifest.stateVersion);\n }\n\n function restore(service: Running, state: ServiceState): void {\n if (state.stateVersion !== manifest.stateVersion) {\n throw new ProviderError(\n \"state_incompatible\",\n `Saved state for ${startMessage?.service ?? manifest.name} has stateVersion ${state.stateVersion}, but ${manifest.name} ${version} expects ${manifest.stateVersion}.`,\n );\n }\n const { store, tokenMap, webhooks } = service.server;\n try {\n restoreServiceState({ store, tokenMap, webhooks }, state);\n } catch (error) {\n // biome-ignore lint/style/useErrorCause: the cause goes in ProviderError's third (options) argument; the rule only reads the second\n throw new ProviderError(\"state_invalid\", describe(error), { cause: error });\n }\n }\n\n // Stop listening, take the final state, and close WebSockets alongside the listener (they hold it open).\n async function shutdown(snapshot = false): Promise<ServiceState | undefined> {\n const service = running;\n if (!service) {\n return undefined;\n }\n const closing = service.listener ? closeListener(service.listener) : Promise.resolve();\n const state = snapshot ? capture(service) : undefined;\n await Promise.all([closing, service.server.app.dispose()]);\n service.server.webhooks.clear();\n return state;\n }\n\n return { done };\n}\n\nfunction bind(\n message: StartMessage,\n fetch: (request: Request) => Response | Promise<Response>,\n upgrade: UpgradeListener,\n): Promise<Server> {\n const server = serve({ port: message.port, hostname: message.hostname, fetch, upgrade });\n return new Promise((resolve, reject) => {\n const ready = () => {\n server.off(\"error\", failed);\n resolve(server);\n };\n const failed = (error: NodeJS.ErrnoException) => {\n server.off(\"listening\", ready);\n reject(\n new ProviderError(\n error.code === \"EADDRINUSE\" || error.code === \"EACCES\" ? \"port_in_use\" : \"internal\",\n error.message,\n ),\n );\n };\n server.once(\"listening\", ready);\n server.once(\"error\", failed);\n });\n}\n\nfunction boundPort(server: Server, fallback: number): number {\n const address = server.address();\n return address && typeof address === \"object\" ? address.port : fallback;\n}\n\nfunction closeListener(server: Server): Promise<void> {\n return new Promise((resolve) => {\n server.close(() => resolve());\n server.closeAllConnections();\n });\n}\n\nconst starting = () => Response.json({ error: \"Starting\" }, { status: 503 });\n\nconst hostGone = (): WireResponse => ({\n status: 503,\n headers: [[\"content-type\", \"application/json\"]],\n body: Buffer.from(JSON.stringify({ error: \"The Baseline host is not available\" })).toString(\"base64\"),\n});\n\nfunction describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction readVersion(url: URL | undefined): string {\n if (!url) {\n return \"0.0.0\";\n }\n try {\n const pkg = JSON.parse(readFileSync(url, \"utf8\")) as { version?: unknown };\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n","export interface Entity {\n id: number;\n created_at: string;\n updated_at: string;\n}\n\nexport type InsertInput<T extends Entity> = Omit<T, \"id\" | \"created_at\" | \"updated_at\"> & { id?: number };\n\nexport type FilterFn<T> = (item: T) => boolean;\nexport type SortFn<T> = (a: T, b: T) => number;\n\nexport interface QueryOptions<T> {\n filter?: FilterFn<T>;\n sort?: SortFn<T>;\n page?: number;\n per_page?: number;\n}\n\nexport interface PaginatedResult<T> {\n items: T[];\n total_count: number;\n page: number;\n per_page: number;\n has_next: boolean;\n has_prev: boolean;\n}\n\nexport interface CollectionSnapshot<T extends Entity = Entity> {\n items: T[];\n autoId: number;\n indexFields: string[];\n}\n\nexport interface StoreSnapshot {\n collections: Record<string, CollectionSnapshot>;\n data: Record<string, unknown>;\n}\n\nexport function serializeValue(value: unknown): unknown {\n if (value instanceof Map) {\n return { __type: \"Map\" as const, entries: [...value.entries()].map(([k, v]) => [k, serializeValue(v)]) };\n }\n if (value instanceof Set) {\n return { __type: \"Set\" as const, values: [...value.values()] };\n }\n return value;\n}\n\nexport function deserializeValue(value: unknown): unknown {\n if (value !== null && typeof value === \"object\" && \"__type\" in value) {\n const tagged = value as Record<string, unknown>;\n if (tagged.__type === \"Map\") {\n const entries = tagged.entries as [unknown, unknown][];\n return new Map(entries.map(([k, v]) => [k, deserializeValue(v)]));\n }\n if (tagged.__type === \"Set\") {\n return new Set(tagged.values as unknown[]);\n }\n }\n return value;\n}\n\nexport class Collection<T extends Entity> {\n private readonly items = new Map<number, T>();\n private readonly indexes = new Map<string, Map<string | number, Set<number>>>();\n private autoId = 1;\n readonly fieldNames: string[];\n private readonly indexFields: (keyof T)[];\n /** Called after every change, so the owning store can count revisions. */\n private readonly onChange: () => void;\n\n constructor(\n indexFields: (keyof T)[] = [],\n onChange: () => void = () => {\n // No-op.\n },\n ) {\n this.indexFields = indexFields;\n this.onChange = onChange;\n this.fieldNames = indexFields.map(String).sort();\n for (const field of indexFields) {\n this.indexes.set(String(field), new Map());\n }\n }\n\n private addToIndex(item: T): void {\n for (const field of this.indexFields) {\n const value = item[field];\n if (value === undefined || value === null) {\n continue;\n }\n const indexMap = this.indexes.get(String(field))!;\n const key = String(value);\n if (!indexMap.has(key)) {\n indexMap.set(key, new Set());\n }\n indexMap.get(key)!.add(item.id);\n }\n }\n\n private removeFromIndex(item: T): void {\n for (const field of this.indexFields) {\n const value = item[field];\n if (value === undefined || value === null) {\n continue;\n }\n const indexMap = this.indexes.get(String(field))!;\n const key = String(value);\n indexMap.get(key)?.delete(item.id);\n }\n }\n\n insert(data: InsertInput<T>): T {\n const now = new Date().toISOString();\n const explicitId = data.id !== null && data.id !== undefined && data.id > 0 ? data.id : undefined;\n let id: number;\n if (explicitId === undefined) {\n id = this.autoId;\n this.autoId += 1;\n } else {\n id = explicitId;\n }\n if (id >= this.autoId) {\n this.autoId = id + 1;\n }\n const item = {\n ...data,\n id,\n created_at: now,\n updated_at: now,\n } as unknown as T;\n this.items.set(id, item);\n this.addToIndex(item);\n this.onChange();\n return item;\n }\n\n get(id: number): T | undefined {\n return this.items.get(id);\n }\n\n findBy(field: keyof T, value: T[keyof T] | string | number): T[] {\n if (this.indexes.has(String(field))) {\n const ids = this.indexes.get(String(field))!.get(String(value));\n if (!ids) {\n return [];\n }\n return Array.from(ids)\n .map((id) => this.items.get(id)!)\n .filter(Boolean);\n }\n return this.all().filter((item) => item[field] === value);\n }\n\n findOneBy(field: keyof T, value: T[keyof T] | string | number): T | undefined {\n return this.findBy(field, value)[0];\n }\n\n update(id: number, data: Partial<T>): T | undefined {\n const existing = this.items.get(id);\n if (!existing) {\n return undefined;\n }\n this.removeFromIndex(existing);\n const updated = {\n ...existing,\n ...data,\n id,\n updated_at: new Date().toISOString(),\n } as T;\n this.items.set(id, updated);\n this.addToIndex(updated);\n this.onChange();\n return updated;\n }\n\n delete(id: number): boolean {\n const existing = this.items.get(id);\n if (!existing) {\n return false;\n }\n this.removeFromIndex(existing);\n this.items.delete(id);\n this.onChange();\n return true;\n }\n\n all(): T[] {\n return Array.from(this.items.values());\n }\n\n query(options: QueryOptions<T> = {}): PaginatedResult<T> {\n let results = this.all();\n\n if (options.filter) {\n results = results.filter(options.filter);\n }\n\n const total_count = results.length;\n\n if (options.sort) {\n results.sort(options.sort);\n }\n\n const page = options.page ?? 1;\n const per_page = Math.min(options.per_page ?? 30, 100);\n const start = (page - 1) * per_page;\n const paged = results.slice(start, start + per_page);\n\n return {\n items: paged,\n total_count,\n page,\n per_page,\n has_next: start + per_page < total_count,\n has_prev: page > 1,\n };\n }\n\n count(filter?: FilterFn<T>): number {\n if (!filter) {\n return this.items.size;\n }\n return this.all().filter(filter).length;\n }\n\n clear(): void {\n this.items.clear();\n for (const indexMap of this.indexes.values()) {\n indexMap.clear();\n }\n this.autoId = 1;\n this.onChange();\n }\n\n snapshot(): CollectionSnapshot<T> {\n return {\n items: this.all(),\n autoId: this.autoId,\n indexFields: this.fieldNames,\n };\n }\n\n restore(snap: CollectionSnapshot<T>): void {\n this.clear();\n this.autoId = snap.autoId;\n for (const item of snap.items) {\n this.items.set(item.id, item);\n this.addToIndex(item);\n }\n }\n}\n\nexport class Store {\n private readonly collections = new Map<string, Collection<Entity>>();\n private readonly _data = new Map<string, unknown>();\n private _revision = 0;\n\n /**\n * Increases on every collection change, `setData`, `reset`, and `restore`.\n * Runners compare it before and after a request to decide whether to save.\n * Mutating an object returned by `getData` in place does not count.\n */\n get revision(): number {\n return this._revision;\n }\n\n private readonly touch = () => {\n this._revision += 1;\n };\n\n collection<T extends Entity>(name: string, indexFields: (keyof T)[] = []): Collection<T> {\n const existing = this.collections.get(name);\n if (existing) {\n if (indexFields.length > 0) {\n const requested = indexFields.map(String).sort();\n if (existing.fieldNames.length !== requested.length || existing.fieldNames.some((f, i) => f !== requested[i])) {\n throw new Error(\n `Collection \"${name}\" already exists with indexes [${existing.fieldNames}] but was requested with [${requested}]`,\n );\n }\n }\n return existing as unknown as Collection<T>;\n }\n const col = new Collection<T>(indexFields, this.touch);\n this.collections.set(name, col as unknown as Collection<Entity>);\n return col;\n }\n\n hasCollection(name: string): boolean {\n return this.collections.has(name);\n }\n\n getData<V>(key: string): V | undefined {\n return this._data.get(key) as V | undefined;\n }\n\n setData<V>(key: string, value: V): void {\n this._data.set(key, value);\n this.touch();\n }\n\n reset(): void {\n for (const collection of this.collections.values()) {\n collection.clear();\n }\n this._data.clear();\n this.touch();\n }\n\n snapshot(): StoreSnapshot {\n const collections: Record<string, CollectionSnapshot> = {};\n for (const [name, col] of this.collections) {\n collections[name] = col.snapshot();\n }\n const data: Record<string, unknown> = {};\n for (const [key, value] of this._data) {\n data[key] = serializeValue(value);\n }\n return { collections, data };\n }\n\n restore(snap: StoreSnapshot): void {\n const snapshotNames = new Set(Object.keys(snap.collections));\n for (const name of this.collections.keys()) {\n if (!snapshotNames.has(name)) {\n this.collections.delete(name);\n }\n }\n for (const [name, colSnap] of Object.entries(snap.collections)) {\n const indexFields = colSnap.indexFields as (keyof Entity)[];\n const col = this.collection(name, indexFields);\n col.restore(colSnap as CollectionSnapshot<Entity>);\n }\n this._data.clear();\n for (const [key, value] of Object.entries(snap.data)) {\n this._data.set(key, deserializeValue(value));\n }\n this.touch();\n }\n}\n","import { registerFontRoutes } from \"./fonts.js\";\nimport { cors, Hono } from \"./http.js\";\nimport {\n type AppEnv,\n type AppKeyResolver,\n type AuthFallback,\n authMiddleware,\n type TokenMap,\n} from \"./middleware/auth.js\";\nimport { createApiErrorHandler, createErrorHandler } from \"./middleware/error-handler.js\";\nimport type { ServicePlugin } from \"./plugin.js\";\nimport { Store } from \"./store.js\";\nimport { WebhookDispatcher } from \"./webhooks.js\";\n\nexport interface ServerOptions {\n port?: number;\n baseUrl?: string;\n docsUrl?: string;\n tokens?: Record<string, { login: string; id: number; scopes?: string[] }>;\n appKeyResolver?: AppKeyResolver;\n fallbackUser?: AuthFallback;\n}\n\nexport function createServer(plugin: ServicePlugin, options: ServerOptions = {}) {\n const port = options.port ?? 4000;\n const baseUrl = options.baseUrl ?? `http://localhost:${port}`;\n\n const app = new Hono<AppEnv>();\n const store = new Store();\n const webhooks = new WebhookDispatcher();\n\n const tokenMap: TokenMap = new Map();\n if (options.tokens) {\n for (const [token, user] of Object.entries(options.tokens)) {\n tokenMap.set(token, {\n login: user.login,\n id: user.id,\n scopes: user.scopes ?? [\"repo\", \"user\", \"admin:org\", \"admin:repo_hook\"],\n });\n }\n }\n\n const docsUrl = options.docsUrl ?? `https://docs.deploybaseline.com/${plugin.name}`;\n\n registerFontRoutes(app);\n\n app.onError(createApiErrorHandler(docsUrl));\n // OPTIONS routes a plugin registers answer plain OPTIONS requests.\n app.use(\n \"*\",\n cors({\n passThrough: (c) => app.matchedRoute(\"OPTIONS\", new URL(c.req.url).pathname)?.method === \"OPTIONS\",\n }),\n );\n app.use(\"*\", createErrorHandler(docsUrl));\n app.use(\"*\", authMiddleware(tokenMap, options.appKeyResolver, options.fallbackUser));\n\n const rateLimitCounters = new Map<string, { remaining: number; resetAt: number }>();\n let lastPruneAt = Math.floor(Date.now() / 1000);\n\n app.use(\"*\", async (c, next) => {\n const token = c.get(\"authToken\") ?? \"__anonymous__\";\n const now = Math.floor(Date.now() / 1000);\n\n if (now - lastPruneAt > 3600) {\n for (const [key, val] of rateLimitCounters) {\n if (val.resetAt <= now) {\n rateLimitCounters.delete(key);\n }\n }\n lastPruneAt = now;\n }\n\n let counter = rateLimitCounters.get(token);\n if (!counter || counter.resetAt <= now) {\n counter = { remaining: 5000, resetAt: now + 3600 };\n rateLimitCounters.set(token, counter);\n }\n\n counter.remaining = Math.max(0, counter.remaining - 1);\n\n c.header(\"X-RateLimit-Limit\", \"5000\");\n c.header(\"X-RateLimit-Remaining\", String(counter.remaining));\n c.header(\"X-RateLimit-Reset\", String(counter.resetAt));\n c.header(\"X-RateLimit-Resource\", \"core\");\n\n if (counter.remaining === 0) {\n return c.json(\n {\n message: \"API rate limit exceeded\",\n documentation_url: docsUrl,\n },\n 403,\n );\n }\n\n await next();\n });\n\n plugin.register(app, store, webhooks, baseUrl, tokenMap);\n\n app.notFound((c) =>\n c.json(\n {\n message: \"Not Found\",\n documentation_url: docsUrl,\n },\n 404,\n ),\n );\n\n return { app, store, webhooks, port, baseUrl, tokenMap };\n}\n","import type { PersistenceAdapter } from \"./persistence.js\";\nimport { checkSnapshotName, type SnapshotInfo, type SnapshotStore, snapshotServices } from \"./snapshots.js\";\n\nconst FORMAT_PREFIX = /^\\{\"format\":(\\d+)/;\n\n/**\n * The little a SQL database has to offer for saved state: run a statement with\n * positional `?` arguments and return its rows. node:sqlite and libSQL both fit.\n */\nexport interface SqlDatabase {\n execute(sql: string, args?: ReadonlyArray<string | number | null>): Promise<Record<string, unknown>[]>;\n}\n\n/** Saved state in a SQL database: the live state plus named snapshots, in one table. */\nexport interface SqlStateStore extends PersistenceAdapter {\n readonly snapshots: SnapshotStore;\n}\n\n/** The table that holds saved state. One row per name: \"current\" is the live state, others are snapshots. */\nexport const SQL_STATE_TABLE = \"baseline_state\";\nconst CURRENT = \"current\";\n\n/** Create the table if needed. Safe to run on every start. */\nexport const SQL_STATE_SCHEMA = `CREATE TABLE IF NOT EXISTS ${SQL_STATE_TABLE} (\n name TEXT PRIMARY KEY,\n format INTEGER NOT NULL,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n)`;\n\n// The envelope writes `format` first; anything else (format 0) has none.\nconst formatOf = (data: string) => Number(FORMAT_PREFIX.exec(data)?.[1] ?? 0);\n\nconst UPSERT = `INSERT INTO ${SQL_STATE_TABLE} (name, format, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?)\nON CONFLICT(name) DO UPDATE SET format = excluded.format, data = excluded.data, updated_at = excluded.updated_at`;\n\n/**\n * Persistence and snapshots over a SQL database. `label` names the database in\n * messages, e.g. \"sqlite:.baseline/state.db\". Call after `SQL_STATE_SCHEMA` ran.\n */\nexport function sqlStateStore(db: SqlDatabase, label: string): SqlStateStore {\n async function read(name: string): Promise<string | null> {\n const [row] = await db.execute(`SELECT data FROM ${SQL_STATE_TABLE} WHERE name = ?`, [name]);\n return row ? String(row.data) : null;\n }\n async function write(name: string, data: string): Promise<void> {\n const now = Date.now();\n await db.execute(UPSERT, [name, formatOf(data), data, now, now]);\n }\n const snapshots: SnapshotStore = {\n label: `in ${label}`,\n async list() {\n const rows = await db.execute(\n `SELECT name, updated_at, data FROM ${SQL_STATE_TABLE} WHERE name <> ? ORDER BY updated_at, name`,\n [CURRENT],\n );\n return rows.map(\n (row): SnapshotInfo => ({\n name: String(row.name),\n createdAt: new Date(Number(row.updated_at)).toISOString(),\n size: Buffer.byteLength(String(row.data)),\n services: snapshotServices(String(row.data)),\n }),\n );\n },\n load: async (name) => read(checkSnapshotName(name)),\n save: async (name, data) => write(checkSnapshotName(name), data),\n async delete(name) {\n const rows = await db.execute(`DELETE FROM ${SQL_STATE_TABLE} WHERE name = ? RETURNING name`, [\n checkSnapshotName(name),\n ]);\n return rows.length > 0;\n },\n };\n return {\n load: () => read(CURRENT),\n save: (data) => write(CURRENT, data),\n // First writer wins: concurrent cold starts all end up with the same state.\n async initialize(data) {\n const now = Date.now();\n await db.execute(\n `INSERT INTO ${SQL_STATE_TABLE} (name, format, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(name) DO NOTHING`,\n [CURRENT, formatOf(data), data, now, now],\n );\n return (await read(CURRENT)) ?? data;\n },\n snapshots,\n };\n}\n","// Escaping for the small XML documents some APIs (QuickBooks errors) return.\n\nexport function escapeXml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nexport function unescapeXml(value: string): string {\n return value\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&#(\\d+);/g, (_, code: string) => String.fromCodePoint(Number(code)))\n .replace(/&#x([0-9a-f]+);/gi, (_, code: string) => String.fromCodePoint(Number.parseInt(code, 16)))\n .replace(/&/g, \"&\");\n}\n","const encoder = new TextEncoder(), decoder = new TextDecoder(), strictDecoder = new TextDecoder(\"utf-8\", { fatal: !0 }), MAX_INT32 = 2 ** 32;\nfunction concat(...buffers) {\n const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);\n let i = 0;\n for (const buffer of buffers)\n buf.set(buffer, i), i += buffer.length;\n return buf;\n}\nfunction writeUInt32BE(buf, value, offset) {\n if (value < 0 || value >= MAX_INT32)\n throw new RangeError(`value must be >= 0 and <= ${MAX_INT32 - 1}. Received ${value}`);\n buf.set([value >>> 24, value >>> 16, value >>> 8, value & 255], offset);\n}\nfunction uint64be(value) {\n const high = Math.floor(value / MAX_INT32), low = value % MAX_INT32, buf = new Uint8Array(8);\n return writeUInt32BE(buf, high, 0), writeUInt32BE(buf, low, 4), buf;\n}\nfunction uint32be(value) {\n const buf = new Uint8Array(4);\n return writeUInt32BE(buf, value), buf;\n}\nconst NON_ASCII = /[^\\x00-\\x7f]/;\nfunction encode(string) {\n if (typeof string == \"string\" && string.length >= 128) {\n if (NON_ASCII.test(string))\n throw new TypeError(\"non-ASCII string encountered in encode()\");\n return encoder.encode(string);\n }\n const bytes = new Uint8Array(string.length);\n for (let i = 0; i < string.length; i++) {\n const code = string.charCodeAt(i);\n if (code > 127)\n throw new TypeError(\"non-ASCII string encountered in encode()\");\n bytes[i] = code;\n }\n return bytes;\n}\nfunction encodeBase64(input, url = !1) {\n if (Uint8Array.prototype.toBase64)\n return input.toBase64({ alphabet: url ? \"base64url\" : \"base64\", omitPadding: url });\n const CHUNK_SIZE = 32768, arr = [];\n for (let i = 0; i < input.length; i += CHUNK_SIZE)\n arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));\n const encoded = btoa(arr.join(\"\"));\n return url ? encoded.replace(/=/g, \"\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\") : encoded;\n}\nfunction decodeBase64(encoded, url = !1) {\n if (Uint8Array.fromBase64)\n return Uint8Array.fromBase64(encoded, { alphabet: url ? \"base64url\" : \"base64\" });\n if (url) {\n if (encoded.includes(\"+\") || encoded.includes(\"/\"))\n throw new TypeError(\"Invalid base64url\");\n encoded = encoded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n }\n const binary = atob(encoded), bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++)\n bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\nasync function digest(algorithm, data) {\n const subtleDigest = `SHA-${algorithm.slice(-3)}`;\n return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));\n}\nexport {\n concat,\n decodeBase64,\n decoder,\n digest,\n encode,\n encodeBase64,\n encoder,\n strictDecoder,\n uint32be,\n uint64be\n};\n","class JOSEError extends Error {\n static code = \"ERR_JOSE_GENERIC\";\n code = \"ERR_JOSE_GENERIC\";\n constructor(message, options) {\n super(message, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);\n }\n}\nclass JWTClaimValidationFailed extends JOSEError {\n static code = \"ERR_JWT_CLAIM_VALIDATION_FAILED\";\n code = \"ERR_JWT_CLAIM_VALIDATION_FAILED\";\n claim;\n reason;\n payload;\n constructor(message, payload, claim = \"unspecified\", reason = \"unspecified\") {\n super(message, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;\n }\n}\nclass JWTExpired extends JOSEError {\n static code = \"ERR_JWT_EXPIRED\";\n code = \"ERR_JWT_EXPIRED\";\n claim;\n reason;\n payload;\n constructor(message, payload, claim = \"unspecified\", reason = \"unspecified\") {\n super(message, { cause: { claim, reason, payload } }), this.claim = claim, this.reason = reason, this.payload = payload;\n }\n}\nclass JOSEAlgNotAllowed extends JOSEError {\n static code = \"ERR_JOSE_ALG_NOT_ALLOWED\";\n code = \"ERR_JOSE_ALG_NOT_ALLOWED\";\n}\nclass JOSENotSupported extends JOSEError {\n static code = \"ERR_JOSE_NOT_SUPPORTED\";\n code = \"ERR_JOSE_NOT_SUPPORTED\";\n}\nclass JWEDecryptionFailed extends JOSEError {\n static code = \"ERR_JWE_DECRYPTION_FAILED\";\n code = \"ERR_JWE_DECRYPTION_FAILED\";\n constructor(message = \"decryption operation failed\", options) {\n super(message, options);\n }\n}\nclass JWEInvalid extends JOSEError {\n static code = \"ERR_JWE_INVALID\";\n code = \"ERR_JWE_INVALID\";\n}\nclass JWSInvalid extends JOSEError {\n static code = \"ERR_JWS_INVALID\";\n code = \"ERR_JWS_INVALID\";\n}\nclass JWTInvalid extends JOSEError {\n static code = \"ERR_JWT_INVALID\";\n code = \"ERR_JWT_INVALID\";\n}\nclass JWKInvalid extends JOSEError {\n static code = \"ERR_JWK_INVALID\";\n code = \"ERR_JWK_INVALID\";\n}\nclass JWKSInvalid extends JOSEError {\n static code = \"ERR_JWKS_INVALID\";\n code = \"ERR_JWKS_INVALID\";\n}\nclass JWKSNoMatchingKey extends JOSEError {\n static code = \"ERR_JWKS_NO_MATCHING_KEY\";\n code = \"ERR_JWKS_NO_MATCHING_KEY\";\n constructor(message = \"no applicable key found in the JSON Web Key Set\", options) {\n super(message, options);\n }\n}\nclass JWKSMultipleMatchingKeys extends JOSEError {\n [Symbol.asyncIterator] = async function* () {\n };\n static code = \"ERR_JWKS_MULTIPLE_MATCHING_KEYS\";\n code = \"ERR_JWKS_MULTIPLE_MATCHING_KEYS\";\n constructor(message = \"multiple matching keys found in the JSON Web Key Set\", options) {\n super(message, options);\n }\n}\nclass JWKSTimeout extends JOSEError {\n static code = \"ERR_JWKS_TIMEOUT\";\n code = \"ERR_JWKS_TIMEOUT\";\n constructor(message = \"request timed out\", options) {\n super(message, options);\n }\n}\nclass JWSSignatureVerificationFailed extends JOSEError {\n static code = \"ERR_JWS_SIGNATURE_VERIFICATION_FAILED\";\n code = \"ERR_JWS_SIGNATURE_VERIFICATION_FAILED\";\n constructor(message = \"signature verification failed\", options) {\n super(message, options);\n }\n}\nexport {\n JOSEAlgNotAllowed,\n JOSEError,\n JOSENotSupported,\n JWEDecryptionFailed,\n JWEInvalid,\n JWKInvalid,\n JWKSInvalid,\n JWKSMultipleMatchingKeys,\n JWKSNoMatchingKey,\n JWKSTimeout,\n JWSInvalid,\n JWSSignatureVerificationFailed,\n JWTClaimValidationFailed,\n JWTExpired,\n JWTInvalid\n};\n","import { encoder, decoder, encodeBase64, decodeBase64 } from \"../lib/buffer_utils.js\";\nconst invalid = \"The input to be decoded is not correctly encoded.\";\nfunction decode(input) {\n try {\n return decodeBase64(typeof input == \"string\" ? input : decoder.decode(input), !0);\n } catch (cause) {\n throw new TypeError(invalid, { cause });\n }\n}\nfunction encode(input) {\n return encodeBase64(typeof input == \"string\" ? encoder.encode(input) : input, !0);\n}\nexport {\n decode,\n encode\n};\n","import { JOSENotSupported, JWSInvalid } from \"../util/errors.js\";\nimport { decode } from \"../util/base64url.js\";\nimport { encode, strictDecoder } from \"./buffer_utils.js\";\nfunction assertUint8Array(input, label) {\n if (!(input instanceof Uint8Array))\n throw new TypeError(`${label} must be an instance of Uint8Array`);\n}\nfunction isObject(input) {\n if (typeof input != \"object\" || input === null || Object.prototype.toString.call(input) !== \"[object Object]\")\n return !1;\n const prototype = Object.getPrototypeOf(input);\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\nfunction isJwkSet(input) {\n return isObject(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject);\n}\nfunction isDisjoint(...headers) {\n const parameters = /* @__PURE__ */ new Set();\n for (const header of headers)\n if (header)\n for (const parameter of Object.keys(header)) {\n if (parameters.has(parameter))\n return !1;\n parameters.add(parameter);\n }\n return !0;\n}\nfunction assertNotSet(value, name) {\n if (value !== void 0)\n throw new TypeError(`${name} can only be called once`);\n}\nfunction decodeBase64url(value, label, ErrorClass) {\n try {\n return decode(value);\n } catch {\n throw new ErrorClass(`Failed to base64url decode the ${label}`);\n }\n}\nfunction encodeBase64url(value, label, ErrorClass) {\n try {\n return encode(value);\n } catch {\n throw new ErrorClass(`The ${label} is not a valid base64url string`);\n }\n}\nfunction parseJoseHeader(b64, ErrorClass, message) {\n let parsed;\n try {\n parsed = JSON.parse(strictDecoder.decode(decode(b64)));\n } catch {\n throw new ErrorClass(message);\n }\n if (!isObject(parsed))\n throw new ErrorClass(message);\n return parsed;\n}\nconst JWS_RECOGNIZED = { __proto__: null, b64: !0 }, JWE_RECOGNIZED = { __proto__: null };\nfunction validateAlgorithms(option, algorithms) {\n if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != \"string\")))\n throw new TypeError(`\"${option}\" option must be an array of strings`);\n return algorithms === void 0 ? void 0 : new Set(algorithms);\n}\nfunction validateCritDuplicates(Err, protectedHeader) {\n const { crit } = protectedHeader ?? {};\n if (Array.isArray(crit) && new Set(crit).size !== crit.length)\n throw new Err('\"crit\" (Critical) Header Parameter MUST NOT contain duplicate values');\n}\nfunction validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {\n if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0)\n throw new Err('\"crit\" (Critical) Header Parameter MUST be integrity protected');\n if (!protectedHeader || protectedHeader.crit === void 0)\n return [];\n if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != \"string\" || input.length === 0))\n throw new Err('\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present');\n const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };\n for (const parameter of protectedHeader.crit) {\n if (!(parameter in recognized))\n throw new JOSENotSupported(`Extension Header Parameter \"${parameter}\" is not recognized`);\n if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0)\n throw new Err(`Extension Header Parameter \"${parameter}\" is missing`);\n if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0))\n throw new Err(`Extension Header Parameter \"${parameter}\" MUST be integrity protected`);\n }\n return protectedHeader.crit;\n}\nfunction validateB64(protectedHeader, extensions) {\n if (extensions.includes(\"b64\")) {\n const b64 = protectedHeader.b64;\n if (typeof b64 != \"boolean\")\n throw new JWSInvalid('The \"b64\" (base64url-encode payload) Header Parameter must be a boolean');\n return b64;\n }\n return !0;\n}\nfunction serializeJoseHeader(Err, header) {\n let serialized, parsed;\n try {\n serialized = JSON.stringify(header), parsed = JSON.parse(serialized);\n } catch (cause) {\n throw new Err(\"JOSE Header is not valid JSON\", { cause });\n }\n if (!isObject(parsed))\n throw new Err(\"JOSE Header is not a JSON object\");\n return [parsed, serialized];\n}\nexport {\n JWE_RECOGNIZED,\n JWS_RECOGNIZED,\n assertNotSet,\n assertUint8Array,\n decodeBase64url,\n encodeBase64url,\n isDisjoint,\n isJwkSet,\n isObject,\n parseJoseHeader,\n serializeJoseHeader,\n validateAlgorithms,\n validateB64,\n validateCrit,\n validateCritDuplicates\n};\n","import { isObject } from \"./validate.js\";\nimport { decode } from \"../util/base64url.js\";\nimport { JOSENotSupported } from \"../util/errors.js\";\nconst tag = (key) => key[Symbol.toStringTag], jwkMatchesOp = (entry, key, usage) => {\n const { alg } = entry;\n if (key.use !== void 0) {\n const expected = usage === \"sign\" || usage === \"verify\" ? \"sig\" : \"enc\";\n if (key.use !== expected)\n throw new TypeError(`Invalid key for this operation, its \"use\" must be \"${expected}\" when present`);\n }\n if (key.alg !== void 0 && key.alg !== alg)\n throw new TypeError(`Invalid key for this operation, its \"alg\" must be \"${alg}\" when present`);\n if (Array.isArray(key.key_ops)) {\n const expectedKeyOp = usage === \"encrypt\" || usage === \"decrypt\" ? entry.ops?.[usage === \"encrypt\" ? 0 : 1] : usage;\n if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp))\n throw new TypeError(`Invalid key for this operation, its \"key_ops\" must include \"${expectedKeyOp}\" when present`);\n }\n};\nasync function prepareKey(entry, key, usage) {\n const { alg, secret } = entry, privateKey = usage === \"decrypt\" || usage === \"sign\";\n if (secret && key instanceof Uint8Array)\n return key;\n let normalized, keyObject;\n if (isObject(key)) {\n if (normalized = normalizeJwk(key), typeof normalized.kty != \"string\")\n throw invalidKeyType(alg, key, secret);\n if (!(secret ? normalized.kty === \"oct\" && typeof normalized.k == \"string\" : normalized.kty !== \"oct\" && (privateKey ? normalized.kty === \"AKP\" && typeof normalized.priv == \"string\" || typeof normalized.d == \"string\" : normalized.d === void 0 && normalized.priv === void 0)))\n throw new TypeError(secret ? 'JSON Web Key for symmetric algorithms must have JWK \"kty\" (Key Type) equal to \"oct\" and the JWK \"k\" (Key Value) present' : `JSON Web Key for this operation must be a ${privateKey ? \"private\" : \"public\"} JWK`);\n if (jwkMatchesOp(entry, normalized, usage), normalized.kty === \"oct\")\n return decode(normalized.k);\n if (!Object.isFrozen(key)) {\n const { key_ops } = key;\n Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);\n }\n } else {\n if (!isKeyLike(key))\n throw invalidKeyType(alg, key, secret);\n const expectedType = secret ? \"secret\" : privateKey ? \"private\" : \"public\";\n if (key.type !== expectedType && (secret || [\"secret\", \"public\", \"private\"].includes(key.type)))\n throw new TypeError(`${tag(key)} instances must be of type \"${expectedType}\" for the ${alg} algorithm`);\n if (isCryptoKey(key))\n return key;\n if (keyObject = key, keyObject.type === \"secret\")\n return keyObject.export();\n }\n cache ||= /* @__PURE__ */ new WeakMap();\n const cacheKey = key;\n let cached = cache.get(cacheKey);\n if (cached?.[alg])\n return cached[alg];\n if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == \"function\") {\n const isPublic = keyObject.type === \"public\", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({ crv, asymmetricKeyType: keyObject.asymmetricKeyType }) ?? entry.subtle;\n return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);\n }\n return normalized ??= keyObject.export({ format: \"jwk\" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);\n}\nlet cache;\nconst nist = {\n __proto__: null,\n prime256v1: \"P-256\",\n secp384r1: \"P-384\",\n secp521r1: \"P-521\"\n};\nfunction assertCryptoKey(key) {\n if (!isCryptoKey(key))\n throw new Error(\"CryptoKey instance expected\");\n}\nconst isCryptoKey = (key) => {\n if (key?.[Symbol.toStringTag] === \"CryptoKey\")\n return !0;\n try {\n return key instanceof CryptoKey;\n } catch {\n return !1;\n }\n}, isKeyObject = (key) => key?.[Symbol.toStringTag] === \"KeyObject\", isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);\nfunction message(msg, actual, ...types) {\n if (types.length > 2) {\n const last = types.pop();\n msg += `one of type ${types.join(\", \")}, or ${last}.`;\n } else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;\n return actual == null ? msg += ` Received ${actual}` : typeof actual == \"function\" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == \"object\" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;\n}\nconst invalidKeyInput = (actual, ...types) => message(\"Key must be \", actual, ...types);\nfunction invalidKeyType(alg, actual, secret) {\n const types = [\"CryptoKey\", \"KeyObject\", \"JSON Web Key\"];\n return secret && types.push(\"Uint8Array\"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));\n}\nconst unusable = (name, prop = \"algorithm.name\") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);\nfunction checkUsage(key, usage) {\n if (usage && !key.usages.includes(usage))\n throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);\n}\nfunction checkModulusLength(alg, key) {\n const { modulusLength } = key.algorithm;\n if (typeof modulusLength != \"number\" || modulusLength < 2048)\n throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);\n}\nfunction checkCryptoKey(key, expected, usage) {\n const algorithm = key.algorithm;\n if (algorithm.name !== expected.name)\n throw unusable(expected.name);\n if (expected.hash && algorithm.hash?.name !== expected.hash)\n throw unusable(expected.hash, \"algorithm.hash\");\n if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve)\n throw unusable(expected.namedCurve, \"algorithm.namedCurve\");\n if (expected.length !== void 0 && algorithm.length !== expected.length)\n throw unusable(expected.length, \"algorithm.length\");\n checkUsage(key, usage);\n}\nfunction snapshotJwk(jwk) {\n return { __proto__: null, ...jwk };\n}\nfunction normalizeJwk(jwk) {\n const normalized = snapshotJwk(jwk);\n if (normalized.ext !== void 0 && typeof normalized.ext != \"boolean\")\n throw new TypeError('\"ext\" (Extractable) Parameter must be a boolean');\n if (normalized.key_ops !== void 0) {\n const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;\n if (!keyOps || keyOps.some((operation) => typeof operation != \"string\") || new Set(keyOps).size !== keyOps.length)\n throw new TypeError('\"key_ops\" (Key Operations) Parameter must be an array of unique strings');\n normalized.key_ops = keyOps;\n }\n return normalized;\n}\nfunction validateExtractableOption(extractable) {\n if (extractable !== void 0 && typeof extractable != \"boolean\")\n throw new TypeError('\"extractable\" option must be a boolean');\n return extractable;\n}\nasync function jwkToKey(entry, jwk, extractable) {\n if (!entry.kty.includes(jwk.kty))\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = { ...jwk, ext: extractable ?? jwk.ext };\n return keyData.kty !== \"AKP\" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey(\"jwk\", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);\n}\nasync function rawKey(key, expected, usage, extractable = !1) {\n return key instanceof Uint8Array && (key = await crypto.subtle.importKey(\"raw\", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;\n}\nexport {\n assertCryptoKey,\n checkCryptoKey,\n checkModulusLength,\n checkUsage,\n invalidKeyInput,\n isCryptoKey,\n isKeyLike,\n isKeyObject,\n jwkToKey,\n normalizeJwk,\n prepareKey,\n rawKey,\n snapshotJwk,\n validateExtractableOption\n};\n","function table(entries) {\n const out = { __proto__: null };\n for (const alg in entries)\n out[alg] = { ...entries[alg], alg };\n return out;\n}\nexport {\n table\n};\n","import { JOSENotSupported } from \"../util/errors.js\";\nimport { table } from \"./key_descriptor.js\";\nconst wrap = [\n [\"encrypt\", \"wrapKey\"],\n [\"decrypt\", \"unwrapKey\"]\n], derive = [[], [\"deriveBits\"]], none = [[], []];\nfunction rsaes(bits) {\n return {\n kty: [\"RSA\"],\n mode: \"key-encryption\",\n subtle: { name: \"RSA-OAEP\", hash: `SHA-${bits}` },\n usages: wrap,\n ops: [\"wrapKey\", \"unwrapKey\"]\n };\n}\nfunction ecdh(mode) {\n return {\n kty: [\"EC\", \"OKP\"],\n mode,\n subtle: { name: \"ECDH\" },\n resolve: ({ kty, crv, asymmetricKeyType }) => {\n if (crv === \"X25519\" || asymmetricKeyType === \"x25519\")\n return { name: \"X25519\" };\n if (kty === \"OKP\")\n throw new JOSENotSupported('Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value');\n return { name: \"ECDH\", namedCurve: crv };\n },\n usages: derive,\n ops: [void 0, \"deriveBits\"]\n };\n}\nfunction aeskw(bits, gcm = !1) {\n return {\n kty: [\"oct\"],\n mode: \"key-wrapping\",\n secret: !0,\n subtle: { name: gcm ? \"AES-GCM\" : \"AES-KW\", length: bits },\n usages: none,\n ops: gcm ? [\"encrypt\", \"decrypt\"] : [\"wrapKey\", \"unwrapKey\"]\n };\n}\nfunction pbes2() {\n return {\n kty: [\"oct\"],\n mode: \"key-wrapping\",\n secret: !0,\n subtle: { name: \"PBKDF2\" },\n usages: none,\n ops: [\"deriveBits\", \"deriveBits\"]\n };\n}\nconst JWE = table({\n dir: {\n kty: [\"oct\"],\n mode: \"direct-encryption\",\n secret: !0,\n subtle: { name: \"AES-GCM\" },\n usages: none,\n ops: [\"encrypt\", \"decrypt\"]\n },\n \"RSA-OAEP\": rsaes(1),\n \"RSA-OAEP-256\": rsaes(256),\n \"RSA-OAEP-384\": rsaes(384),\n \"RSA-OAEP-512\": rsaes(512),\n \"ECDH-ES\": ecdh(\"direct-key-agreement\"),\n \"ECDH-ES+A128KW\": ecdh(\"key-agreement-with-key-wrapping\"),\n \"ECDH-ES+A192KW\": ecdh(\"key-agreement-with-key-wrapping\"),\n \"ECDH-ES+A256KW\": ecdh(\"key-agreement-with-key-wrapping\"),\n A128KW: aeskw(128),\n A192KW: aeskw(192),\n A256KW: aeskw(256),\n A128GCMKW: aeskw(128, !0),\n A192GCMKW: aeskw(192, !0),\n A256GCMKW: aeskw(256, !0),\n \"PBES2-HS256+A128KW\": pbes2(),\n \"PBES2-HS384+A192KW\": pbes2(),\n \"PBES2-HS512+A256KW\": pbes2()\n}), contentOps = [\"encrypt\", \"decrypt\"];\nfunction contentEncryption(bits, cbc = !1) {\n return {\n kty: [\"oct\"],\n secret: !0,\n subtle: { name: cbc ? \"AES-CBC\" : \"AES-GCM\", length: bits },\n usages: none,\n ops: contentOps,\n cekBits: bits,\n ivBits: cbc ? 128 : 96,\n cbc\n };\n}\nconst ENC = table({\n A128GCM: contentEncryption(128),\n A192GCM: contentEncryption(192),\n A256GCM: contentEncryption(256),\n \"A128CBC-HS256\": contentEncryption(256, !0),\n \"A192CBC-HS384\": contentEncryption(384, !0),\n \"A256CBC-HS512\": contentEncryption(512, !0)\n});\nfunction unsupported(parameter, name) {\n throw new JOSENotSupported(`Invalid or unsupported \"${parameter}\" (JWE ${name}) header value`);\n}\nfunction jweAlgorithm(alg) {\n return (typeof alg == \"string\" ? JWE[alg] : void 0) ?? unsupported(\"alg\", \"Algorithm\");\n}\nfunction isJWECEKTransport(algorithm) {\n return algorithm.mode === \"key-wrapping\" || algorithm.mode === \"key-encryption\" || algorithm.mode === \"key-agreement-with-key-wrapping\";\n}\nfunction jweEncryption(enc) {\n return (typeof enc == \"string\" ? ENC[enc] : void 0) ?? unsupported(\"enc\", \"Encryption Algorithm\");\n}\nexport {\n JWE,\n isJWECEKTransport,\n jweAlgorithm,\n jweEncryption\n};\n","import { JOSENotSupported } from \"../util/errors.js\";\nimport { table } from \"./key_descriptor.js\";\nconst sig = [[\"verify\"], [\"sign\"]];\nfunction hmac(bits) {\n const subtle = { name: \"HMAC\", hash: `SHA-${bits}` };\n return { kty: [\"oct\"], secret: !0, subtle, signing: subtle, usages: sig };\n}\nfunction rsa(bits, saltLength) {\n const subtle = { name: saltLength ? \"RSA-PSS\" : \"RSASSA-PKCS1-v1_5\", hash: `SHA-${bits}` };\n return {\n kty: [\"RSA\"],\n subtle,\n signing: saltLength ? { ...subtle, saltLength } : subtle,\n usages: sig,\n minRsaBits: 2048\n };\n}\nfunction ecdsa(crv, bits) {\n return {\n kty: [\"EC\"],\n crv,\n subtle: { name: \"ECDSA\", namedCurve: crv },\n signing: { name: \"ECDSA\", hash: `SHA-${bits}` },\n usages: sig\n };\n}\nfunction eddsa() {\n const subtle = { name: \"Ed25519\" };\n return {\n kty: [\"OKP\"],\n crv: \"Ed25519\",\n subtle,\n signing: subtle,\n usages: sig\n };\n}\nfunction mldsa(bits) {\n const subtle = { name: `ML-DSA-${bits}` };\n return {\n kty: [\"AKP\"],\n subtle,\n signing: subtle,\n usages: sig\n };\n}\nconst JWS = table({\n HS256: hmac(256),\n HS384: hmac(384),\n HS512: hmac(512),\n RS256: rsa(256),\n RS384: rsa(384),\n RS512: rsa(512),\n PS256: rsa(256, 32),\n PS384: rsa(384, 48),\n PS512: rsa(512, 64),\n ES256: ecdsa(\"P-256\", 256),\n ES384: ecdsa(\"P-384\", 384),\n ES512: ecdsa(\"P-521\", 512),\n EdDSA: eddsa(),\n Ed25519: eddsa(),\n \"ML-DSA-44\": mldsa(44),\n \"ML-DSA-65\": mldsa(65),\n \"ML-DSA-87\": mldsa(87)\n});\nfunction jwsAlgorithm(alg) {\n const entry = typeof alg == \"string\" ? JWS[alg] : void 0;\n if (!entry)\n throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);\n return entry;\n}\nexport {\n JWS,\n jwsAlgorithm\n};\n","import { jwsAlgorithm } from \"./jws_algorithms.js\";\nimport { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from \"../util/errors.js\";\nimport { concat, decoder, encoder, encode } from \"./buffer_utils.js\";\nimport { decodeBase64url, encodeBase64url, parseJoseHeader, isDisjoint, isObject, validateB64, validateCrit, validateAlgorithms, JWS_RECOGNIZED } from \"./validate.js\";\nimport { prepareKey, rawKey, checkModulusLength } from \"./key.js\";\nfunction snapshotJws(jws, sharedPayload) {\n const encodedProtected = jws.protected, inputHeader = jws.header, header = isObject(inputHeader) ? { ...inputHeader } : inputHeader;\n let payload = sharedPayload ? sharedPayload[0] : jws.payload;\n !sharedPayload && payload instanceof Uint8Array && (payload = new Uint8Array(payload));\n const signature = jws.signature, snapshot = { payload, signature };\n if (encodedProtected !== void 0 && (snapshot.protected = encodedProtected), inputHeader !== void 0 && (snapshot.header = header), encodedProtected === void 0 && header === void 0)\n throw new JWSInvalid('Flattened JWS must have either of the \"protected\" or \"header\" members');\n if (encodedProtected !== void 0 && typeof encodedProtected != \"string\")\n throw new JWSInvalid(\"JWS Protected Header incorrect type\");\n if (payload === void 0)\n throw new JWSInvalid(\"JWS Payload missing\");\n if (typeof signature != \"string\")\n throw new JWSInvalid(\"JWS Signature missing or incorrect type\");\n if (header !== void 0 && !isObject(header))\n throw new JWSInvalid(\"JWS Unprotected Header incorrect type\");\n return snapshot;\n}\nfunction prepareVerify(options) {\n return [options && validateAlgorithms(\"algorithms\", options.algorithms), options?.crit];\n}\nfunction parseProtectedHeader(encodedProtected) {\n return encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, \"JWS Protected Header is invalid\");\n}\nfunction encodeJsonUnencodedPayload(payload) {\n const invalid = /[\\p{Cs}\\p{Cn}]/u.exec(payload)?.[0];\n if (invalid !== void 0)\n throw new JWSInvalid(/\\p{Cs}/u.test(invalid) ? \"JWS Payload must be a well-formed Unicode string\" : \"JWS Payload must not contain unassigned Unicode code points\");\n return encoder.encode(payload);\n}\nfunction encodeCompactUnencodedPayload(payload) {\n try {\n return encode(payload);\n } catch {\n throw new JWSInvalid(\"JWS Compact Serialization payload must use only ASCII characters\");\n }\n}\nasync function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {\n const { protected: encodedProtected, header, payload: inputPayload } = jws, parsedProt = parsedProtected ?? parseProtectedHeader(encodedProtected);\n if (!isDisjoint(parsedProt, header))\n throw new JWSInvalid(\"JWS Protected and JWS Unprotected Header Parameter names must be disjoint\");\n const joseHeader = { ...parsedProt, ...header }, b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader)), { alg } = joseHeader;\n if (typeof alg != \"string\" || !alg)\n throw new JWSInvalid('JWS \"alg\" (Algorithm) Header Parameter missing or invalid');\n if (shared[0] && !shared[0].has(alg))\n throw new JOSEAlgNotAllowed('\"alg\" (Algorithm) Header Parameter value not allowed');\n if (b64) {\n if (typeof inputPayload != \"string\")\n throw new JWSInvalid(\"JWS Payload must be a string\");\n } else if (typeof inputPayload != \"string\" && !(inputPayload instanceof Uint8Array))\n throw new JWSInvalid(\"JWS Payload must be a string or an Uint8Array instance\");\n const signingPayload = b64 || typeof inputPayload != \"string\" ? inputPayload : encodeUnencodedPayload(inputPayload);\n let resolvedKey = !1;\n typeof key == \"function\" && (key = await key(parsedProt, jws), resolvedKey = !0);\n const entry = jwsAlgorithm(alg), data = concat(encodedProtected !== void 0 ? encode(encodedProtected) : new Uint8Array(), encode(\".\"), typeof signingPayload == \"string\" ? shared[2] ??= encodeBase64url(signingPayload, \"payload\", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, \"signature\", JWSInvalid), k = await prepareKey(entry, key, \"verify\"), cryptoKey = await rawKey(k, entry.subtle, \"verify\");\n entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);\n let verified = !1;\n try {\n verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);\n } catch {\n }\n if (!verified)\n throw new JWSSignatureVerificationFailed();\n const result = { payload: typeof signingPayload == \"string\" ? decodeBase64url(signingPayload, \"payload\", JWSInvalid) : signingPayload };\n return encodedProtected !== void 0 && (result.protectedHeader = parsedProt), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? [{ ...result, key: k }, b64] : [result, b64];\n}\nasync function verifyCompact(jws, shared, key) {\n if (jws instanceof Uint8Array && (jws = decoder.decode(jws)), typeof jws != \"string\")\n throw new JWSInvalid(\"Compact JWS must be a string or Uint8Array\");\n const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(\".\");\n if (length !== 3)\n throw new JWSInvalid(\"Invalid Compact JWS\");\n return verifySignature({ payload, protected: protectedHeader, signature }, shared, key, encodeCompactUnencodedPayload);\n}\nexport {\n encodeJsonUnencodedPayload,\n parseProtectedHeader,\n prepareVerify,\n snapshotJws,\n verifyCompact,\n verifySignature\n};\n","import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from \"../util/errors.js\";\nimport { encoder, strictDecoder } from \"./buffer_utils.js\";\nimport { isObject } from \"./validate.js\";\nconst epoch = (date) => Math.floor(date.getTime() / 1e3), multipliers = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n w: 604800,\n y: 31557600\n}, REGEX = /^(\\+|\\-)? ?(\\d+|\\d+\\.\\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i, checkFailed = \"check_failed\";\nfunction invalidDuration() {\n throw new TypeError(\"Invalid time period format\");\n}\nfunction secs(str) {\n typeof str != \"string\" && invalidDuration();\n const matched = REGEX.exec(str);\n (!matched || matched[4] && matched[1]) && invalidDuration();\n const value = parseFloat(matched[2]), numericDate2 = Math.round(value * multipliers[matched[3][0].toLowerCase()]);\n return Number.isFinite(numericDate2) || invalidDuration(), matched[1] === \"-\" || matched[4] === \"ago\" ? -numericDate2 : numericDate2;\n}\nfunction validateInput(label, input) {\n if (!Number.isFinite(input))\n throw new TypeError(`Invalid ${label} input`);\n return input;\n}\nfunction validateStringClaim(claim, value) {\n if (typeof value != \"string\")\n throw new TypeError(`\"${claim}\" claim must be a string`);\n}\nfunction validateAudienceClaim(value) {\n if (typeof value != \"string\" && (!Array.isArray(value) || Array.from(value).some((member) => typeof member != \"string\")))\n throw new TypeError('\"aud\" claim must be a string or an array of strings');\n}\nfunction numericDate(value, label) {\n return typeof value == \"number\" ? validateInput(label, value) : value instanceof Date ? validateInput(label, epoch(value)) : epoch(/* @__PURE__ */ new Date()) + secs(value);\n}\nconst normalizeTyp = (value) => {\n const normalized = value.toLowerCase();\n return value.includes(\"/\") ? normalized : `application/${normalized}`;\n}, checkAudiencePresence = (audPayload, audOption) => typeof audPayload == \"string\" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : !1;\nfunction validateNumericDate(payload, claim, required = !1) {\n const value = payload[claim];\n if (!(value === void 0 && !required)) {\n if (typeof value != \"number\")\n throw new JWTClaimValidationFailed(`\"${claim}\" claim must be a number`, payload, claim, \"invalid\");\n return value;\n }\n}\nfunction unexpectedClaim(payload, claim) {\n throw new JWTClaimValidationFailed(`unexpected \"${claim}\" claim value`, payload, claim, checkFailed);\n}\nfunction validateClaimsSet(protectedHeader, encodedPayload, options = {}) {\n let payload;\n try {\n payload = JSON.parse(strictDecoder.decode(encodedPayload));\n } catch {\n }\n if (!isObject(payload))\n throw new JWTInvalid(\"JWT Claims Set must be a top-level JSON object\");\n const { typ } = options;\n if (typ !== void 0 && (typeof protectedHeader.typ != \"string\" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ)))\n throw new JWTClaimValidationFailed('unexpected \"typ\" JWT header value', payload, \"typ\", checkFailed);\n const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];\n maxTokenAge !== void 0 && presenceCheck.push(\"iat\"), audience !== void 0 && presenceCheck.push(\"aud\"), subject !== void 0 && presenceCheck.push(\"sub\"), issuer !== void 0 && presenceCheck.push(\"iss\");\n for (const claim of new Set(presenceCheck.reverse()))\n if (!Object.hasOwn(payload, claim))\n throw new JWTClaimValidationFailed(`missing required \"${claim}\" claim`, payload, claim, \"missing\");\n issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss) && unexpectedClaim(payload, \"iss\"), subject !== void 0 && payload.sub !== subject && unexpectedClaim(payload, \"sub\"), audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience == \"string\" ? [audience] : audience) && unexpectedClaim(payload, \"aud\");\n const { clockTolerance } = options;\n let tolerance = 0;\n if (typeof clockTolerance == \"string\")\n tolerance = secs(clockTolerance);\n else if (clockTolerance !== void 0) {\n if (typeof clockTolerance != \"number\")\n throw new TypeError(\"Invalid clockTolerance option type\");\n tolerance = clockTolerance;\n }\n validateInput(\"clockTolerance option\", tolerance);\n const { currentDate } = options, now = validateInput(\"currentDate option\", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(payload, \"iat\", maxTokenAge !== void 0), nbf = validateNumericDate(payload, \"nbf\");\n if (nbf !== void 0 && nbf > now + tolerance)\n throw new JWTClaimValidationFailed('\"nbf\" claim timestamp check failed', payload, \"nbf\", checkFailed);\n const exp = validateNumericDate(payload, \"exp\");\n if (exp !== void 0 && exp <= now - tolerance)\n throw new JWTExpired('\"exp\" claim timestamp check failed', payload, \"exp\", checkFailed);\n if (maxTokenAge !== void 0) {\n const age = now - iat, max = validateInput(\"maxTokenAge option\", typeof maxTokenAge == \"number\" ? maxTokenAge : secs(maxTokenAge));\n if (age - tolerance > max)\n throw new JWTExpired('\"iat\" claim timestamp check failed (too far in the past)', payload, \"iat\", checkFailed);\n if (age < -tolerance)\n throw new JWTClaimValidationFailed('\"iat\" claim timestamp check failed (it should be in the past)', payload, \"iat\", checkFailed);\n }\n return payload;\n}\nlet producerPayloads;\nfunction producerPayload(producer) {\n return producerPayloads.get(producer);\n}\nfunction jwtData(producer) {\n const payload = producerPayload(producer);\n for (const claim of [\"iat\", \"nbf\", \"exp\"]) {\n const value = payload[claim];\n if (typeof value == \"number\" && !Number.isFinite(value))\n throw new TypeError(`\"${claim}\" claim must be a finite number`);\n }\n return encoder.encode(JSON.stringify(payload));\n}\nfunction jwtClaim(producer, claim) {\n return producerPayload(producer)[claim];\n}\nclass JWTClaimsBuilder {\n constructor(payload = {}) {\n if (!isObject(payload))\n throw new TypeError(\"JWT Claims Set MUST be an object\");\n (producerPayloads ||= /* @__PURE__ */ new WeakMap()).set(this, structuredClone(payload));\n }\n setIssuer(value) {\n return validateStringClaim(\"iss\", value), producerPayload(this).iss = value, this;\n }\n setSubject(value) {\n return validateStringClaim(\"sub\", value), producerPayload(this).sub = value, this;\n }\n setAudience(value) {\n return validateAudienceClaim(value), producerPayload(this).aud = value, this;\n }\n setJti(value) {\n return validateStringClaim(\"jti\", value), producerPayload(this).jti = value, this;\n }\n setNotBefore(value) {\n return producerPayload(this).nbf = numericDate(value, \"setNotBefore\"), this;\n }\n setExpirationTime(value) {\n return producerPayload(this).exp = numericDate(value, \"setExpirationTime\"), this;\n }\n setIssuedAt(value) {\n const payload = producerPayload(this);\n return value === void 0 ? payload.iat = epoch(/* @__PURE__ */ new Date()) : typeof value == \"string\" ? payload.iat = validateInput(\"setIssuedAt\", epoch(/* @__PURE__ */ new Date()) + secs(value)) : payload.iat = numericDate(value, \"setIssuedAt\"), this;\n }\n}\nexport {\n JWTClaimsBuilder,\n jwtClaim,\n jwtData,\n secs,\n validateClaimsSet\n};\n","import { prepareVerify, verifyCompact } from \"../lib/jws_verify.js\";\nimport { validateClaimsSet } from \"../lib/jwt_claims_set.js\";\nimport { JWTInvalid } from \"../util/errors.js\";\nasync function jwtVerify(jwt, key, options) {\n const [verified, b64] = await verifyCompact(jwt, prepareVerify(options), key);\n if (!b64)\n throw new JWTInvalid(\"JWTs MUST NOT use unencoded payload\");\n const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);\n return { ...verified, payload };\n}\nexport {\n jwtVerify\n};\n","import { encode as b64u } from \"../util/base64url.js\";\nimport { jwsAlgorithm } from \"./jws_algorithms.js\";\nimport { isDisjoint, serializeJoseHeader, validateB64, validateCrit, validateCritDuplicates, JWS_RECOGNIZED } from \"./validate.js\";\nimport { JWSInvalid } from \"../util/errors.js\";\nimport { concat, encode, encoder } from \"./buffer_utils.js\";\nimport { prepareKey, rawKey, checkModulusLength } from \"./key.js\";\nasync function createSignature(input, key, rejectUnencoded) {\n let [payload, protectedHeader, unprotectedHeader, crit] = input, protectedHeaderString = \"\";\n if (protectedHeader !== void 0) {\n const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);\n protectedHeader = normalized[0], protectedHeaderString = b64u(normalized[1]);\n }\n if (unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0]), !protectedHeader && !unprotectedHeader)\n throw new JWSInvalid(\"either setProtectedHeader or setUnprotectedHeader must be called before #sign()\");\n if (!isDisjoint(protectedHeader, unprotectedHeader))\n throw new JWSInvalid(\"JWS Protected and JWS Unprotected Header Parameter names must be disjoint\");\n const joseHeader = { ...protectedHeader, ...unprotectedHeader };\n validateCritDuplicates(JWSInvalid, protectedHeader);\n const b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));\n b64 || rejectUnencoded?.();\n const { alg } = joseHeader;\n if (typeof alg != \"string\" || !alg)\n throw new JWSInvalid('JWS \"alg\" (Algorithm) Header Parameter missing or invalid');\n const entry = jwsAlgorithm(alg);\n let payloadS = \"\", payloadB = payload, data;\n if (b64) {\n const encoded = input[4];\n encoded ? (payloadS = encoded[0] ??= b64u(payload), payloadB = encoded[1] ??= encode(payloadS)) : (payloadS = b64u(payload), data = encoder.encode(`${protectedHeaderString}.${payloadS}`));\n }\n data ??= concat(encode(protectedHeaderString), encode(\".\"), payloadB);\n const k = await rawKey(await prepareKey(entry, key, \"sign\"), entry.subtle, \"sign\");\n entry.minRsaBits && checkModulusLength(entry.alg, k);\n const jws = {\n signature: b64u(new Uint8Array(await crypto.subtle.sign(entry.signing, k, data))),\n payload: payloadS\n };\n return protectedHeader && (jws.protected = protectedHeaderString), unprotectedHeader && (jws.header = unprotectedHeader), [jws, b64];\n}\nasync function createCompactSignature(payload, protectedHeader, crit, key, rejectUnencoded) {\n const [jws] = await createSignature([payload, protectedHeader, void 0, crit], key, rejectUnencoded);\n return `${jws.protected}.${jws.payload}.${jws.signature}`;\n}\nexport {\n createCompactSignature,\n createSignature\n};\n","import { createCompactSignature } from \"../lib/jws_sign.js\";\nimport { JWTInvalid } from \"../util/errors.js\";\nimport { JWTClaimsBuilder, jwtData } from \"../lib/jwt_claims_set.js\";\nimport { assertNotSet } from \"../lib/validate.js\";\nconst SignJWT_base = JWTClaimsBuilder;\nclass SignJWT extends SignJWT_base {\n #protectedHeader;\n setProtectedHeader(protectedHeader) {\n return assertNotSet(this.#protectedHeader, \"setProtectedHeader\"), this.#protectedHeader = protectedHeader, this;\n }\n async sign(key, options) {\n return createCompactSignature(jwtData(this), this.#protectedHeader, options?.crit, key, () => {\n throw new JWTInvalid(\"JWTs MUST NOT use unencoded payload\");\n });\n }\n}\nexport {\n SignJWT\n};\n","import { JOSENotSupported } from \"../util/errors.js\";\nimport { JWS } from \"./jws_algorithms.js\";\nimport { JWE } from \"./jwe_algorithms.js\";\nconst algArgument = '\"alg\" (Algorithm)';\nfunction unsupportedAlg(source = 'JWK \"alg\" (Algorithm) Parameter') {\n throw new JOSENotSupported(`Invalid or unsupported ${source} value`);\n}\nfunction keyAlgorithm(alg, source) {\n return (typeof alg == \"string\" ? JWS[alg] ?? JWE[alg] : void 0) ?? unsupportedAlg(source);\n}\nexport {\n algArgument,\n keyAlgorithm,\n unsupportedAlg\n};\n","import { invalidKeyInput, isCryptoKey, isKeyObject, validateExtractableOption } from \"./key.js\";\nimport { encodeBase64, decodeBase64 } from \"./buffer_utils.js\";\nimport { JOSENotSupported } from \"../util/errors.js\";\nimport { keyAlgorithm, unsupportedAlg, algArgument } from \"./key_algorithm.js\";\nconst formatPEM = (b64, descriptor) => {\n const newlined = (b64.match(/.{1,64}/g) || []).join(`\n`);\n return `-----BEGIN ${descriptor}-----\n${newlined}\n-----END ${descriptor}-----`;\n}, genericExport = async (keyType, keyFormat, key) => {\n if (isKeyObject(key)) {\n if (key.type !== keyType)\n throw new TypeError(`key is not a ${keyType} key`);\n return key.export({ format: \"pem\", type: keyFormat });\n }\n if (!isCryptoKey(key))\n throw new TypeError(invalidKeyInput(key, \"CryptoKey\", \"KeyObject\"));\n if (!key.extractable)\n throw new TypeError(\"CryptoKey is not extractable\");\n if (key.type !== keyType)\n throw new TypeError(`key is not a ${keyType} key`);\n return formatPEM(encodeBase64(new Uint8Array(await crypto.subtle.exportKey(keyFormat, key))), `${keyType.toUpperCase()} KEY`);\n}, toSPKI = (key) => genericExport(\"public\", \"spki\", key), toPKCS8 = (key) => genericExport(\"private\", \"pkcs8\", key), bytesEqual = (a, b) => {\n if (a.byteLength !== b.length)\n return !1;\n for (let i = 0; i < a.byteLength; i++)\n if (a[i] !== b[i])\n return !1;\n return !0;\n}, createASN1State = (data) => ({ data, pos: 0 }), readByte = (state) => {\n const byte = state.data[state.pos++];\n if (byte === void 0)\n throw new Error(\"Unexpected end of ASN.1 input\");\n return byte;\n}, parseLength = (state) => {\n const first = readByte(state);\n if (first & 128) {\n const lengthOfLen = first & 127;\n let length = 0;\n for (let i = 0; i < lengthOfLen; i++)\n length = length << 8 | readByte(state);\n return length;\n }\n return first;\n}, skipElement = (state, count = 1) => {\n for (; count-- > 0; ) {\n state.pos++;\n const length = parseLength(state);\n state.pos += length;\n }\n}, expectTag = (state, expectedTag, errorMessage) => {\n if (readByte(state) !== expectedTag)\n throw new Error(errorMessage);\n}, getSubarray = (state, length) => {\n if (length < 0 || state.pos + length > state.data.length)\n throw new Error(\"Unexpected end of ASN.1 input\");\n const result = state.data.subarray(state.pos, state.pos + length);\n return state.pos += length, result;\n}, parseAlgorithmOID = (state) => {\n expectTag(state, 6, \"Expected algorithm OID\");\n const oidLen = parseLength(state);\n return getSubarray(state, oidLen);\n};\nfunction parseKeyHeader(state, keyFormat) {\n if (expectTag(state, 48, `Invalid ${keyFormat === \"spki\" ? \"SPKI\" : \"PKCS#8\"} structure`), parseLength(state), keyFormat === \"pkcs8\") {\n expectTag(state, 2, \"Expected version field\");\n const length = parseLength(state);\n state.pos += length;\n }\n expectTag(state, 48, \"Expected algorithm identifier\"), parseLength(state);\n}\nconst parseECAlgorithmIdentifier = (state) => {\n const algOid = parseAlgorithmOID(state);\n if (bytesEqual(algOid, [43, 101, 110]))\n return \"X25519\";\n if (!bytesEqual(algOid, [42, 134, 72, 206, 61, 2, 1]))\n throw new Error(\"Unsupported key algorithm\");\n expectTag(state, 6, \"Expected curve OID\");\n const curveOidLen = parseLength(state), curveOid = getSubarray(state, curveOidLen);\n if (bytesEqual(curveOid, [42, 134, 72, 206, 61, 3, 1, 7]))\n return \"P-256\";\n if (bytesEqual(curveOid, [43, 129, 4, 0, 34]))\n return \"P-384\";\n if (bytesEqual(curveOid, [43, 129, 4, 0, 35]))\n return \"P-521\";\n throw new Error(\"Unsupported named curve\");\n}, genericImport = async (keyFormat, keyData, alg, options) => {\n const extractable = validateExtractableOption(options?.extractable), entry = keyAlgorithm(alg, algArgument);\n entry.secret && unsupportedAlg(algArgument);\n const isPublic = keyFormat === \"spki\";\n let algorithm;\n if (entry.resolve)\n try {\n const state = createASN1State(keyData);\n parseKeyHeader(state, keyFormat), algorithm = entry.resolve({ crv: parseECAlgorithmIdentifier(state) });\n } catch {\n throw new JOSENotSupported(\"Invalid or unsupported key format\");\n }\n else\n algorithm = entry.subtle;\n return crypto.subtle.importKey(keyFormat, keyData, algorithm, extractable ?? isPublic, entry.usages[isPublic ? 0 : 1]);\n}, processPEMData = (pem, pattern) => decodeBase64(pem.replace(pattern, \"\")), fromPKCS8 = (pem, alg, options) => {\n const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PRIVATE KEY-----|\\s)/g);\n return genericImport(\"pkcs8\", keyData, alg, options);\n}, fromSPKI = (pem, alg, options) => {\n const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PUBLIC KEY-----|\\s)/g);\n return genericImport(\"spki\", keyData, alg, options);\n};\nfunction spkiFromX509(buf) {\n const state = createASN1State(buf);\n expectTag(state, 48, \"Invalid certificate structure\");\n const certificateLength = parseLength(state);\n if (certificateLength < 0 || state.pos + certificateLength > state.data.length)\n throw new Error(\"Unexpected end of ASN.1 input\");\n expectTag(state, 48, \"Invalid tbsCertificate structure\"), parseLength(state), buf[state.pos] === 160 ? skipElement(state, 6) : skipElement(state, 5);\n const spkiStart = state.pos;\n expectTag(state, 48, \"Invalid SPKI structure\");\n const spkiContentLen = parseLength(state);\n return buf.subarray(spkiStart, spkiStart + spkiContentLen + (state.pos - spkiStart));\n}\nconst fromX509 = (pem, alg, options) => {\n let spki;\n try {\n const certificate = processPEMData(pem, /(?:-----(?:BEGIN|END) CERTIFICATE-----|\\s)/g);\n spki = spkiFromX509(certificate);\n } catch (cause) {\n throw new TypeError(\"Failed to parse the X.509 certificate\", { cause });\n }\n return genericImport(\"spki\", spki, alg, options);\n};\nexport {\n fromPKCS8,\n fromSPKI,\n fromX509,\n toPKCS8,\n toSPKI\n};\n","import { decode as decodeBase64URL } from \"../util/base64url.js\";\nimport { fromSPKI, fromPKCS8, fromX509 } from \"../lib/asn1.js\";\nimport { jwkToKey, validateExtractableOption, normalizeJwk } from \"../lib/key.js\";\nimport { keyAlgorithm } from \"../lib/key_algorithm.js\";\nimport { JOSENotSupported } from \"../util/errors.js\";\nimport { isObject } from \"../lib/validate.js\";\nasync function importSPKI(spki, alg, options) {\n if (typeof spki != \"string\" || spki.indexOf(\"-----BEGIN PUBLIC KEY-----\") !== 0)\n throw new TypeError('\"spki\" must be SPKI formatted string');\n return fromSPKI(spki, alg, options);\n}\nasync function importX509(x509, alg, options) {\n if (typeof x509 != \"string\" || x509.indexOf(\"-----BEGIN CERTIFICATE-----\") !== 0)\n throw new TypeError('\"x509\" must be X.509 formatted string');\n return fromX509(x509, alg, options);\n}\nasync function importPKCS8(pkcs8, alg, options) {\n if (typeof pkcs8 != \"string\" || pkcs8.indexOf(\"-----BEGIN PRIVATE KEY-----\") !== 0)\n throw new TypeError('\"pkcs8\" must be PKCS#8 formatted string');\n return fromPKCS8(pkcs8, alg, options);\n}\nasync function importJWK(jwk, alg, options) {\n if (!isObject(jwk))\n throw new TypeError(\"JWK must be an object\");\n const normalized = normalizeJwk(jwk), extractable = validateExtractableOption(options?.extractable), { alg: jwkAlg } = normalized;\n if (alg ??= jwkAlg, normalized.kty !== \"oct\" && !alg)\n throw new TypeError('\"alg\" argument is required when \"jwk.alg\" is not present');\n switch (normalized.kty) {\n case \"oct\":\n if (typeof normalized.k != \"string\")\n throw new TypeError('missing \"k\" (Key Value) Parameter value');\n return decodeBase64URL(normalized.k);\n case \"AKP\": {\n if (typeof jwkAlg != \"string\" || !jwkAlg)\n throw new TypeError('missing \"alg\" (Algorithm) Parameter value');\n if (alg !== jwkAlg)\n throw new TypeError(\"JWK alg and alg option value mismatch\");\n return jwkToKey(keyAlgorithm(alg), normalized, extractable);\n }\n case \"RSA\":\n case \"EC\":\n case \"OKP\":\n return jwkToKey(keyAlgorithm(alg), normalized, extractable);\n default:\n throw new JOSENotSupported('Unsupported \"kty\" (Key Type) Parameter value');\n }\n}\nexport {\n importJWK,\n importPKCS8,\n importSPKI,\n importX509\n};\n","import { parseJoseHeader } from \"../lib/validate.js\";\nfunction decodeProtectedHeader(token) {\n let protectedB64u;\n if (typeof token == \"string\") {\n const parts = token.split(\".\");\n (parts.length === 3 || parts.length === 5) && ([protectedB64u] = parts);\n } else if (typeof token == \"object\" && token)\n if (\"protected\" in token)\n protectedB64u = token.protected;\n else\n throw new TypeError(\"Token does not contain a Protected Header\");\n const invalid = \"Invalid Token or Protected Header formatting\";\n if (typeof protectedB64u != \"string\" || !protectedB64u)\n throw new TypeError(invalid);\n return parseJoseHeader(protectedB64u, TypeError, invalid);\n}\nexport {\n decodeProtectedHeader\n};\n","import { decode as b64u } from \"./base64url.js\";\nimport { strictDecoder } from \"../lib/buffer_utils.js\";\nimport { isObject } from \"../lib/validate.js\";\nimport { JWTInvalid } from \"./errors.js\";\nfunction decodeJwt(jwt) {\n if (typeof jwt != \"string\")\n throw new JWTInvalid(\"JWTs must use Compact JWS serialization, JWT must be a string\");\n const { 1: payload, length } = jwt.split(\".\");\n if (length === 5)\n throw new JWTInvalid(\"Only JWTs using Compact JWS serialization can be decoded\");\n if (length !== 3)\n throw new JWTInvalid(\"Invalid JWT\");\n if (!payload)\n throw new JWTInvalid(\"JWTs must contain a payload\");\n let decoded;\n try {\n decoded = b64u(payload);\n } catch {\n throw new JWTInvalid(\"Failed to base64url decode the payload\");\n }\n let result;\n try {\n result = JSON.parse(strictDecoder.decode(decoded));\n } catch {\n throw new JWTInvalid(\"Failed to parse the decoded payload as JSON\");\n }\n if (!isObject(result))\n throw new JWTInvalid(\"Invalid JWT Claims Set\");\n return result;\n}\nexport {\n decodeJwt\n};\n"],"mappings":"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","names":["message","message","encode","message","encode","invalid","dirname","join","createHmac","timingSafeEqual","createHash","createPublicKey","readFileSync","message","open","bounded","dirname","join","message","join","head","message","route","resolve","createHmac","URL_SCHEME","resolve","fetch","resolve","WHITESPACE","message","isRecord","createPublicKey","resolve","createHash","message","message","resolve","message","fetch","readFileSync"]}
|