@orkestrel/browser 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/src/browser/index.d.ts +77 -19
- package/dist/src/browser/index.js +361 -21
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +963 -173
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +354 -78
- package/dist/src/core/index.d.ts +354 -78
- package/dist/src/core/index.js +957 -175
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +36 -11
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +2 -2
- package/dist/src/server/index.d.ts +2 -2
- package/dist/src/server/index.js +36 -11
- package/dist/src/server/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["BrowserError","isInstance","pathWin32","pathPosix","mkdtemp","join","tmpdir","resolve","dirname","basename","BrowserError","rm","existsSync","spawnSync","globSync","spawn","isString","BrowserConnectionError","isArray","isRecord","BrowserTransition","Emitter","BROWSER_DEFAULT_TIMEOUT_MS","WEBSOCKET_READY_OPEN","BrowserConnectionError","attempt","randomBytes","WEBSOCKET_VERSION","httpsRequest","httpRequest","WEBSOCKET_READY_CLOSED","isString","computeWebSocketAccept","createNodeWebSocket","mkdir","dirname","writeFile","resolve","createToolManager","BROWSER_TOOL_NAMES","BROWSER_JOURNEY_TOOL_NAMES","createTool","BROWSER_TOOL_COPY","createMCPServer","createStdioServer","createMCPLegacy","rm","BrowserError","mkdir","join","randomUUID","createBrowserToolset","toolToDefinition","BrowserError","realpathSync","BROWSER_JOURNEY_NAME_PATTERN","BROWSER_RUN_ID_PATTERN","resolve","sep","relative","lstat","dirname","mkdir","readFile","randomUUID","open","rename","unlink","readdir","rmdir","parseJSON","isRecord","BrowserError","normalizeBrowserJourneyReason","BROWSER_JOURNEY_NAME_PATTERN","generateBrowserRunId","parseJSON","isRecord","BrowserError","BROWSER_JOURNEY_FORMAT_VERSION","rm","readdir","lstat","BrowserTransition","Emitter","isRecord","isString","BrowserConnectionError","BrowserContext","isBrowserConnectionError","isError","addAbortListener","BROWSER_DEFAULT_TIMEOUT_MS","CDPClient","isArray","isInteger","once"],"sources":["../../../src/server/constants.ts","../../../src/server/errors.ts","../../../src/server/helpers.ts","../../../src/server/transports/WebSocketCDPTransport.ts","../../../src/server/writers/FileBrowserWriter.ts","../../../package.json","../../../src/server/BrowserMCPServer.ts","../../../src/server/stores/FileBrowserStore.ts","../../../src/server/stores/FileBrowserJourneyStore.ts","../../../src/server/stores/FileBrowserRunStore.ts","../../../src/server/factories.ts","../../../src/server/Browser.ts"],"sourcesContent":["import type { BrowserEngine } from './types.js'\n\n// === CDP discovery\n\n/**\n * Sets the default CDP port probed for an existing browser and used for launches, `9222`.\n */\nexport const BROWSER_DEFAULT_CDP_PORT = 9222\n\n/**\n * Sets the default host probed for an existing browser and used for launches, `'127.0.0.1'`,\n * which avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`.\n */\nexport const BROWSER_DEFAULT_HOST = '127.0.0.1'\n\n/** Names the protocol prefix for CDP discovery requests, `'http'`. */\nexport const BROWSER_CDP_PROTOCOL = 'http'\n\n/**\n * Names the path appended to the CDP host to fetch version metadata, `'/json/version'`, which\n * is where endpoint discovery reads.\n */\nexport const BROWSER_CDP_VERSION_PATH = '/json/version'\n\n/**\n * Names the path appended to the CDP host to list open targets — pages, workers, and every\n * other target category Chromium reports — `'/json/list'`.\n */\nexport const BROWSER_CDP_LIST_PATH = '/json/list'\n\n// === Browser launch\n\n/** Lists the flags always passed to a launched browser process, alongside the caller's own. */\nexport const BROWSER_LAUNCH_ARGS: readonly string[] = Object.freeze([\n\t'--no-first-run',\n\t'--no-default-browser-check',\n])\n\n/**\n * Names the flag that enables headless mode on a launched browser process, `'--headless=new'`.\n */\nexport const BROWSER_HEADLESS_ARG = '--headless=new'\n\n/**\n * Names the prefix for isolated browser profiles created beneath the operating-system temp\n * directory, `'orkestrel-browser-'`.\n */\nexport const BROWSER_PROFILE_PREFIX = 'orkestrel-browser-'\n\n/**\n * Bounds each launched-process exit window during TERM-to-KILL teardown at `3_000`\n * milliseconds.\n */\nexport const BROWSER_KILL_GRACE_MS = 3_000\n\n/**\n * Bounds the `discover: false` port-occupancy probe before launching at `200` milliseconds,\n * which is short because the probe only needs to detect an already-listening CDP endpoint\n * rather than perform full discovery.\n */\nexport const BROWSER_PORT_PROBE_TIMEOUT_MS = 200\n\n/**\n * Matches the stderr line Chromium prints when its CDP endpoint accepts connections, and\n * captures the `ws://` endpoint the line names.\n *\n * @remarks\n * Chromium prints the line only when launched with `--remote-debugging-port`, which is why an\n * owned launch always passes that flag.\n */\nexport const BROWSER_DEVTOOLS_PATTERN = /DevTools listening on (ws:\\/\\/\\S+)/\n\n/**\n * Sets the interval in milliseconds between liveness probes of a terminated browser process\n * group.\n *\n * @remarks\n * Node raises an exit event for the direct child only. Neither the rest of a POSIX process\n * group nor a process a launcher handed the endpoint to raises one, so the bounded drain in\n * `Browser` probes on this interval until the group is gone or the grace period ends.\n */\nexport const BROWSER_DRAIN_INTERVAL_MS = 100\n\n/**\n * Defers once for `50` milliseconds when a transport loss is observed on an owned process,\n * so a near-simultaneous process-exit event, which libuv might reap slightly later than the\n * socket close, decides the diagnosis first.\n */\nexport const BROWSER_TRANSPORT_LOSS_DEFER_MS = 50\n\n/**\n * Names the machine-readable error-context cause for an owned browser process exiting,\n * `'process-exit'`.\n */\nexport const BROWSER_PROCESS_EXIT_CAUSE = 'process-exit'\n\n/**\n * Names the machine-readable error-context cause for a CDP transport disconnecting while its\n * browser remains alive, `'transport-loss'`.\n */\nexport const BROWSER_TRANSPORT_LOSS_CAUSE = 'transport-loss'\n\n/**\n * Lists the environment variables checked, in order, for an explicit browser executable path\n * override: `PLAYWRIGHT_EXECUTABLE_PATH`, then `CHROME_PATH`.\n */\nexport const BROWSER_ENV_PATH_KEYS: readonly string[] = Object.freeze([\n\t'PLAYWRIGHT_EXECUTABLE_PATH',\n\t'CHROME_PATH',\n])\n\n/**\n * Lists the well-known Chrome/Chromium/Edge executable paths with no platform-specific root,\n * keyed by `process.platform`, leaving `win32` empty because its roots come from\n * `BROWSER_WINDOWS_SUFFIXES`.\n */\nexport const BROWSER_EXECUTABLE_PATHS: Readonly<Record<string, readonly string[]>> = Object.freeze({\n\tlinux: Object.freeze([\n\t\t'/usr/bin/google-chrome',\n\t\t'/usr/bin/google-chrome-stable',\n\t\t'/usr/bin/microsoft-edge',\n\t\t'/usr/bin/microsoft-edge-stable',\n\t\t'/usr/bin/chromium',\n\t\t'/usr/bin/chromium-browser',\n\t\t'/snap/bin/chromium',\n\t\t'/opt/google/chrome/chrome',\n\t\t'/opt/microsoft/msedge/msedge',\n\t]),\n\tdarwin: Object.freeze([\n\t\t'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n\t\t'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',\n\t\t'/Applications/Chromium.app/Contents/MacOS/Chromium',\n\t]),\n\twin32: Object.freeze([]),\n})\n\n/** Lists the Windows install-root-relative suffixes for Chrome/Edge/Chromium, joined against each candidate root (`PROGRAMFILES`, `PROGRAMFILES(X86)`, `LOCALAPPDATA`). */\nexport const BROWSER_WINDOWS_SUFFIXES: readonly string[] = Object.freeze([\n\t'Google\\\\Chrome\\\\Application\\\\chrome.exe',\n\t'Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n\t'Chromium\\\\Application\\\\chrome.exe',\n])\n\n/**\n * Lists the fallback Windows install roots used when `PROGRAMFILES`, `PROGRAMFILES(X86)`, or\n * `LOCALAPPDATA` is absent.\n */\nexport const BROWSER_WINDOWS_ROOT_FALLBACKS: Readonly<Record<string, string>> = Object.freeze({\n\tPROGRAMFILES: 'C:\\\\Program Files',\n\t'PROGRAMFILES(X86)': 'C:\\\\Program Files (x86)',\n})\n\n/** Lists the command names probed on PATH when no well-known executable path exists. */\nexport const BROWSER_EXECUTABLE_NAMES: readonly string[] = Object.freeze([\n\t'google-chrome',\n\t'google-chrome-stable',\n\t'msedge',\n\t'microsoft-edge',\n\t'chromium',\n\t'chromium-browser',\n\t'chrome',\n])\n\n/**\n * Names the environment variable that carries an additional Playwright browser store base\n * directory, `'PLAYWRIGHT_BROWSERS_PATH'`.\n */\nexport const BROWSER_STORE_ENV_KEY = 'PLAYWRIGHT_BROWSERS_PATH'\n\n/**\n * Lists the well-known Playwright browser store base directories checked in addition to\n * `PLAYWRIGHT_BROWSERS_PATH`, starting with `/opt/pw-browsers`.\n */\nexport const BROWSER_STORE_DEFAULT_DIRS: readonly string[] = Object.freeze(['/opt/pw-browsers'])\n\n/** Names the per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */\nexport const BROWSER_STORE_CACHE_DIRS: Readonly<Record<string, string>> = Object.freeze({\n\tlinux: '.cache/ms-playwright',\n\tdarwin: 'Library/Caches/ms-playwright',\n})\n\n/**\n * Names the top-level Chromium symlink or binary Playwright maintains inside a browser store\n * base, `'chromium'`.\n */\nexport const BROWSER_STORE_LINK_NAME = 'chromium'\n\n/**\n * Lists the case-insensitive substrings identifying an executable path/name's browser\n * engine, checked by `parseBrowserEngine` in the order `edge` → `chromium` → `chrome`.\n */\nexport const BROWSER_ENGINE_HINTS: Readonly<Record<BrowserEngine, readonly string[]>> =\n\tObject.freeze({\n\t\tedge: Object.freeze(['msedge', 'microsoft-edge', 'edge']),\n\t\tchromium: Object.freeze([\n\t\t\t'chromium',\n\t\t\t'pw-browsers',\n\t\t\t'chrome-linux',\n\t\t\t'chrome-win',\n\t\t\t'chrome-mac',\n\t\t\t'chrome_headless',\n\t\t]),\n\t\tchrome: Object.freeze(['google-chrome', 'google/chrome', 'google\\\\chrome', 'chrome']),\n\t})\n\n/** Names the glob pattern (relative to a store base) matching a versioned Chromium binary, keyed by `process.platform`. */\nexport const BROWSER_STORE_GLOBS: Readonly<Record<string, string>> = Object.freeze({\n\tlinux: 'chromium-*/chrome-linux*/chrome',\n\tdarwin: 'chromium-*/chrome-mac*/Chromium.app/Contents/MacOS/Chromium',\n\twin32: 'chromium-*/chrome-win*/chrome.exe',\n})\n\n/** Names the persisted journey snapshot. */\nexport const BROWSER_JOURNEY_SNAPSHOT_FILE = 'journey.json'\n/** Names the retained journey revision counter. */\nexport const BROWSER_JOURNEY_REVISION_FILE = 'revision'\n/** Names the exclusive journey write lock directory. */\nexport const BROWSER_JOURNEY_LOCK_DIRECTORY = 'journey.lock'\n/** Bounds attempts to acquire a journey lock after concurrent recovery. */\nexport const BROWSER_JOURNEY_LOCK_ATTEMPTS = 8\n/** Names the persisted run snapshot. */\nexport const BROWSER_RUN_FILE = 'run.json'\n/** Names the journey directory holding its runs. */\nexport const BROWSER_RUN_DIRECTORY = 'runs'\n/** Bounds a file-store listing page by default. */\nexport const BROWSER_FILE_STORE_LIMIT = 100\n","import { BrowserError } from '@src/core'\nimport { isInstance } from '@orkestrel/contract'\n\n// === Server browser errors\n\n/**\n * Reports that an operation requiring an active connection was attempted while disconnected,\n * under the code `BROWSER_NOT_CONNECTED_ERROR`.\n */\nexport class BrowserNotConnectedError extends BrowserError {\n\tconstructor(context?: Readonly<Record<string, unknown>>) {\n\t\tsuper('Browser is not connected', 'BROWSER_NOT_CONNECTED_ERROR', context)\n\t\tthis.name = 'BrowserNotConnectedError'\n\t}\n}\n\n/**\n * Reports that an operation was attempted after the browser wrapper was destroyed, under the\n * code `BROWSER_DESTROYED_ERROR`.\n */\nexport class BrowserDestroyedError extends BrowserError {\n\tconstructor(context?: Readonly<Record<string, unknown>>) {\n\t\tsuper('Browser has been destroyed', 'BROWSER_DESTROYED_ERROR', context)\n\t\tthis.name = 'BrowserDestroyedError'\n\t}\n}\n\n// === Server browser type guards\n\n/**\n * Narrows an unknown value to a `BrowserNotConnectedError`.\n *\n * @param value - Value to check\n * @returns True if value is a BrowserNotConnectedError instance; false otherwise\n */\nexport function isBrowserNotConnectedError(value: unknown): value is BrowserNotConnectedError {\n\treturn isInstance(value, BrowserNotConnectedError)\n}\n\n/**\n * Narrows an unknown value to a `BrowserDestroyedError`.\n *\n * @param value - Value to check\n * @returns True if value is a BrowserDestroyedError instance; false otherwise\n */\nexport function isBrowserDestroyedError(value: unknown): value is BrowserDestroyedError {\n\treturn isInstance(value, BrowserDestroyedError)\n}\n","import type { ChildProcess } from 'node:child_process'\nimport type { Readable } from 'node:stream'\nimport type { CDPTarget } from '@src/core'\nimport type { Result } from '@orkestrel/contract'\nimport type {\n\tBrowserEngine,\n\tBrowserProfileResult,\n\tSystemBrowser,\n\tSystemBrowserOptions,\n} from './types.js'\nimport { existsSync, globSync } from 'node:fs'\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { basename, dirname, join, resolve, win32 as pathWin32, posix as pathPosix } from 'node:path'\nimport { spawn, spawnSync } from 'node:child_process'\nimport { isArray, isRecord, isString } from '@orkestrel/contract'\nimport { BrowserConnectionError, BrowserError } from '@src/core'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_LIST_PATH,\n\tBROWSER_DEVTOOLS_PATTERN,\n\tBROWSER_ENV_PATH_KEYS,\n\tBROWSER_EXECUTABLE_PATHS,\n\tBROWSER_EXECUTABLE_NAMES,\n\tBROWSER_WINDOWS_SUFFIXES,\n\tBROWSER_WINDOWS_ROOT_FALLBACKS,\n\tBROWSER_STORE_ENV_KEY,\n\tBROWSER_STORE_DEFAULT_DIRS,\n\tBROWSER_STORE_CACHE_DIRS,\n\tBROWSER_STORE_LINK_NAME,\n\tBROWSER_STORE_GLOBS,\n\tBROWSER_ENGINE_HINTS,\n\tBROWSER_LAUNCH_ARGS,\n\tBROWSER_HEADLESS_ARG,\n\tBROWSER_DEFAULT_HOST,\n\tBROWSER_PROFILE_PREFIX,\n} from './constants.js'\n\n/**\n * Formats a process identifier and UUID token as a lock entry name.\n * @param pid - Positive safe integer identifying the holder process\n * @param token - Lowercase UUID token identifying this acquisition\n * @returns The entry name\n * @example\n * formatBrowserLockEntry(123, '11111111-1111-4111-8111-111111111111')\n */\nexport function formatBrowserLockEntry(pid: number, token: string): string {\n\treturn `${pid}-${token}`\n}\n\n/**\n * Parses the holder process identifier from a lock entry name.\n * @remarks Requires a positive safe integer followed by a lowercase UUID token.\n * @param name - Directory entry name\n * @returns The process identifier, or undefined when the entry is malformed\n * @example\n * parseBrowserLockEntry('123-11111111-1111-4111-8111-111111111111') // 123\n */\nexport function parseBrowserLockEntry(name: string): number | undefined {\n\tconst match = /^([1-9]\\d*)-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.exec(\n\t\tname,\n\t)\n\tconst pid = Number(match?.[1])\n\treturn Number.isSafeInteger(pid) && pid > 0 ? pid : undefined\n}\n\n// === Discovery helpers\n\n/**\n * Enumerates every Chrome/Chromium/Edge executable discoverable on this\n * machine, deduplicated by normalized absolute path.\n *\n * @remarks\n * Resolution precedence (candidates appended in this order):\n * 1. `PLAYWRIGHT_EXECUTABLE_PATH`, then `CHROME_PATH` — explicit environment\n * overrides that exist on disk\n * 2. Well-known platform install locations (Chrome, Edge, Chromium); Windows\n * roots are derived from `PROGRAMFILES` / `PROGRAMFILES(X86)` / `LOCALAPPDATA`\n * 3. PATH probe for known command names (`which` on POSIX, `where` on Windows)\n * 4. Playwright-managed browser stores (`PLAYWRIGHT_BROWSERS_PATH`, `/opt/pw-browsers`,\n * and the per-OS Playwright cache directory) — the top-level `chromium`\n * link/binary, then the highest-revision `chromium-*` install found\n *\n * Each candidate is classified into a {@link BrowserEngine} through\n * `parseBrowserEngine` (unclassifiable candidates default to `'chromium'`),\n * and `options.engine` (when given) narrows the result to that engine.\n *\n * @param options - Overrides for the candidate sources; see {@link SystemBrowserOptions}\n * @returns Every discovered browser, in resolution-precedence order\n */\nexport function findSystemBrowsers(options?: SystemBrowserOptions): readonly SystemBrowser[] {\n\tconst platform = process.platform\n\tconst env = options?.env ?? process.env\n\n\tconst candidates: string[] = []\n\n\tcandidates.push(...findEnvOverrides(env))\n\n\tconst paths = options?.paths ?? buildInstallPaths(platform, env)\n\tcandidates.push(...findInstallPaths(paths))\n\n\tconst names = options?.names ?? BROWSER_EXECUTABLE_NAMES\n\tcandidates.push(...probePathNames(names, platform))\n\n\tconst stores = options?.stores ?? buildStoreBases(env, platform)\n\tfor (const store of stores) {\n\t\tcandidates.push(...findStorePaths(store, platform))\n\t}\n\n\tconst seen = new Set<string>()\n\tconst browsers: SystemBrowser[] = []\n\n\tfor (const executable of candidates) {\n\t\tconst key = normalizeExecutablePath(executable, platform)\n\t\tif (seen.has(key)) continue\n\t\tseen.add(key)\n\n\t\tconst engine = parseBrowserEngine(executable) ?? 'chromium'\n\t\tif (options?.engine !== undefined && engine !== options.engine) continue\n\n\t\tbrowsers.push({ executable, engine })\n\t}\n\n\treturn browsers\n}\n\n/**\n * Locates a Chrome/Chromium/Edge executable on this machine — the first entry\n * of {@link findSystemBrowsers}.\n *\n * @param options - Overrides for the candidate sources; see {@link SystemBrowserOptions}\n * @returns The first discovered browser, or undefined\n */\nexport function findSystemBrowser(options?: SystemBrowserOptions): SystemBrowser | undefined {\n\treturn findSystemBrowsers(options)[0]\n}\n\n/**\n * Classifies an executable path/name into a {@link BrowserEngine} by\n * case-insensitive hint, checked in the order edge → chromium → chrome.\n *\n * @param executable - Executable path or command name to classify\n * @returns The classified engine, or undefined when no hint matches\n */\nexport function parseBrowserEngine(executable: string): BrowserEngine | undefined {\n\tconst lower = executable.toLowerCase()\n\tconst order: readonly BrowserEngine[] = ['edge', 'chromium', 'chrome']\n\tfor (const engine of order) {\n\t\tconst hints = BROWSER_ENGINE_HINTS[engine]\n\t\tif (hints.some((hint) => lower.includes(hint))) return engine\n\t}\n\treturn undefined\n}\n\n/** Normalizes an executable path for cross-source deduplication (case-insensitive on Windows). */\nexport function normalizeExecutablePath(path: string, platform: string): string {\n\tconst normalized = platform === 'win32' ? pathWin32.normalize(path) : pathPosix.normalize(path)\n\treturn platform === 'win32' ? normalized.toLowerCase() : normalized\n}\n\n/** Classifies a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */\nexport function browserToEngine(browser?: string): BrowserEngine {\n\tif (browser?.includes('Edg/') === true) return 'edge'\n\tif (browser?.includes('Chrome/') === true) return 'chrome'\n\treturn 'chromium'\n}\n\n/**\n * Resolves a persistent caller profile or creates an isolated temporary one.\n *\n * @param path - Optional caller-owned persistent user-data directory\n * @returns The resolved profile and whether the library owns its lifecycle\n */\nexport async function createBrowserProfile(path?: string): Promise<BrowserProfileResult> {\n\tif (path !== undefined) return { path, temporary: false }\n\tconst directory = await mkdtemp(join(tmpdir(), BROWSER_PROFILE_PREFIX))\n\treturn { path: directory, temporary: true }\n}\n\n/**\n * Removes a library-owned isolated browser profile.\n *\n * @remarks\n * The path must remain a direct child of the operating-system temp directory\n * with {@link BROWSER_PROFILE_PREFIX}; this defensive check prevents a\n * malformed profile value from widening recursive deletion.\n *\n * @param profile - Resolved profile lifecycle result\n */\nexport async function removeBrowserProfile(profile: BrowserProfileResult): Promise<void> {\n\tif (!profile.temporary) return\n\tconst path = resolve(profile.path)\n\tconst temporary = resolve(tmpdir())\n\tif (dirname(path) !== temporary || !basename(path).startsWith(BROWSER_PROFILE_PREFIX)) {\n\t\tthrow new BrowserError('Refusing to remove an unsafe browser profile path', undefined, {\n\t\t\tpath,\n\t\t})\n\t}\n\tawait rm(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })\n}\n\n/** Checks the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order and returns every one that exists. */\nexport function findEnvOverrides(\n\tenv: Readonly<Record<string, string | undefined>>,\n): readonly string[] {\n\tconst found: string[] = []\n\tfor (const key of BROWSER_ENV_PATH_KEYS) {\n\t\tconst value = env[key]\n\t\tif (value !== undefined && value.length > 0 && existsSync(value)) found.push(value)\n\t}\n\treturn found\n}\n\n/** Builds the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */\nexport function buildInstallPaths(\n\tplatform: string,\n\tenv: Readonly<Record<string, string | undefined>>,\n): readonly string[] {\n\tif (platform !== 'win32') return BROWSER_EXECUTABLE_PATHS[platform] ?? []\n\n\tconst roots = buildWindowsRoots(env)\n\tconst paths: string[] = []\n\tfor (const root of roots) {\n\t\tfor (const suffix of BROWSER_WINDOWS_SUFFIXES) {\n\t\t\tpaths.push(pathWin32.join(root, suffix))\n\t\t}\n\t}\n\treturn paths\n}\n\n/** Derives Windows install roots from env vars, falling back to well-known literals when absent. */\nexport function buildWindowsRoots(\n\tenv: Readonly<Record<string, string | undefined>>,\n): readonly string[] {\n\tconst programFiles = env['PROGRAMFILES'] ?? BROWSER_WINDOWS_ROOT_FALLBACKS['PROGRAMFILES']\n\tconst programFilesX86 =\n\t\tenv['PROGRAMFILES(X86)'] ?? BROWSER_WINDOWS_ROOT_FALLBACKS['PROGRAMFILES(X86)']\n\tconst localAppData = env['LOCALAPPDATA']\n\n\tconst roots = [programFiles, programFilesX86, localAppData]\n\treturn roots.filter((root): root is string => root !== undefined)\n}\n\n/** Returns every candidate path that exists on disk, in the given order. */\nexport function findInstallPaths(paths: readonly string[]): readonly string[] {\n\treturn paths.filter((path) => existsSync(path))\n}\n\n/** Probes PATH (`which`/`where`) for every resolvable command name, in the given order. */\nexport function probePathNames(names: readonly string[], platform: string): readonly string[] {\n\tconst finder = platform === 'win32' ? 'where' : 'which'\n\tconst found: string[] = []\n\tfor (const name of names) {\n\t\tconst result = spawnSync(finder, [name], { stdio: 'pipe' })\n\t\tif (result.status === 0) {\n\t\t\tconst executable = readFirstLine(result.stdout.toString('utf-8'))\n\t\t\tif (executable !== undefined) found.push(executable)\n\t\t}\n\t}\n\treturn found\n}\n\n/**\n * Returns the first non-empty line of a command's output, without its\n * surrounding whitespace.\n *\n * @remarks\n * `where` reports every PATH match on its own CRLF-terminated line, so a\n * carriage return left on the first line would travel into `existsSync` and\n * `spawn` as part of the executable path.\n *\n * @param output - Raw decoded standard output of a command\n * @returns The first line carrying text, or undefined when the output has none\n *\n * @example\n * ```ts\n * readFirstLine('C:\\\\bin\\\\chrome.exe\\r\\nC:\\\\other\\\\chrome.exe\\r\\n') // 'C:\\\\bin\\\\chrome.exe'\n * ```\n */\nexport function readFirstLine(output: string): string | undefined {\n\tfor (const line of output.split(/\\r?\\n/)) {\n\t\tconst text = line.trim()\n\t\tif (text.length > 0) return text\n\t}\n\treturn undefined\n}\n\n/** Builds the default Playwright browser store base directories to search for a managed Chromium. */\nexport function buildStoreBases(\n\tenv: Readonly<Record<string, string | undefined>>,\n\tplatform: string,\n): readonly string[] {\n\tconst bases: string[] = []\n\n\tconst envBase = env[BROWSER_STORE_ENV_KEY]\n\tif (envBase !== undefined && envBase.length > 0) bases.push(envBase)\n\n\tbases.push(...BROWSER_STORE_DEFAULT_DIRS)\n\n\tif (platform === 'win32') {\n\t\tconst localAppData = env['LOCALAPPDATA']\n\t\tif (localAppData !== undefined) bases.push(pathWin32.join(localAppData, 'ms-playwright'))\n\t} else {\n\t\tconst cacheDir = BROWSER_STORE_CACHE_DIRS[platform]\n\t\tconst home = env['HOME']\n\t\tif (cacheDir !== undefined && home !== undefined) bases.push(pathPosix.join(home, cacheDir))\n\t}\n\n\treturn bases\n}\n\n/** Searches one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */\nexport function findStorePaths(base: string, platform: string): readonly string[] {\n\tconst joiner = platform === 'win32' ? pathWin32.join : pathPosix.join\n\tconst found: string[] = []\n\n\tconst linkPath = joiner(base, BROWSER_STORE_LINK_NAME)\n\tif (existsSync(linkPath)) found.push(linkPath)\n\n\tconst glob = BROWSER_STORE_GLOBS[platform]\n\tif (glob === undefined) return found\n\n\tconst pattern = `${base.replaceAll('\\\\', '/')}/${glob}`\n\tconst matches = globSync(pattern).filter((match) => existsSync(match))\n\tmatches.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))\n\tfound.push(...matches)\n\n\treturn found\n}\n\n/**\n * Launches a browser process with raw-CDP debugging flags.\n *\n * @remarks\n * POSIX launches own an isolated process group so lifecycle teardown can\n * signal and await every Chromium subprocess without affecting the caller.\n * Windows launches are not detached and own no group, so teardown there\n * signals one process by identifier: the spawned process, or the process the\n * launcher handed the endpoint to when that spawned process re-executed the\n * browser and exited. Terminating a Chromium browser process takes its own\n * subprocesses with it, so that single signal drains the tree.\n *\n * @param executable - Absolute path to the browser executable\n * @param port - Port the browser exposes its CDP endpoint on, or undefined for a port the operating system picks\n * @param headless - Whether to launch in headless mode\n * @param profile - Optional user-data-dir for a persistent profile\n * @param extra - Additional command-line flags\n * @returns The spawned ChildProcess, whose standard error carries the endpoint line `readBrowserEndpoint` reads\n */\nexport function launchBrowserProcess(\n\texecutable: string,\n\tport: number | undefined,\n\theadless: boolean,\n\tprofile?: string,\n\textra?: readonly string[],\n): ChildProcess {\n\t// Caller-supplied args come first so a script path (for example `node <script>`,\n\t// used to spawn a Node stand-in executable cross-platform in tests) lands\n\t// as an early positional argv entry ahead of the CDP flags that follow —\n\t// Chromium itself accepts flags in any order, so production is unaffected.\n\tconst args: string[] = []\n\tif (extra !== undefined) args.push(...extra)\n\targs.push(`--remote-debugging-port=${port ?? 0}`, ...BROWSER_LAUNCH_ARGS)\n\n\tif (headless) args.push(BROWSER_HEADLESS_ARG)\n\tif (profile !== undefined) args.push(`--user-data-dir=${profile}`)\n\n\treturn spawn(executable, args, {\n\t\tstdio: ['ignore', 'ignore', 'pipe'],\n\t\tdetached: process.platform !== 'win32',\n\t})\n}\n\n/**\n * Reads the CDP endpoint a launched browser announces on its standard error.\n *\n * @remarks\n * Chromium prints `DevTools listening on ws://HOST:PORT/devtools/browser/ID` after it binds the\n * debugging port. The read splits arriving text on line breaks across chunks, so a line split\n * between two chunks and a line ending `\\r\\n` both resolve. After resolving, the stream keeps\n * draining until it closes so the browser's logging never fills the pipe.\n *\n * @param stream - The browser's standard error\n * @param signal - Abort that rejects the read with its reason\n * @returns The `ws://` endpoint the browser announced\n *\n * @throws When the stream closes without the line, or the signal aborts first\n */\nexport function readBrowserEndpoint(stream: Readable, signal: AbortSignal): Promise<string> {\n\tconst read = Promise.withResolvers<string>()\n\tlet pending = ''\n\tlet found = false\n\n\tif (signal.aborted) read.reject(signal.reason)\n\tsignal.addEventListener('abort', () => read.reject(signal.reason), { once: true })\n\tstream.on('error', read.reject)\n\tstream.setEncoding('utf8')\n\tstream.on('data', (chunk) => {\n\t\tif (found || !isString(chunk)) return\n\t\tconst lines = (pending + chunk).split(/\\r\\n|\\n/)\n\t\tpending = lines.pop() ?? ''\n\t\tfor (const line of lines) {\n\t\t\tconst endpoint = BROWSER_DEVTOOLS_PATTERN.exec(line)?.[1]\n\t\t\tif (endpoint === undefined) continue\n\t\t\tfound = true\n\t\t\tpending = ''\n\t\t\tread.resolve(endpoint)\n\t\t\treturn\n\t\t}\n\t})\n\tstream.on('close', () => {\n\t\tconst endpoint = found ? undefined : BROWSER_DEVTOOLS_PATTERN.exec(pending)?.[1]\n\t\tif (endpoint !== undefined) read.resolve(endpoint)\n\t\telse {\n\t\t\tread.reject(\n\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t'Browser closed its standard error before reporting a CDP endpoint',\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t})\n\n\treturn read.promise\n}\n\n/**\n * Fetches the current CDP target list from a browser's `/json/list` endpoint, as a `Result`\n * carrying either the targets or a coded `BrowserConnectionError`.\n *\n * @remarks\n * The endpoint is a network boundary, so an unreachable host, a non-2xx\n * response, and a body that is not a JSON array each come back as a failed\n * `Result` carrying a coded `BrowserConnectionError`. An entry missing a\n * required string field is skipped rather than failing the whole list.\n *\n * @param port - Port the browser exposes its CDP endpoint on\n * @param timeout - Request timeout in milliseconds\n * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)\n * @returns The normalized CDP targets, or the fault that stopped the request\n *\n * @example\n * ```ts\n * import { fetchCDPTargets } from '@orkestrel/browser/server'\n *\n * const result = await fetchCDPTargets(9222, 2000)\n * if (result.success) log(result.value.length)\n * else log(result.error.code)\n * ```\n */\nexport async function fetchCDPTargets(\n\tport: number,\n\ttimeout: number,\n\thost: string = BROWSER_DEFAULT_HOST,\n): Promise<Result<readonly CDPTarget[], BrowserError>> {\n\tconst url = `${BROWSER_CDP_PROTOCOL}://${host}:${port}${BROWSER_CDP_LIST_PATH}`\n\tconst controller = new AbortController()\n\tconst timer = setTimeout(() => controller.abort(), timeout)\n\n\ttry {\n\t\tconst response = await fetch(url, { signal: controller.signal })\n\n\t\tif (!response.ok) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: new BrowserConnectionError('CDP target list request was refused', {\n\t\t\t\t\turl,\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t}),\n\t\t\t}\n\t\t}\n\n\t\tconst list: unknown = await response.json()\n\t\tif (!isArray(list)) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: new BrowserConnectionError('CDP target list is not a JSON array', { url }),\n\t\t\t}\n\t\t}\n\n\t\tconst targets: CDPTarget[] = []\n\t\tfor (const entry of list) {\n\t\t\tif (!isRecord(entry)) continue\n\t\t\tif (\n\t\t\t\t!isString(entry['id']) ||\n\t\t\t\t!isString(entry['type']) ||\n\t\t\t\t!isString(entry['title']) ||\n\t\t\t\t!isString(entry['url'])\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttargets.push({\n\t\t\t\tid: entry['id'],\n\t\t\t\tcategory: entry['type'],\n\t\t\t\ttitle: entry['title'],\n\t\t\t\turl: entry['url'],\n\t\t\t})\n\t\t}\n\n\t\treturn { success: true, value: targets }\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: new BrowserConnectionError('CDP target list is unreachable', { url, error }),\n\t\t}\n\t} finally {\n\t\tclearTimeout(timer)\n\t}\n}\n","import type { CDPTransportEventMap, CDPTransportInterface } from '@src/core'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { NodeWebSocketInterface } from '@orkestrel/websocket'\nimport type { WebSocketCDPTransportOptions } from '../types.js'\nimport type { ClientRequest, IncomingMessage, RequestOptions } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport { randomBytes } from 'node:crypto'\nimport { request as httpRequest } from 'node:http'\nimport { request as httpsRequest } from 'node:https'\nimport { attempt, isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport {\n\tcomputeWebSocketAccept,\n\tcreateNodeWebSocket,\n\tWEBSOCKET_READY_CLOSED,\n\tWEBSOCKET_READY_OPEN,\n\tWEBSOCKET_VERSION,\n} from '@orkestrel/websocket'\nimport { BROWSER_DEFAULT_TIMEOUT_MS, BrowserConnectionError, BrowserTransition } from '@src/core'\n\n// === WebSocketCDPTransport\n\n/**\n * Provides a raw CDP text transport backed by `@orkestrel/websocket`.\n *\n * @remarks\n * Performs and validates the RFC 6455 HTTP upgrade, then delegates frame\n * handling to `@orkestrel/websocket`. Concurrent and repeated `start()` /\n * `close()` calls share their active transition, and a later `start()` opens a\n * fresh socket after the prior one closes.\n *\n * @example\n * ```ts\n * import { WebSocketCDPTransport } from '@orkestrel/browser/server'\n *\n * const transport = new WebSocketCDPTransport({ url: 'ws://127.0.0.1:9222/devtools/browser/abc' })\n * await transport.start()\n * await transport.close()\n * ```\n */\nexport class WebSocketCDPTransport implements CDPTransportInterface {\n\treadonly #emitter: Emitter<CDPTransportEventMap>\n\treadonly #url: string\n\treadonly #timeout: number\n\t#socket: NodeWebSocketInterface | undefined\n\treadonly #starting: BrowserTransition = new BrowserTransition()\n\treadonly #closing: BrowserTransition = new BrowserTransition()\n\t#request: ClientRequest | undefined\n\t#resolve: ((socket: NodeWebSocketInterface) => void) | undefined\n\t#reject: ((error: unknown) => void) | undefined\n\t#timer: ReturnType<typeof setTimeout> | undefined\n\t#closeResolve: (() => void) | undefined\n\treadonly #socketCloseHandler = this.#handleSocketClose.bind(this)\n\n\tconstructor(options: WebSocketCDPTransportOptions) {\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#url = options.url\n\t\tthis.#timeout = options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS\n\t}\n\n\tget emitter(): EmitterInterface<CDPTransportEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tasync start(): Promise<void> {\n\t\tconst closing = this.#closing.pending\n\t\tif (closing !== undefined) await closing\n\t\tif (this.#socket?.readyState === WEBSOCKET_READY_OPEN) return\n\n\t\tconst active = this.#starting.pending\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\n\t\tthis.#socket?.destroy()\n\t\tthis.#socket = undefined\n\t\tawait this.#starting.execute(() => this.#start())\n\t}\n\n\tasync send(data: string): Promise<void> {\n\t\tconst socket = this.#socket\n\t\tif (socket === undefined || socket.readyState !== WEBSOCKET_READY_OPEN) {\n\t\t\tthrow new BrowserConnectionError('WebSocket CDP transport is not open', { url: this.#url })\n\t\t}\n\t\tsocket.send(data)\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.#closing.execute(() => this.#close())\n\t}\n\n\t// === Private helpers\n\n\tasync #start(): Promise<void> {\n\t\tconst parsed = attempt(() => new URL(this.#url))\n\t\tif (!parsed.success) {\n\t\t\tthrow new BrowserConnectionError(`WebSocket CDP URL is invalid: ${this.#url}`, {\n\t\t\t\turl: this.#url,\n\t\t\t\terror: parsed.error,\n\t\t\t})\n\t\t}\n\t\tconst url = parsed.value\n\t\tif (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t`WebSocket CDP connection requires a ws: or wss: URL: ${this.#url}`,\n\t\t\t\t{ url: this.#url },\n\t\t\t)\n\t\t}\n\t\tconst key = randomBytes(16).toString('base64')\n\t\tconst deferred = Promise.withResolvers<NodeWebSocketInterface>()\n\t\tconst options: RequestOptions = {\n\t\t\thostname: url.hostname,\n\t\t\tport: url.port.length > 0 ? Number(url.port) : url.protocol === 'wss:' ? 443 : 80,\n\t\t\tpath: `${url.pathname}${url.search}`,\n\t\t\theaders: {\n\t\t\t\tConnection: 'Upgrade',\n\t\t\t\tUpgrade: 'websocket',\n\t\t\t\t'Sec-WebSocket-Key': key,\n\t\t\t\t'Sec-WebSocket-Version': WEBSOCKET_VERSION,\n\t\t\t},\n\t\t}\n\t\tconst request = url.protocol === 'wss:' ? httpsRequest(options) : httpRequest(options)\n\n\t\tthis.#request = request\n\t\tthis.#resolve = deferred.resolve\n\t\tthis.#reject = deferred.reject\n\t\tthis.#timer = setTimeout(() => this.#expire(request), this.#timeout)\n\n\t\trequest.on('upgrade', (response: IncomingMessage, socket: Duplex, head: Buffer) => {\n\t\t\tthis.#upgrade(request, key, response, socket, head)\n\t\t})\n\t\trequest.on('response', (response) => this.#decline(request, response))\n\t\trequest.on('error', (error) => this.#fail(request, error))\n\t\trequest.end()\n\n\t\tconst socket = await deferred.promise\n\t\tthis.#socket = socket\n\t\tthis.#bind(socket)\n\t}\n\n\tasync #close(): Promise<void> {\n\t\tconst request = this.#request\n\t\tif (request !== undefined) {\n\t\t\tthis.#rejectRequest(\n\t\t\t\trequest,\n\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t`WebSocket CDP connection to ${this.#url} was closed before it finished connecting`,\n\t\t\t\t\t{ url: this.#url },\n\t\t\t\t),\n\t\t\t)\n\t\t\trequest.destroy()\n\t\t}\n\t\tawait this.#starting.pending?.catch(() => undefined)\n\n\t\tconst socket = this.#socket\n\t\tthis.#socket = undefined\n\t\tif (socket === undefined || socket.readyState === WEBSOCKET_READY_CLOSED) return\n\n\t\tconst closed = Promise.withResolvers<void>()\n\t\tthis.#closeResolve = closed.resolve\n\t\tsocket.emitter.on('close', this.#socketCloseHandler)\n\t\ttry {\n\t\t\tsocket.close()\n\t\t\tif (socket.readyState !== WEBSOCKET_READY_CLOSED) await closed.promise\n\t\t} catch {\n\t\t\tsocket.destroy()\n\t\t\tif (socket.readyState !== WEBSOCKET_READY_CLOSED) await closed.promise\n\t\t} finally {\n\t\t\tsocket.emitter.off('close', this.#socketCloseHandler)\n\t\t\tthis.#closeResolve = undefined\n\t\t}\n\t}\n\n\t#upgrade(\n\t\trequest: ClientRequest,\n\t\tkey: string,\n\t\tresponse: IncomingMessage,\n\t\tsocket: Duplex,\n\t\thead: Buffer,\n\t): void {\n\t\tif (this.#request !== request) {\n\t\t\tsocket.destroy()\n\t\t\treturn\n\t\t}\n\n\t\tconst accept = response.headers['sec-websocket-accept']\n\t\tif (!isString(accept) || accept !== computeWebSocketAccept(key)) {\n\t\t\tsocket.destroy()\n\t\t\tthis.#rejectRequest(\n\t\t\t\trequest,\n\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: Sec-WebSocket-Accept mismatch`,\n\t\t\t\t\t{ url: this.#url },\n\t\t\t\t),\n\t\t\t)\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tthis.#resolveRequest(request, createNodeWebSocket({ socket, head }))\n\t\t} catch (error) {\n\t\t\tsocket.destroy()\n\t\t\tthis.#rejectRequest(request, error)\n\t\t}\n\t}\n\n\t#decline(request: ClientRequest, response: IncomingMessage): void {\n\t\tresponse.resume()\n\t\tconst reason =\n\t\t\tresponse.statusCode === undefined\n\t\t\t\t? 'upgrade was declined without a status code'\n\t\t\t\t: `upgrade declined with status ${response.statusCode}`\n\t\tthis.#rejectRequest(\n\t\t\trequest,\n\t\t\tnew BrowserConnectionError(`WebSocket CDP connection to ${this.#url} failed: ${reason}`, {\n\t\t\t\turl: this.#url,\n\t\t\t}),\n\t\t)\n\t}\n\n\t#fail(request: ClientRequest, error: Error): void {\n\t\tthis.#rejectRequest(\n\t\t\trequest,\n\t\t\tnew BrowserConnectionError(\n\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: ${error.message}`,\n\t\t\t\t{ url: this.#url },\n\t\t\t),\n\t\t)\n\t}\n\n\t#expire(request: ClientRequest): void {\n\t\tthis.#rejectRequest(\n\t\t\trequest,\n\t\t\tnew BrowserConnectionError(\n\t\t\t\t`WebSocket CDP connection to ${this.#url} timed out after ${this.#timeout}ms`,\n\t\t\t\t{ url: this.#url, timeout: this.#timeout },\n\t\t\t),\n\t\t)\n\t\trequest.destroy()\n\t}\n\n\t#resolveRequest(request: ClientRequest, socket: NodeWebSocketInterface): void {\n\t\tif (this.#request !== request) {\n\t\t\tsocket.destroy()\n\t\t\treturn\n\t\t}\n\n\t\tconst resolve = this.#resolve\n\t\tthis.#clearRequest()\n\t\tresolve?.(socket)\n\t}\n\n\t#rejectRequest(request: ClientRequest, error: unknown): void {\n\t\tif (this.#request !== request) return\n\n\t\tconst reject = this.#reject\n\t\tthis.#clearRequest()\n\t\treject?.(error)\n\t}\n\n\t#clearRequest(): void {\n\t\tif (this.#timer !== undefined) clearTimeout(this.#timer)\n\t\tthis.#timer = undefined\n\t\tthis.#request = undefined\n\t\tthis.#resolve = undefined\n\t\tthis.#reject = undefined\n\t}\n\n\t#bind(socket: NodeWebSocketInterface): void {\n\t\tsocket.emitter.on('message', (data) => this.#emitter.emit('message', data))\n\t\tsocket.emitter.on('close', () => {\n\t\t\tif (this.#socket === socket) this.#socket = undefined\n\t\t\tthis.#emitter.emit('close')\n\t\t})\n\t\tsocket.emitter.on('error', (error) => this.#emitter.emit('error', error))\n\t}\n\n\t#handleSocketClose(): void {\n\t\tthis.#closeResolve?.()\n\t}\n}\n","import type { BrowserWriterInterface } from '@src/core'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n// === FileBrowserWriter\n\n/**\n * Persists captured browser bytes to the filesystem through `node:fs/promises`.\n *\n * @remarks\n * Creates every missing parent directory of the target path before writing, so\n * a caller may name a nested destination that does not exist yet.\n *\n * @example\n * ```ts\n * import { FileBrowserWriter } from '@orkestrel/browser/server'\n *\n * const writer = new FileBrowserWriter()\n * await writer.write('shots/hero.png', new Uint8Array([137, 80, 78, 71]))\n * ```\n */\nexport class FileBrowserWriter implements BrowserWriterInterface {\n\t/**\n\t * Writes the captured bytes to a path, creating its parent directories.\n\t *\n\t * @param path - Destination file path\n\t * @param data - Captured bytes to persist\n\t * @returns A promise resolving once the bytes are on disk\n\t */\n\tasync write(path: string, data: Uint8Array): Promise<void> {\n\t\tawait mkdir(dirname(path), { recursive: true })\n\t\tawait writeFile(path, data)\n\t}\n}\n","{\n\t\"name\": \"@orkestrel/browser\",\n\t\"version\": \"0.0.20\",\n\t\"description\": \"Chrome DevTools Protocol browser automation with an environment-agnostic core. Part of the @orkestrel line.\",\n\t\"keywords\": [\n\t\t\"automation\",\n\t\t\"browser\",\n\t\t\"cdp\",\n\t\t\"chrome\",\n\t\t\"chromium\",\n\t\t\"devtools\",\n\t\t\"orkestrel\",\n\t\t\"screenshot\",\n\t\t\"typescript\"\n\t],\n\t\"homepage\": \"https://github.com/orkestrel/browser#readme\",\n\t\"bugs\": \"https://github.com/orkestrel/browser/issues\",\n\t\"license\": \"MIT\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/orkestrel/browser.git\"\n\t},\n\t\"bin\": {\n\t\t\"browse\": \"dist/bin/main.js\"\n\t},\n\t\"files\": [\n\t\t\"dist/src\",\n\t\t\"dist/bin\",\n\t\t\"README.md\"\n\t],\n\t\"type\": \"module\",\n\t\"sideEffects\": false,\n\t\"main\": \"./dist/src/core/index.cjs\",\n\t\"module\": \"./dist/src/core/index.js\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/src/core/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/src/core/index.js\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/src/core/index.d.cts\",\n\t\t\t\t\"default\": \"./dist/src/core/index.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./server\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/src/server/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/src/server/index.js\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/src/server/index.d.cts\",\n\t\t\t\t\"default\": \"./dist/src/server/index.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./browser\": {\n\t\t\t\"types\": \"./dist/src/browser/index.d.ts\",\n\t\t\t\"default\": \"./dist/src/browser/index.js\"\n\t\t},\n\t\t\"./package.json\": \"./package.json\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"scripts\": {\n\t\t\"clean\": \"node -e \\\"require('node:fs').rmSync('dist',{recursive:true,force:true})\\\"\",\n\t\t\"copy\": \"node -e \\\"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\\\"\",\n\t\t\"scaffold\": \"scaffold\",\n\t\t\"lint\": \"oxlint --config .oxlintrc.json --fix .\",\n\t\t\"check\": \"tsc --noEmit --project tsconfig.json && npm run check:src\",\n\t\t\"check:src\": \"npm run check:src:core && npm run check:src:server && npm run check:src:browser && npm run check:src:bin\",\n\t\t\"check:src:core\": \"tsc --noEmit -p configs/src/tsconfig.core.json\",\n\t\t\"check:src:server\": \"tsc --noEmit -p configs/src/tsconfig.server.json\",\n\t\t\"check:src:browser\": \"tsc --noEmit -p configs/src/tsconfig.browser.json\",\n\t\t\"check:src:bin\": \"tsc --noEmit -p configs/src/tsconfig.bin.json\",\n\t\t\"format\": \"oxfmt --config .oxfmtrc.json --write .\",\n\t\t\"format:check\": \"oxfmt --config .oxfmtrc.json --check .\",\n\t\t\"lint:check\": \"oxlint --config .oxlintrc.json --deny-warnings .\",\n\t\t\"test\": \"npm run test:src && npm run test:src:bin && npm run test:policy && npm run test:config && npm run test:setup && npm run test:setup:browser && npm run test:guides && npm run test:conformance\",\n\t\t\"test:conformance\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project conformance\",\n\t\t\"test:src\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core --project src:server --project src:browser\",\n\t\t\"test:src:core\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core\",\n\t\t\"test:src:server\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:server\",\n\t\t\"test:src:browser\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:browser\",\n\t\t\"test:src:bin\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin\",\n\t\t\"test:policy\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project policy\",\n\t\t\"test:config\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project config\",\n\t\t\"test:guides\": \"node --experimental-strip-types tests/guides.test.ts\",\n\t\t\"build\": \"npm run clean && npm run build:src\",\n\t\t\"build:src\": \"npm run build:src:core && npm run build:src:server && npm run build:src:browser && npm run build:src:bin\",\n\t\t\"build:src:core\": \"vite build --config configs/src/vite.core.config.ts && npm run copy dist/src/core/index.d.ts dist/src/core/index.d.cts\",\n\t\t\"build:src:server\": \"vite build --config configs/src/vite.server.config.ts && npm run copy dist/src/server/index.d.ts dist/src/server/index.d.cts\",\n\t\t\"build:src:browser\": \"vite build --config configs/src/vite.browser.config.ts\",\n\t\t\"build:src:bin\": \"vite build --config configs/src/vite.bin.config.ts\",\n\t\t\"prepack\": \"npm run build\",\n\t\t\"prepublishOnly\": \"npm run format:check && npm run lint:check && npm run check && npm run build && npm test && npm run test:distribution -- --mode release && npm run test:service\",\n\t\t\"test:distribution\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project distribution\",\n\t\t\"test:service\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project service\",\n\t\t\"test:probe\": \"vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe\",\n\t\t\"test:bench\": \"vitest bench --config vite.config.ts --no-cache --project probe\",\n\t\t\"test:setup\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project setup\",\n\t\t\"test:setup:browser\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project setup:browser\"\n\t},\n\t\"dependencies\": {\n\t\t\"@orkestrel/contract\": \"^0.0.19\",\n\t\t\"@orkestrel/emitter\": \"^0.0.11\",\n\t\t\"@orkestrel/html\": \"^0.0.12\",\n\t\t\"@orkestrel/markdown\": \"^0.0.17\",\n\t\t\"@orkestrel/mcp\": \"^0.0.35\",\n\t\t\"@orkestrel/router\": \"^0.0.16\",\n\t\t\"@orkestrel/server\": \"^0.0.22\",\n\t\t\"@orkestrel/tool\": \"^0.0.18\",\n\t\t\"@orkestrel/websocket\": \"^0.0.14\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@microsoft/api-extractor\": \"^7.59.3\",\n\t\t\"@orkestrel/guide\": \"^0.0.22\",\n\t\t\"@orkestrel/probe\": \"^0.0.19\",\n\t\t\"@orkestrel/scaffold\": \"^0.0.82\",\n\t\t\"@orkestrel/test\": \"^0.0.24\",\n\t\t\"@types/node\": \"^26.6.3\",\n\t\t\"@vitest/browser-playwright\": \"^4.1.11\",\n\t\t\"oxfmt\": \"^0.71.0\",\n\t\t\"oxlint\": \"^1.86.0\",\n\t\t\"playwright\": \"^1.63.0\",\n\t\t\"typescript\": \"^6.0.3\",\n\t\t\"vite\": \"^8.3.2\",\n\t\t\"vitest\": \"^4.1.11\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n","import type { BrowserToolsetInterface } from '@src/core'\nimport type { MCPCallResult, MCPExecutionContext } from '@orkestrel/mcp'\nimport type { StdioServerInterface } from '@orkestrel/mcp/server'\nimport type { ToolContext, ToolInterface, ToolManagerInterface, ToolResult } from '@orkestrel/tool'\nimport type {\n\tBrowserInterface,\n\tBrowserLaunchFunction,\n\tBrowserMCPServerInterface,\n\tBrowserMCPServerOptions,\n} from './types.js'\nimport { randomUUID } from 'node:crypto'\nimport { mkdir, rm } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport { createMCPLegacy, createMCPServer } from '@orkestrel/mcp'\nimport { createStdioServer } from '@orkestrel/mcp/server'\nimport { createTool, createToolManager, toolToDefinition } from '@orkestrel/tool'\nimport {\n\tBROWSER_JOURNEY_TOOL_NAMES,\n\tBROWSER_TOOL_COPY,\n\tBROWSER_TOOL_NAMES,\n\tBrowserError,\n\tcreateBrowserToolset,\n} from '@src/core'\nimport { version } from '../../package.json' with { type: 'json' }\nimport {\n\tcreateBrowser,\n\tcreateFileBrowserJourneyStore,\n\tcreateFileBrowserRunStore,\n} from './factories.js'\n\n/**\n * Implements `BrowserMCPServerInterface`: serves the browser vocabulary and the journey tools over\n * the Model Context Protocol on stdio, and launches Chromium on the first tool call.\n *\n * @remarks\n * The server's own manager holds one dispatcher per name of the vocabulary — `look`, `read`,\n * `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, `switch`, `record`, `save`,\n * `journeys`, `edit`, and `replay` — each carrying the description, parameters, and annotations\n * `BROWSER_TOOL_COPY` gives, so `tools/list` answers before Chromium starts and with Chromium\n * absent. After the launch, a tool the toolset's manager adds under another name, such as a page\n * tool it adopts, is mirrored as a dispatcher with that tool's definition, and the mirror is\n * removed when the toolset withdraws the tool, so the server's tool list changes and a subscribed\n * client is notified. The first call of any dispatcher launches Chromium one time: concurrent callers await\n * the same launch, a failed launch rejects every one of them, and the next call launches again.\n * A launch creates `ROOT/.profiles/ID/` exclusively, connects a browser that never attaches to an\n * existing endpoint, opens one page in an isolated context, and constructs the page toolset with\n * that context and the file journey and run stores under the root, on a manager the toolset owns.\n * A dispatcher forwards its arguments and the call's context, signal included, to the toolset's\n * manager and returns that manager's value, or rejects with its failure message; a text value\n * reaches the client as one text block rather than as its JSON text.\n *\n * `start()` serves stdio and destroys the server at the end of its input, on `SIGINT`, and on\n * `SIGTERM`. `destroy()` stops reading requests and removes every dispatcher, then destroys the\n * toolset, which aborts the active replay, then the browser it launched, then removes the profile.\n *\n * Chromium on Linux refuses to start as the root user unless its sandbox is disabled, so a server\n * running as root on Linux launches Chromium with `--no-sandbox`; a launch that could run\n * sandboxed is never changed.\n *\n * @example\n * ```ts\n * import { BrowserMCPServer } from '@orkestrel/browser/server'\n *\n * const server = new BrowserMCPServer({ root: 'tmp/browsers', readonly: true })\n * await server.start()\n * await server.destroy()\n * ```\n */\nexport class BrowserMCPServer implements BrowserMCPServerInterface {\n\treadonly #root: string\n\treadonly #headless: boolean\n\treadonly #executable: string | undefined\n\treadonly #readonly: boolean\n\treadonly #launcher: BrowserLaunchFunction\n\treadonly #input: NodeJS.ReadableStream\n\treadonly #tools: ToolManagerInterface\n\treadonly #transport: StdioServerInterface\n\treadonly #abort = new AbortController()\n\treadonly #signal: () => void\n\treadonly #vocabulary: ReadonlySet<string>\n\treadonly #added: (tool: ToolInterface) => void\n\treadonly #removed: (tool: ToolInterface) => void\n\treadonly #cleared: (tools: readonly ToolInterface[]) => void\n\t#mirrored: ToolManagerInterface | undefined\n\t#session: Promise<BrowserToolsetInterface> | undefined\n\t#browser: BrowserInterface | undefined\n\t#profile: string | undefined\n\t#started = false\n\t#closing: Promise<void> | undefined\n\n\t/**\n\t * Registers the dispatchers and binds the protocol to the stdio streams without reading them.\n\t *\n\t * @param options - The root, the launch, the journeys' read-only switch, and the streams\n\t */\n\tconstructor(options?: BrowserMCPServerOptions) {\n\t\tthis.#root = resolve(options?.root ?? 'tmp/browsers')\n\t\tthis.#headless = options?.headless ?? true\n\t\tthis.#executable = options?.executable\n\t\tthis.#readonly = options?.readonly ?? false\n\t\tthis.#launcher = options?.launch ?? createBrowser\n\t\tthis.#input = options?.stdio?.input ?? process.stdin\n\t\tthis.#tools = createToolManager()\n\t\tconst names = [...BROWSER_TOOL_NAMES, ...BROWSER_JOURNEY_TOOL_NAMES]\n\t\tthis.#vocabulary = new Set(names)\n\t\tfor (const name of names) {\n\t\t\tthis.#tools.add(\n\t\t\t\tcreateTool({\n\t\t\t\t\t...BROWSER_TOOL_COPY[name],\n\t\t\t\t\texecute: this.#forward.bind(this, name),\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\tconst server = createMCPServer({\n\t\t\tidentity: { name: 'browse', version },\n\t\t\ttools: this.#tools,\n\t\t\texecution: this.#execute.bind(this),\n\t\t})\n\t\tthis.#transport = createStdioServer(createMCPLegacy(server), {\n\t\t\tinput: this.#input,\n\t\t\t...(options?.stdio?.output === undefined ? {} : { output: options.stdio.output }),\n\t\t})\n\t\t// One reference serves the end of input and both signals, because a listener is removed by\n\t\t// identity.\n\t\tthis.#signal = this.#end.bind(this)\n\t\tthis.#added = this.#mirror.bind(this)\n\t\tthis.#removed = this.#withdraw.bind(this)\n\t\tthis.#cleared = this.#clear.bind(this)\n\t}\n\n\tasync start(): Promise<void> {\n\t\tif (this.#closing !== undefined) throw this.#ended()\n\t\tif (this.#started) return\n\t\tthis.#started = true\n\t\tthis.#transport.start()\n\t\tthis.#input.on('end', this.#signal)\n\t\tprocess.on('SIGINT', this.#signal)\n\t\tprocess.on('SIGTERM', this.#signal)\n\t}\n\n\tdestroy(): Promise<void> {\n\t\tthis.#closing ??= this.#destroy()\n\t\treturn this.#closing\n\t}\n\n\tasync #destroy(): Promise<void> {\n\t\t// The handlers go first: a second signal during a slow teardown asks for the process.\n\t\tprocess.removeListener('SIGINT', this.#signal)\n\t\tprocess.removeListener('SIGTERM', this.#signal)\n\t\tthis.#input.removeListener('end', this.#signal)\n\t\tthis.#transport.stop()\n\t\tfor (const tool of this.#tools.tools()) this.#tools.remove(tool.name)\n\t\tthis.#unmirror()\n\t\t// Aborting the launch signal ends a connect in flight, so its launch cleans up after itself.\n\t\tthis.#abort.abort()\n\t\t// Each step runs whether or not an earlier one failed, so the profile is always removed.\n\t\tconst failures: unknown[] = []\n\t\tconst toolset = await this.#session?.catch(() => undefined)\n\t\tawait toolset?.destroy().catch((error: unknown) => failures.push(error))\n\t\tawait this.#browser?.destroy().catch((error: unknown) => failures.push(error))\n\t\tthis.#browser = undefined\n\t\tconst profile = this.#profile\n\t\tthis.#profile = undefined\n\t\t// `rm` retries a busy directory within its budget, which a Chromium that has ended can leave.\n\t\tif (profile !== undefined) await rm(profile, { recursive: true, force: true, maxRetries: 5 })\n\t\tif (failures.length > 0) throw new AggregateError(failures, 'The browse server teardown failed')\n\t}\n\n\t// Runs the dispatcher and answers a text result as one text block, because the protocol's own\n\t// rendering of a value is its JSON text, which escapes every quote and line break of a receipt.\n\tasync #execute(context: MCPExecutionContext): Promise<ToolResult | MCPCallResult> {\n\t\tconst result = await context.tools.execute(context.call, {\n\t\t\tsignal: context.signal,\n\t\t\t...(context.caller === undefined ? {} : { caller: context.caller }),\n\t\t})\n\t\tif (!result.success || typeof result.value !== 'string') return result\n\t\treturn { resultType: 'complete', content: [{ type: 'text', text: result.value }] }\n\t}\n\n\t// Answers the end of input and a termination signal.\n\t#end(): void {\n\t\tvoid this.destroy()\n\t}\n\n\tasync #forward(\n\t\tname: string,\n\t\targs: Readonly<Record<string, unknown>>,\n\t\tcontext: ToolContext,\n\t): Promise<unknown> {\n\t\tconst toolset = await this.#open()\n\t\tconst result = await toolset.tools.execute({ id: name, name, arguments: args }, context)\n\t\tif (!result.success) throw new BrowserError(result.error)\n\t\treturn result.value\n\t}\n\n\t// Returns the launch every caller shares; a rejected launch is forgotten so the next call retries.\n\t// Stopping the transport aborts a call in flight and `destroy()` removes the dispatchers, so the\n\t// refusal here is the last of three layers that keep a call from launching after `destroy()`.\n\t#open(): Promise<BrowserToolsetInterface> {\n\t\tif (this.#closing !== undefined) return Promise.reject(this.#ended())\n\t\tconst current = this.#session\n\t\tif (current !== undefined) return current\n\t\tconst session = this.#launch()\n\t\tthis.#session = session\n\t\tsession.catch(() => {\n\t\t\tif (this.#session === session) this.#session = undefined\n\t\t})\n\t\treturn session\n\t}\n\n\tasync #launch(): Promise<BrowserToolsetInterface> {\n\t\tawait mkdir(this.#root, { recursive: true })\n\t\tconst profiles = join(this.#root, '.profiles')\n\t\tawait mkdir(profiles, { recursive: true })\n\t\tconst profile = join(profiles, randomUUID())\n\t\t// Without `recursive`, an existing directory refuses with `EEXIST`, so no two launches share one.\n\t\tawait mkdir(profile)\n\t\tthis.#profile = profile\n\t\tlet browser: BrowserInterface | undefined\n\t\tlet toolset: BrowserToolsetInterface | undefined\n\t\ttry {\n\t\t\tbrowser = this.#launcher({\n\t\t\t\theadless: this.#headless,\n\t\t\t\tprofile,\n\t\t\t\tcdp: { discover: false },\n\t\t\t\tsignal: this.#abort.signal,\n\t\t\t\t...(this.#executable === undefined ? {} : { executable: this.#executable }),\n\t\t\t\t...(process.platform === 'linux' && process.getuid?.() === 0\n\t\t\t\t\t? { args: ['--no-sandbox'] }\n\t\t\t\t\t: {}),\n\t\t\t})\n\t\t\tthis.#browser = browser\n\t\t\tawait browser.connect()\n\t\t\tconst context = await browser.isolate()\n\t\t\tconst page = await context.create()\n\t\t\ttoolset = createBrowserToolset(page, {\n\t\t\t\tcontext,\n\t\t\t\tjourneys: {\n\t\t\t\t\tstore: createFileBrowserJourneyStore({ root: this.#root }),\n\t\t\t\t\truns: createFileBrowserRunStore({ root: this.#root }),\n\t\t\t\t\treadonly: this.#readonly,\n\t\t\t\t},\n\t\t\t})\n\t\t\t// The toolset adopts page tools during `start()`, so the mirror follows it from before.\n\t\t\tthis.#mirrored = toolset.tools\n\t\t\ttoolset.tools.emitter.on('add', this.#added)\n\t\t\ttoolset.tools.emitter.on('remove', this.#removed)\n\t\t\ttoolset.tools.emitter.on('clear', this.#cleared)\n\t\t\tawait toolset.start()\n\t\t\treturn toolset\n\t\t} catch (error) {\n\t\t\tthis.#unmirror()\n\t\t\tif (this.#browser === browser) this.#browser = undefined\n\t\t\tif (this.#profile === profile) this.#profile = undefined\n\t\t\tawait toolset?.destroy().catch(() => undefined)\n\t\t\tawait browser?.destroy().catch(() => undefined)\n\t\t\tawait rm(profile, { recursive: true, force: true, maxRetries: 5 })\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t// Adds a dispatcher for a tool the toolset's manager added under a name outside the vocabulary.\n\t#mirror(tool: ToolInterface): void {\n\t\tif (this.#vocabulary.has(tool.name)) return\n\t\tthis.#tools.add(\n\t\t\tcreateTool({ ...toolToDefinition(tool), execute: this.#forward.bind(this, tool.name) }),\n\t\t)\n\t}\n\n\t// Removes the dispatcher of a withdrawn tool; a replacement publishes `remove` while it is\n\t// installed, so the mirror follows the manager's current tool rather than the event.\n\t#withdraw(tool: ToolInterface): void {\n\t\tif (this.#vocabulary.has(tool.name)) return\n\t\tconst current = this.#mirrored?.tool(tool.name)\n\t\tif (current === undefined) this.#tools.remove(tool.name)\n\t\telse this.#mirror(current)\n\t}\n\n\t#clear(tools: readonly ToolInterface[]): void {\n\t\tfor (const tool of tools) this.#withdraw(tool)\n\t}\n\n\t#unmirror(): void {\n\t\tconst mirrored = this.#mirrored\n\t\tif (mirrored === undefined) return\n\t\tthis.#mirrored = undefined\n\t\tmirrored.emitter.off('add', this.#added)\n\t\tmirrored.emitter.off('remove', this.#removed)\n\t\tmirrored.emitter.off('clear', this.#cleared)\n\t}\n\n\t#ended(): BrowserError {\n\t\treturn new BrowserError('the browser session ended', 'BROWSER_TOOLSET_ENDED')\n\t}\n}\n","import type { BrowserStoreOptions, BrowserStorePage, BrowserStoreFault } from '@src/core'\nimport type { FileBrowserStoreOptions } from '../types.js'\nimport { realpathSync } from 'node:fs'\nimport { lstat, mkdir, open, readFile, readdir, rename, rmdir, unlink } from 'node:fs/promises'\nimport { dirname, relative, resolve, sep } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport {\n\tBrowserError,\n\tBROWSER_JOURNEY_NAME_PATTERN,\n\tBROWSER_RUN_ID_PATTERN,\n\tvalidateBrowserStorePage,\n} from '@src/core'\nimport { BROWSER_FILE_STORE_LIMIT, BROWSER_JOURNEY_LOCK_ATTEMPTS } from '../constants.js'\nimport { formatBrowserLockEntry, parseBrowserLockEntry } from '../helpers.js'\n\n/**\n * Shares confined filesystem operations between the journey and run stores.\n * @remarks Requires an existing root directory. Links present during a component check are refused;\n * replacement between a check and its use by another filesystem writer is outside this boundary.\n * @example\n * const files = new FileBrowserStore({ root: directory })\n * files.validateName('check-ready')\n */\nexport class FileBrowserStore {\n\treadonly #root: string\n\treadonly #limit: number\n\n\tconstructor(options: FileBrowserStoreOptions) {\n\t\tthis.#limit = options.limit ?? BROWSER_FILE_STORE_LIMIT\n\t\tif (!Number.isSafeInteger(this.#limit) || this.#limit < 1)\n\t\t\tthrow new BrowserError(\n\t\t\t\t'The listing cap must be a positive integer',\n\t\t\t\t'BROWSER_JOURNEY_ARGUMENT',\n\t\t\t)\n\t\ttry {\n\t\t\tthis.#root = realpathSync(options.root)\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT')\n\t\t\t\tthrow new BrowserError(`Missing root: ${options.root}`, 'BROWSER_JOURNEY_PATH', {\n\t\t\t\t\tpath: options.root,\n\t\t\t\t})\n\t\t\tthrow this.translateError(options.root, error)\n\t\t}\n\t}\n\n\t/** Checks a journey name before filesystem access. @param name - Journey name */\n\tvalidateName(name: string): void {\n\t\tif (!BROWSER_JOURNEY_NAME_PATTERN.test(name))\n\t\t\tthrow new BrowserError(`Refused journey name: ${name}`, 'BROWSER_JOURNEY_PATH')\n\t}\n\n\t/** Checks a run id before filesystem access. @param id - Producer id */\n\tvalidateId(id: string): void {\n\t\tif (!BROWSER_RUN_ID_PATTERN.test(id))\n\t\t\tthrow new BrowserError(`Refused run id: ${id}`, 'BROWSER_JOURNEY_PATH')\n\t}\n\n\t/** Resolves a confined target. @param parts - Relative components @returns Absolute target */\n\tresolvePath(...parts: readonly string[]): string {\n\t\tconst path = resolve(this.#root, ...parts)\n\t\tif (\n\t\t\tpath !== this.#root &&\n\t\t\t!path.startsWith(this.#root.endsWith(sep) ? this.#root : this.#root + sep)\n\t\t)\n\t\t\tthrow new BrowserError(`Refused path: ${path}`, 'BROWSER_JOURNEY_PATH')\n\t\treturn path\n\t}\n\n\t/**\n\t * Checks every existing component including the root and target.\n\t * @param path - Absolute target\n\t * @param options - Cancellation options\n\t * @returns True if the target exists; false if a component is missing\n\t */\n\tasync check(path: string, options?: BrowserStoreOptions): Promise<boolean> {\n\t\tthis.resolvePath(path)\n\t\tlet current = this.#root\n\t\tconst parts = relative(this.#root, path).split(sep).filter(Boolean)\n\t\tfor (let index = 0; index <= parts.length; index += 1) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tconst status = await lstat(current)\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tif (status.isSymbolicLink())\n\t\t\t\t\tthrow new BrowserError(`Refused symbolic link: ${current}`, 'BROWSER_JOURNEY_PATH')\n\t\t\t\tif (index < parts.length && !status.isDirectory())\n\t\t\t\t\tthrow new BrowserError(`Not a directory: ${current}`, 'BROWSER_JOURNEY_PATH')\n\t\t\t} catch (error) {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT') return false\n\t\t\t\tthrow this.translateError(current, error)\n\t\t\t}\n\t\t\tconst part = parts[index]\n\t\t\tif (part !== undefined) current = this.resolvePath(current, part)\n\t\t}\n\t\treturn true\n\t}\n\n\t/** Creates checked directories one component at a time. @param path - Directory @param options - Cancellation options */\n\tasync createDirectory(path: string, options?: BrowserStoreOptions): Promise<void> {\n\t\tif (await this.check(path, options)) return\n\t\tif (path === this.#root) throw new BrowserError(`Missing root: ${path}`, 'BROWSER_JOURNEY_PATH')\n\t\tawait this.createDirectory(dirname(path), options)\n\t\toptions?.signal?.throwIfAborted()\n\t\ttry {\n\t\t\tawait mkdir(path)\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error && 'code' in error && error.code === 'EEXIST'))\n\t\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t\tawait this.check(path, options)\n\t}\n\n\t/** Reads an existing file without collapsing a fault to absence. @param path - File @param options - Cancellation options @returns Bytes as UTF-8, or absence */\n\tasync read(path: string, options?: BrowserStoreOptions): Promise<string | undefined> {\n\t\tif (!(await this.check(path, options))) return undefined\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst value = await readFile(path, { encoding: 'utf8', signal: options?.signal })\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\treturn value\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT') return undefined\n\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t}\n\n\t/** Atomically replaces a file and cleans its owned temporary file on failure. @param path - Destination @param value - Bytes or UTF-8 @param options - Cancellation options */\n\tasync write(\n\t\tpath: string,\n\t\tvalue: string | Uint8Array,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<void> {\n\t\tconst temporary = this.resolvePath(dirname(path), `.${randomUUID()}.tmp`)\n\t\tlet owned = false\n\t\ttry {\n\t\t\tawait this.check(path, options)\n\t\t\tawait this.check(temporary, options)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst file = await open(temporary, 'wx')\n\t\t\towned = true\n\t\t\ttry {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tawait file.writeFile(value, { signal: options?.signal })\n\t\t\t} finally {\n\t\t\t\tawait file.close()\n\t\t\t}\n\t\t\tawait this.check(path, options)\n\t\t\tawait this.check(temporary, options)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tawait rename(temporary, path)\n\t\t\towned = false\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.translateError(path, error)\n\t\t} finally {\n\t\t\tif (owned) await this.remove(temporary)\n\t\t}\n\t}\n\n\t/** Removes a checked file, accepting absence. @param path - File @param options - Cancellation options */\n\tasync remove(path: string, options?: BrowserStoreOptions): Promise<void> {\n\t\tif (!(await this.check(path, options))) return\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tawait unlink(path)\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tif (!(error instanceof Error && 'code' in error && error.code === 'ENOENT'))\n\t\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t}\n\n\t/**\n\t * Holds a directory lock through a mutation and releases only its named entry.\n\t * @remarks Reclaims dead or empty locks within a bounded attempt count; a live or unknown holder refuses.\n\t * @param path - Lock directory\n\t * @param action - Mutation inside the lock\n\t * @param options - Cancellation options\n\t * @returns The mutation result\n\t */\n\tasync lock<T>(path: string, action: () => Promise<T>, options?: BrowserStoreOptions): Promise<T> {\n\t\tawait this.createDirectory(dirname(path), options)\n\t\tconst name = formatBrowserLockEntry(process.pid, randomUUID())\n\t\tconst entry = this.resolvePath(path, name)\n\t\tfor (let attempt = 0; attempt < BROWSER_JOURNEY_LOCK_ATTEMPTS; attempt += 1) {\n\t\t\tawait this.check(path, options)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tawait mkdir(path)\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof Error && 'code' in error && error.code === 'EEXIST'))\n\t\t\t\t\tthrow this.translateError(path, error)\n\t\t\t\tconst entries = await this.#readLock(path, options)\n\t\t\t\tif (entries === undefined) continue\n\t\t\t\tif (entries.length > 1) break\n\t\t\t\tconst holder = entries[0]\n\t\t\t\tif (holder !== undefined) {\n\t\t\t\t\tconst pid = parseBrowserLockEntry(holder)\n\t\t\t\t\tif (pid === undefined) break\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 0)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t} catch (cause) {\n\t\t\t\t\t\tif (!(cause instanceof Error && 'code' in cause && cause.code === 'ESRCH')) break\n\t\t\t\t\t}\n\t\t\t\t\tif (!(await this.#unlinkLock(this.resolvePath(path, holder)))) continue\n\t\t\t\t}\n\t\t\t\tawait this.#removeLock(path)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlet owned = false\n\t\t\ttry {\n\t\t\t\tawait this.check(entry, options)\n\t\t\t\ttry {\n\t\t\t\t\tconst file = await open(entry, 'wx')\n\t\t\t\t\towned = true\n\t\t\t\t\tawait file.close()\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT') continue\n\t\t\t\t\tthrow this.translateError(entry, error)\n\t\t\t\t}\n\t\t\t\t// An empty directory can be replaced between mkdir and entry creation.\n\t\t\t\tconst entries = await this.#readLock(path, options)\n\t\t\t\tif (entries?.length !== 1 || entries[0] !== name) break\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\treturn await action()\n\t\t\t} finally {\n\t\t\t\tif (owned) await this.#unlinkLock(entry)\n\t\t\t\tawait this.#removeLock(path)\n\t\t\t}\n\t\t}\n\t\tthrow new BrowserError(`Journey is locked: ${path}`, 'BROWSER_JOURNEY_LOCKED')\n\t}\n\n\t/**\n\t * Lists readable entries in sorted order with a bounded page and one extra readable probe.\n\t * @param path - Parent directory\n\t * @param reader - Entry reader\n\t * @param options - Paging and cancellation\n\t * @returns Page and observed entry faults\n\t */\n\tasync list<T>(\n\t\tpath: string,\n\t\treader: (name: string) => Promise<T | undefined>,\n\t\toptions?: BrowserStoreOptions & { readonly offset?: number; readonly limit?: number },\n\t): Promise<BrowserStorePage<T>> {\n\t\tconst offset = options?.offset ?? 0\n\t\tconst requested = options?.limit ?? this.#limit\n\t\tvalidateBrowserStorePage(offset, requested)\n\t\tconst limit = Math.min(requested, this.#limit)\n\t\tconst entries: T[] = []\n\t\tconst faults: BrowserStoreFault[] = []\n\t\tif (!(await this.check(path, options))) return { entries, faults, truncated: false }\n\t\tlet names: string[]\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tnames = (await readdir(path)).sort()\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t\tlet count = 0\n\t\tfor (const name of names) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tconst entry = await reader(name)\n\t\t\t\tif (entry === undefined) continue\n\t\t\t\tif (count++ < offset) continue\n\t\t\t\tif (entries.length === limit) return { entries, faults, truncated: true }\n\t\t\t\tentries.push(entry)\n\t\t\t} catch (error) {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tconst reason = error instanceof BrowserError ? error.context?.['reason'] : undefined\n\t\t\t\tfaults.push({\n\t\t\t\t\tname,\n\t\t\t\t\treason:\n\t\t\t\t\t\ttypeof reason === 'string'\n\t\t\t\t\t\t\t? reason\n\t\t\t\t\t\t\t: error instanceof BrowserError && error.code === 'BROWSER_JOURNEY_PATH'\n\t\t\t\t\t\t\t\t? 'The entry path is refused'\n\t\t\t\t\t\t\t\t: error instanceof BrowserError && error.code === 'BROWSER_JOURNEY_ACCESS'\n\t\t\t\t\t\t\t\t\t? 'Permission denied'\n\t\t\t\t\t\t\t\t\t: error instanceof BrowserError && error.code === 'BROWSER_JOURNEY_FORMAT'\n\t\t\t\t\t\t\t\t\t\t? 'Unknown file format'\n\t\t\t\t\t\t\t\t\t\t: 'The stored entry is malformed or unreadable',\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\treturn { entries, faults, truncated: false }\n\t}\n\n\t/**\n\t * Allocates a run directory exclusively, retrying colliding producer candidates.\n\t * @param parent - Checked parent directory\n\t * @param candidate - Producer id source\n\t * @param options - Cancellation options\n\t * @returns Allocated id and absolute directory\n\t */\n\tasync allocate(\n\t\tparent: string,\n\t\tcandidate: () => string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<{ readonly id: string; readonly path: string }> {\n\t\tawait this.createDirectory(parent, options)\n\t\tfor (;;) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst id = candidate()\n\t\t\tthis.validateId(id)\n\t\t\tconst path = this.resolvePath(parent, id)\n\t\t\tawait this.check(path, options)\n\t\t\ttry {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tawait mkdir(path)\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\treturn { id, path }\n\t\t\t} catch (error) {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tif (error instanceof Error && 'code' in error && error.code === 'EEXIST') continue\n\t\t\t\tthrow this.translateError(path, error)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Translates filesystem and validation failures with their path. @param path - Failed path @param error - Cause @returns Coded error */\n\ttranslateError(path: string, error: unknown): BrowserError {\n\t\tconst code = error instanceof Error && 'code' in error ? error.code : undefined\n\t\treturn new BrowserError(\n\t\t\t`${path}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\tcode === 'EACCES' || code === 'EPERM'\n\t\t\t\t? 'BROWSER_JOURNEY_ACCESS'\n\t\t\t\t: error instanceof BrowserError && code !== 'BROWSER_JOURNEY_INVALID'\n\t\t\t\t\t? error.code\n\t\t\t\t\t: 'BROWSER_JOURNEY_FILE',\n\t\t\t{ path },\n\t\t)\n\t}\n\tasync #readLock(\n\t\tpath: string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<readonly string[] | undefined> {\n\t\tawait this.check(path, options)\n\t\ttry {\n\t\t\tconst entries = await readdir(path, { withFileTypes: true })\n\t\t\tfor (const entry of entries) {\n\t\t\t\tawait this.check(this.resolvePath(path, entry.name), options)\n\t\t\t\tif (!entry.isFile())\n\t\t\t\t\tthrow new BrowserError(`Journey is locked: ${path}`, 'BROWSER_JOURNEY_LOCKED')\n\t\t\t}\n\t\t\treturn entries.map((entry) => entry.name)\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && 'code' in error) {\n\t\t\t\tif (error.code === 'ENOENT') return undefined\n\t\t\t\tif (error.code === 'ENOTDIR')\n\t\t\t\t\tthrow new BrowserError(`Journey is locked: ${path}`, 'BROWSER_JOURNEY_LOCKED')\n\t\t\t}\n\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t}\n\n\tasync #unlinkLock(path: string): Promise<boolean> {\n\t\tawait this.check(path)\n\t\ttry {\n\t\t\tawait unlink(path)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tif (\n\t\t\t\terror instanceof Error &&\n\t\t\t\t'code' in error &&\n\t\t\t\t(error.code === 'ENOENT' || error.code === 'ENOTEMPTY')\n\t\t\t)\n\t\t\t\treturn false\n\t\t\tthrow new BrowserError(`Cannot remove lock entry: ${path}`, 'BROWSER_JOURNEY_ACCESS', {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t}\n\n\tasync #removeLock(path: string): Promise<void> {\n\t\tawait this.check(path)\n\t\ttry {\n\t\t\tawait rmdir(path)\n\t\t} catch (error) {\n\t\t\tif (\n\t\t\t\terror instanceof Error &&\n\t\t\t\t'code' in error &&\n\t\t\t\t(error.code === 'ENOENT' || error.code === 'ENOTEMPTY')\n\t\t\t)\n\t\t\t\treturn\n\t\t\tthrow new BrowserError(`Cannot remove lock directory: ${path}`, 'BROWSER_JOURNEY_ACCESS', {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t}\n}\n","import type {\n\tBrowserJourney,\n\tBrowserJourneyRevision,\n\tBrowserJourneyStoreInterface,\n\tBrowserStoreOptions,\n\tBrowserStorePage,\n} from '@src/core'\nimport type { FileBrowserStoreOptions } from '../types.js'\nimport { isRecord, parseJSON } from '@orkestrel/contract'\nimport {\n\tBROWSER_JOURNEY_NAME_PATTERN,\n\tBrowserError,\n\tvalidateBrowserJourney,\n\tnormalizeBrowserJourneyReason,\n} from '@src/core'\nimport {\n\tBROWSER_JOURNEY_SNAPSHOT_FILE,\n\tBROWSER_JOURNEY_REVISION_FILE,\n\tBROWSER_JOURNEY_LOCK_DIRECTORY,\n} from '../constants.js'\nimport { FileBrowserStore } from './FileBrowserStore.js'\n\n/**\n * Persists journeys with exclusive writes and revision counters retained across deletion.\n * @remarks Requires an existing root. A live holder refuses immediately; dead or empty locks are reclaimed within a bounded attempt count.\n * @example\n * const store = new FileBrowserJourneyStore({ root: directory })\n * await store.set(journey)\n */\nexport class FileBrowserJourneyStore implements BrowserJourneyStoreInterface {\n\treadonly #files: FileBrowserStore\n\n\tconstructor(options: FileBrowserStoreOptions) {\n\t\tthis.#files = new FileBrowserStore(options)\n\t}\n\n\tasync get(\n\t\tname: string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<BrowserJourneyRevision | undefined> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tconst path = this.#files.resolvePath(name, BROWSER_JOURNEY_SNAPSHOT_FILE)\n\t\tconst source = await this.#files.read(path, options)\n\t\tif (source === undefined) return undefined\n\t\ttry {\n\t\t\tconst value = parseJSON(source)\n\t\t\tif (\n\t\t\t\t!isRecord(value) ||\n\t\t\t\ttypeof value['revision'] !== 'number' ||\n\t\t\t\t!Number.isSafeInteger(value['revision']) ||\n\t\t\t\tvalue['revision'] < 1\n\t\t\t)\n\t\t\t\tthrow new BrowserError('Malformed journey revision', 'BROWSER_JOURNEY_FILE')\n\t\t\tif (!isRecord(value['journey']) || !('format' in value['journey']))\n\t\t\t\tthrow new BrowserError('Missing journey format', 'BROWSER_JOURNEY_FILE')\n\t\t\tvalidateBrowserJourney(value['journey'])\n\t\t\tif (value['journey'].name !== name)\n\t\t\t\tthrow new BrowserError('Journey name differs from its directory', 'BROWSER_JOURNEY_FILE')\n\t\t\treturn { journey: value['journey'], revision: value['revision'] }\n\t\t} catch (error) {\n\t\t\tconst translated = this.#files.translateError(path, error)\n\t\t\tthrow new BrowserError(translated.message, translated.code, {\n\t\t\t\t...translated.context,\n\t\t\t\treason: normalizeBrowserJourneyReason(error),\n\t\t\t})\n\t\t}\n\t}\n\n\tasync set(\n\t\tjourney: BrowserJourney,\n\t\texpected?: number,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<BrowserJourneyRevision> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(journey.name)\n\t\tvalidateBrowserJourney(journey)\n\t\tconst owned = structuredClone(journey)\n\t\tconst path = this.#files.resolvePath(owned.name, BROWSER_JOURNEY_SNAPSHOT_FILE)\n\t\tconst counter = this.#files.resolvePath(owned.name, BROWSER_JOURNEY_REVISION_FILE)\n\t\treturn this.#files.lock(\n\t\t\tthis.#files.resolvePath(owned.name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\tconst current = await this.get(owned.name, options)\n\t\t\t\tif (expected !== undefined && expected !== (current?.revision ?? 0))\n\t\t\t\t\tthrow new BrowserError(\n\t\t\t\t\t\t`Journey ${owned.name} changed since you read it`,\n\t\t\t\t\t\t'BROWSER_JOURNEY_STALE',\n\t\t\t\t\t)\n\t\t\t\tconst source = await this.#files.read(counter, options)\n\t\t\t\tconst previous = source === undefined ? 0 : Number(source)\n\t\t\t\tif (!Number.isSafeInteger(previous) || previous < 0 || source?.trim() === '')\n\t\t\t\t\tthrow new BrowserError(`Malformed revision: ${counter}`, 'BROWSER_JOURNEY_FILE')\n\t\t\t\tconst revision = Math.max(previous, current?.revision ?? 0) + 1\n\t\t\t\tif (!Number.isSafeInteger(revision))\n\t\t\t\t\tthrow new BrowserError(`Exhausted revision: ${counter}`, 'BROWSER_JOURNEY_FILE')\n\t\t\t\tconst saved = { journey: owned, revision }\n\t\t\t\tawait this.#files.write(path, JSON.stringify(saved), options)\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#files.write(counter, String(revision), options)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Rollback and lock cleanup must finish even when the caller aborts.\n\t\t\t\t\tif (current === undefined) await this.#files.remove(path)\n\t\t\t\t\telse await this.#files.write(path, JSON.stringify(current))\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\treturn saved\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync delete(name: string, options?: BrowserStoreOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tawait this.#files.lock(\n\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\tconst current = await this.get(name, options)\n\t\t\t\tif (current === undefined) return\n\t\t\t\tconst counter = this.#files.resolvePath(name, BROWSER_JOURNEY_REVISION_FILE)\n\t\t\t\tconst source = await this.#files.read(counter, options)\n\t\t\t\tconst previous = source === undefined ? 0 : Number(source)\n\t\t\t\tif (!Number.isSafeInteger(previous) || previous < 0 || source?.trim() === '')\n\t\t\t\t\tthrow new BrowserError(`Malformed revision: ${counter}`, 'BROWSER_JOURNEY_FILE')\n\t\t\t\t// Preserve the committed revision even if a process exited before updating its counter.\n\t\t\t\tawait this.#files.write(counter, String(Math.max(previous, current.revision ?? 0)), options)\n\t\t\t\tawait this.#files.remove(\n\t\t\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_SNAPSHOT_FILE),\n\t\t\t\t\toptions,\n\t\t\t\t)\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync list(\n\t\toptions?: BrowserStoreOptions & { readonly offset?: number; readonly limit?: number },\n\t): Promise<BrowserStorePage<BrowserJourneyRevision>> {\n\t\toptions?.signal?.throwIfAborted()\n\t\treturn this.#files.list(\n\t\t\tthis.#files.resolvePath(),\n\t\t\tasync (name) => {\n\t\t\t\tif (!BROWSER_JOURNEY_NAME_PATTERN.test(name)) return undefined\n\t\t\t\treturn this.get(name, options)\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n}\n","import type {\n\tBrowserRun,\n\tBrowserRunSlot,\n\tBrowserRunStoreInterface,\n\tBrowserStoreOptions,\n\tBrowserStorePage,\n} from '@src/core'\nimport type { FileBrowserStoreOptions } from '../types.js'\nimport { lstat, readdir, rm } from 'node:fs/promises'\nimport { isRecord, parseJSON } from '@orkestrel/contract'\nimport {\n\tBROWSER_JOURNEY_FORMAT_VERSION,\n\tBrowserError,\n\tgenerateBrowserRunId,\n\tvalidateBrowserRun,\n} from '@src/core'\nimport {\n\tBROWSER_RUN_FILE,\n\tBROWSER_RUN_DIRECTORY,\n\tBROWSER_JOURNEY_LOCK_DIRECTORY,\n} from '../constants.js'\nimport { FileBrowserStore } from './FileBrowserStore.js'\n\n/**\n * Persists runs and captures only in directories allocated by this instance.\n * @remarks Requires an existing root. Reopened stores can read and delete saved runs.\n * @example\n * const store = new FileBrowserRunStore({ root: directory })\n * const slot = await store.open('check-ready')\n */\nexport class FileBrowserRunStore implements BrowserRunStoreInterface {\n\treadonly #files: FileBrowserStore\n\treadonly #slots = new WeakMap<BrowserRunSlot, string>()\n\treadonly #directories = new Set<string>()\n\n\tconstructor(options: FileBrowserStoreOptions) {\n\t\tthis.#files = new FileBrowserStore(options)\n\t}\n\n\tasync open(name: string, options?: BrowserStoreOptions): Promise<BrowserRunSlot> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\treturn this.#files.lock(\n\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\tconst directory = await this.#files.allocate(\n\t\t\t\t\tthis.#files.resolvePath(name, BROWSER_RUN_DIRECTORY),\n\t\t\t\t\tgenerateBrowserRunId,\n\t\t\t\t\toptions,\n\t\t\t\t)\n\t\t\t\tconst slot = Object.freeze({ id: directory.id, directory: directory.path })\n\t\t\t\tthis.#directories.add(directory.path)\n\t\t\t\tthis.#slots.set(slot, directory.path)\n\t\t\t\treturn slot\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync get(\n\t\tname: string,\n\t\tid: string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<BrowserRun | undefined> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tthis.#files.validateId(id)\n\t\tconst path = this.#files.resolvePath(name, BROWSER_RUN_DIRECTORY, id, BROWSER_RUN_FILE)\n\t\tconst source = await this.#files.read(path, options)\n\t\tif (source === undefined) return undefined\n\t\ttry {\n\t\t\tconst value = parseJSON(source)\n\t\t\tif (!isRecord(value) || !('format' in value))\n\t\t\t\tthrow new BrowserError('Missing run format', 'BROWSER_JOURNEY_FILE')\n\t\t\tif (\n\t\t\t\tvalue['format'] === BROWSER_JOURNEY_FORMAT_VERSION &&\n\t\t\t\t(!isRecord(value['journey']) || !('format' in value['journey']))\n\t\t\t)\n\t\t\t\tthrow new BrowserError('Missing run journey format', 'BROWSER_JOURNEY_FILE')\n\t\t\tvalidateBrowserRun(value)\n\t\t\tif (value.id !== id || value.journey.name !== name)\n\t\t\t\tthrow new BrowserError('Run identity differs from its directory', 'BROWSER_JOURNEY_FILE')\n\t\t\treturn value\n\t\t} catch (error) {\n\t\t\tthrow this.#files.translateError(path, error)\n\t\t}\n\t}\n\n\tasync set(run: BrowserRun, options?: BrowserStoreOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(run.journey.name)\n\t\tthis.#files.validateId(run.id)\n\t\tvalidateBrowserRun(run)\n\t\tconst source = JSON.stringify(run)\n\t\tconst directory = this.#files.resolvePath(run.journey.name, BROWSER_RUN_DIRECTORY, run.id)\n\t\tawait this.#requireDirectory(directory, options)\n\t\tawait this.#files.write(this.#files.resolvePath(directory, BROWSER_RUN_FILE), source, options)\n\t}\n\n\tasync capture(\n\t\tslot: BrowserRunSlot,\n\t\tname: string,\n\t\tbytes: Uint8Array,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<string> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tconst directory = this.#slots.get(slot)\n\t\tif (directory === undefined || !/^s[1-9]\\d*\\.png$/.test(name))\n\t\t\tthrow new BrowserError(\n\t\t\t\t'Capture requires an opened slot and an sN.png name',\n\t\t\t\t'BROWSER_JOURNEY_PATH',\n\t\t\t)\n\t\tconst owned = new Uint8Array(bytes)\n\t\tawait this.#requireDirectory(directory, options)\n\t\tawait this.#files.write(this.#files.resolvePath(directory, name), owned, options)\n\t\treturn name\n\t}\n\n\tasync delete(name: string, id: string, options?: BrowserStoreOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tthis.#files.validateId(id)\n\t\tconst directory = this.#files.resolvePath(name, BROWSER_RUN_DIRECTORY, id)\n\t\tawait this.#files.check(this.#files.resolvePath(directory, BROWSER_RUN_FILE), options)\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tawait rm(directory, { recursive: true, force: true, maxRetries: 3 })\n\t\t\tthis.#directories.delete(directory)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.#files.translateError(directory, error)\n\t\t}\n\t}\n\n\tasync clear(name: string, options?: BrowserStoreOptions): Promise<number> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tconst parent = this.#files.resolvePath(name, BROWSER_RUN_DIRECTORY)\n\t\tif (!(await this.#files.check(parent, options))) return 0\n\t\treturn this.#files.lock(\n\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\ttry {\n\t\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\t\tconst ids = await readdir(parent)\n\t\t\t\t\t// Check the whole removal before deleting any run, including unsaved slots.\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tthis.#files.validateId(id)\n\t\t\t\t\t\tawait this.#files.check(this.#files.resolvePath(parent, id, BROWSER_RUN_FILE), options)\n\t\t\t\t\t}\n\t\t\t\t\tfor (const id of ids) await this.delete(name, id, options)\n\t\t\t\t\treturn ids.length\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\t\tthrow this.#files.translateError(parent, error)\n\t\t\t\t}\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync list(\n\t\tname: string,\n\t\toptions?: BrowserStoreOptions & { readonly offset?: number; readonly limit?: number },\n\t): Promise<BrowserStorePage<BrowserRun>> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\treturn this.#files.list(\n\t\t\tthis.#files.resolvePath(name, BROWSER_RUN_DIRECTORY),\n\t\t\t(id) => this.get(name, id, options),\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync #requireDirectory(directory: string, options?: BrowserStoreOptions): Promise<void> {\n\t\tif (!this.#directories.has(directory) || !(await this.#files.check(directory, options)))\n\t\t\tthrow new BrowserError(\n\t\t\t\t`Run directory was not opened or is missing: ${directory}`,\n\t\t\t\t'BROWSER_JOURNEY_PATH',\n\t\t\t)\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst status = await lstat(directory)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tif (!status.isDirectory())\n\t\t\t\tthrow new BrowserError(\n\t\t\t\t\t`Run directory is not a directory: ${directory}`,\n\t\t\t\t\t'BROWSER_JOURNEY_PATH',\n\t\t\t\t)\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.#files.translateError(directory, error)\n\t\t}\n\t}\n}\n","import type {\n\tBrowserJourneyStoreInterface,\n\tBrowserRunStoreInterface,\n\tCDPTransportInterface,\n\tBrowserWriterInterface,\n} from '@src/core'\nimport type {\n\tFileBrowserStoreOptions,\n\tBrowserInterface,\n\tBrowserMCPServerInterface,\n\tBrowserMCPServerOptions,\n\tBrowserOptions,\n\tWebSocketCDPTransportOptions,\n} from './types.js'\nimport { BrowserMCPServer } from './BrowserMCPServer.js'\nimport { FileBrowserJourneyStore } from './stores/FileBrowserJourneyStore.js'\nimport { FileBrowserRunStore } from './stores/FileBrowserRunStore.js'\nimport { Browser } from './Browser.js'\nimport { WebSocketCDPTransport } from './transports/WebSocketCDPTransport.js'\nimport { FileBrowserWriter } from './writers/FileBrowserWriter.js'\n\n/**\n * Creates a raw-CDP `BrowserInterface` façade with discovery, connection, and lifecycle\n * management.\n *\n * @param options - Connection, launch, and viewport configuration\n * @returns A {@link BrowserInterface}\n *\n * @example Connect to a browser and drive a page\n * ```ts\n * import { createBrowser } from '@orkestrel/browser/server'\n *\n * const browser = createBrowser({ headless: true })\n * await browser.connect() // CDP endpoint discovery → connect, else launch\n * const page = await browser.create({ url: 'https://example.com' })\n * await (await page.elements.find({ css: '#accept' }))[0]?.click()\n * const shot = await page.screenshot({ path: './out.png' })\n * await browser.destroy()\n * ```\n */\nexport function createBrowser(options?: BrowserOptions): BrowserInterface {\n\treturn new Browser(options)\n}\n\n/**\n * Creates a Node `WebSocket`-backed `CDPTransportInterface` for the given CDP debugger URL.\n *\n * @param options - The CDP WebSocket debugger URL (and optional timeout)\n * @returns A {@link CDPTransportInterface}\n */\nexport function createCDPTransport(options: WebSocketCDPTransportOptions): CDPTransportInterface {\n\treturn new WebSocketCDPTransport(options)\n}\n\n/**\n * Creates a filesystem-backed `BrowserWriterInterface` that persists bytes through\n * `node:fs/promises`.\n *\n * @returns A {@link BrowserWriterInterface} that persists bytes through `node:fs/promises`\n */\nexport function createBrowserWriter(): BrowserWriterInterface {\n\treturn new FileBrowserWriter()\n}\n\n/**\n * Creates a journey store over an existing filesystem root.\n * @param options - Root and listing cap\n * @returns A durable journey store\n * @example\n * const store = createFileBrowserJourneyStore({ root: directory })\n */\nexport function createFileBrowserJourneyStore(\n\toptions: FileBrowserStoreOptions,\n): BrowserJourneyStoreInterface {\n\treturn new FileBrowserJourneyStore(options)\n}\n\n/**\n * Creates a run store over an existing filesystem root.\n * @param options - Root and listing cap\n * @returns A durable run and capture store\n * @example\n * const store = createFileBrowserRunStore({ root: directory })\n */\nexport function createFileBrowserRunStore(\n\toptions: FileBrowserStoreOptions,\n): BrowserRunStoreInterface {\n\treturn new FileBrowserRunStore(options)\n}\n\n/**\n * Creates the browse server, which serves the browser vocabulary and the journey tools over the\n * Model Context Protocol on stdio and launches Chromium on the first tool call.\n *\n * @param options - The root, the launch, the journeys' read-only switch, and the streams\n * @returns A {@link BrowserMCPServerInterface} that reads nothing until `start()`\n *\n * @example\n * ```ts\n * import { createBrowserMCPServer } from '@orkestrel/browser/server'\n *\n * const server = createBrowserMCPServer({ root: 'tmp/browsers', headless: true })\n * await server.start() // answers tools/list before Chromium starts\n * await server.destroy()\n * ```\n */\nexport function createBrowserMCPServer(\n\toptions?: BrowserMCPServerOptions,\n): BrowserMCPServerInterface {\n\treturn new BrowserMCPServer(options)\n}\n","import type { ChildProcess } from 'node:child_process'\nimport type {\n\tBrowserConnection,\n\tBrowserDiscoveryResult,\n\tBrowserEngine,\n\tBrowserEventMap,\n\tBrowserInterface,\n\tBrowserOptions,\n\tBrowserProfileResult,\n\tBrowserStatus,\n} from './types.js'\nimport type {\n\tBrowserContextInterface,\n\tBrowserContextOptions,\n\tBrowserPageInterface,\n\tBrowserPageOptions,\n\tCDPTarget,\n\tCDPTransportInterface,\n} from '@src/core'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport { addAbortListener, once } from 'node:events'\nimport { isArray, isError, isInteger, isRecord, isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport {\n\tBrowserConnectionError,\n\tBrowserContext,\n\tBrowserTransition,\n\tBROWSER_DEFAULT_TIMEOUT_MS,\n\tCDPClient,\n\tisBrowserConnectionError,\n\tvalidateBrowserContextOptions,\n} from '@src/core'\nimport { BrowserDestroyedError, BrowserNotConnectedError } from './errors.js'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_DEFAULT_CDP_PORT,\n\tBROWSER_DEFAULT_HOST,\n\tBROWSER_DRAIN_INTERVAL_MS,\n\tBROWSER_KILL_GRACE_MS,\n\tBROWSER_PORT_PROBE_TIMEOUT_MS,\n\tBROWSER_PROCESS_EXIT_CAUSE,\n\tBROWSER_TRANSPORT_LOSS_CAUSE,\n\tBROWSER_TRANSPORT_LOSS_DEFER_MS,\n} from './constants.js'\nimport {\n\tbrowserToEngine,\n\tcreateBrowserProfile,\n\tfindSystemBrowser,\n\tlaunchBrowserProcess,\n\tparseBrowserEngine,\n\treadBrowserEndpoint,\n\tremoveBrowserProfile,\n} from './helpers.js'\nimport { createCDPTransport, createBrowserWriter } from './factories.js'\n\n// === Browser\n\n/**\n * Discovers, launches, connects to, and owns Chromium-family browser sessions.\n *\n * @example\n * ```ts\n * import { Browser } from '@orkestrel/browser/server'\n *\n * const browser = new Browser({ headless: true })\n * await browser.connect()\n * const page = await browser.create({ url: 'https://example.com' })\n * await browser.destroy()\n * ```\n */\nexport class Browser implements BrowserInterface {\n\treadonly #emitter: Emitter<BrowserEventMap>\n\treadonly #options: BrowserOptions\n\treadonly #abort = new AbortController()\n\treadonly #cdpPort: number\n\treadonly #cdpHost: string\n\t#engine: BrowserEngine\n\t#status: BrowserStatus = 'idle'\n\t#connection: BrowserConnection | undefined\n\t#owned: boolean | undefined\n\t#endpoint: string | undefined\n\t#client: CDPClient | undefined\n\t#process: ChildProcess | undefined\n\t// Identifier the launcher handed the endpoint to when it re-executed the\n\t// browser and exited before CDP became ready. Undefined whenever the\n\t// spawned child is itself the process serving the endpoint.\n\t#servingPid: number | undefined\n\t#profile: BrowserProfileResult | undefined\n\t#contexts: BrowserContext[] = []\n\t#destroyed = false\n\treadonly #connecting: BrowserTransition = new BrowserTransition()\n\treadonly #disconnecting: BrowserTransition = new BrowserTransition()\n\t#exitCleanup: Promise<void> | undefined\n\t#shutdown: Promise<void> | undefined\n\t#transport: CDPTransportInterface | undefined\n\treadonly #transportCloseHandler = this.#handleTransportLoss.bind(this)\n\treadonly #transportErrorHandler = this.#handleTransportLoss.bind(this)\n\treadonly #processExitHandler = this.#handleProcessExit.bind(this)\n\n\tconstructor(options?: BrowserOptions) {\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#options = options ?? {}\n\t\tthis.#engine =\n\t\t\tthis.#options.engine ??\n\t\t\t(this.#options.executable !== undefined\n\t\t\t\t? (parseBrowserEngine(this.#options.executable) ?? 'chromium')\n\t\t\t\t: 'chromium')\n\t\tthis.#cdpPort = this.#options.cdp?.port ?? BROWSER_DEFAULT_CDP_PORT\n\t\tthis.#cdpHost = this.#options.cdp?.host ?? BROWSER_DEFAULT_HOST\n\n\t\tqueueMicrotask(() => this.#emitter.emit('idle'))\n\t}\n\n\tget emitter(): EmitterInterface<BrowserEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget engine(): BrowserEngine {\n\t\treturn this.#engine\n\t}\n\n\tget status(): BrowserStatus {\n\t\treturn this.#status\n\t}\n\n\tget connection(): BrowserConnection | undefined {\n\t\treturn this.#connection\n\t}\n\n\tget owned(): boolean | undefined {\n\t\treturn this.#owned\n\t}\n\n\tget pid(): number | undefined {\n\t\treturn this.#servingPid ?? this.#process?.pid\n\t}\n\n\tasync discover(): Promise<BrowserDiscoveryResult> {\n\t\tconst result = await this.#discoverCDP()\n\t\tthis.#emitter.emit('discover', result)\n\t\treturn result\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\n\t\tconst active = this.#connecting.pending\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\t\tif (this.#status === 'connected') return\n\n\t\tawait this.#connecting.execute(() => this.#establish())\n\t}\n\n\tadopt(): void {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tif (\n\t\t\tthis.#status !== 'connected' ||\n\t\t\tthis.#client === undefined ||\n\t\t\tthis.#endpoint === undefined\n\t\t) {\n\t\t\tthrow new BrowserNotConnectedError()\n\t\t}\n\t\tthis.#owned = true\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.#destroyed) return\n\n\t\tconst disconnecting = this.#disconnecting.pending\n\t\tconst connecting = this.#connecting.pending\n\t\tif (disconnecting !== undefined) await disconnecting\n\t\tif (connecting !== undefined) await connecting.catch(() => undefined)\n\t\tif (this.#destroyed) return\n\t\tif (this.#status !== 'connected' || this.#client === undefined) return\n\n\t\tawait this.#disconnecting.execute(() => this.#detach())\n\t}\n\n\tcontext(index?: number): BrowserContextInterface | undefined {\n\t\tconst i = index ?? 0\n\t\tif (i < 0 || i >= this.#contexts.length) return undefined\n\t\treturn this.#contexts[i]\n\t}\n\n\tcontexts(): readonly BrowserContextInterface[] {\n\t\treturn [...this.#contexts]\n\t}\n\n\tasync isolate(options?: BrowserContextOptions): Promise<BrowserContextInterface> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tconst client = this.#client\n\t\tif (this.#status !== 'connected' || client === undefined) {\n\t\t\tthrow new BrowserNotConnectedError()\n\t\t}\n\t\tvalidateBrowserContextOptions(options)\n\t\tconst params: Record<string, unknown> = { disposeOnDetach: false }\n\t\tif (options?.proxy !== undefined) {\n\t\t\tparams['proxyServer'] = options.proxy.server\n\t\t\tif (options.proxy.bypass !== undefined) {\n\t\t\t\tparams['proxyBypassList'] = options.proxy.bypass.join(',')\n\t\t\t}\n\t\t}\n\t\tif (options?.origins !== undefined) {\n\t\t\tparams['originsWithUniversalNetworkAccess'] = [...options.origins]\n\t\t}\n\t\tconst result = await client.send('Target.createBrowserContext', params)\n\t\tif (!isRecord(result) || !isString(result['browserContextId'])) {\n\t\t\tthrow new BrowserConnectionError('Failed to create isolated browser context')\n\t\t}\n\t\tconst id = result['browserContextId']\n\t\tconst context = new BrowserContext(\n\t\t\tclient,\n\t\t\tid,\n\t\t\toptions?.emulation?.viewport ?? this.#options.viewport,\n\t\t\tcreateBrowserWriter(),\n\t\t\toptions?.emulation,\n\t\t\toptions?.downloads,\n\t\t\toptions,\n\t\t)\n\n\t\ttry {\n\t\t\tif (options?.downloads !== undefined) {\n\t\t\t\tawait client.send('Browser.setDownloadBehavior', {\n\t\t\t\t\tbehavior: options.downloads.named === true ? 'allowAndName' : 'allow',\n\t\t\t\t\tbrowserContextId: id,\n\t\t\t\t\tdownloadPath: options.downloads.path,\n\t\t\t\t\teventsEnabled: true,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait context.close().catch(() => undefined)\n\t\t\tthrow error\n\t\t}\n\n\t\tthis.#registerContext(context)\n\t\treturn context\n\t}\n\n\tasync create(options?: BrowserPageOptions): Promise<BrowserPageInterface> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tconst client = this.#client\n\t\tif (this.#status !== 'connected' || client === undefined) {\n\t\t\tthrow new BrowserNotConnectedError()\n\t\t}\n\n\t\tlet context = this.#contexts[0]\n\t\tif (context === undefined) {\n\t\t\tcontext = new BrowserContext(client, undefined, this.#options.viewport, createBrowserWriter())\n\t\t\tthis.#registerContext(context)\n\t\t}\n\n\t\tconst page = await context.create(options)\n\t\tthis.#emitter.emit('page', page)\n\t\treturn page\n\t}\n\n\tdestroy(): Promise<void> {\n\t\tconst active = this.#shutdown\n\t\tif (active !== undefined) return active\n\t\tif (this.#destroyed) return Promise.resolve()\n\n\t\tthis.#destroyed = true\n\t\tthis.#abort.abort()\n\t\tconst shutdown = this.#destroyResources()\n\t\tthis.#shutdown = shutdown\n\t\treturn shutdown\n\t}\n\n\tclose(): Promise<void> {\n\t\tconst active = this.#shutdown\n\t\tif (active !== undefined) return active\n\t\tif (this.#destroyed) return Promise.resolve()\n\n\t\tthis.#destroyed = true\n\t\tthis.#abort.abort()\n\t\tconst shutdown = this.#closeResources()\n\t\tthis.#shutdown = shutdown\n\t\treturn shutdown\n\t}\n\n\t// === Private helpers\n\n\tasync #establish(): Promise<void> {\n\t\tconst disconnecting = this.#disconnecting.pending\n\t\tif (disconnecting !== undefined) await disconnecting\n\t\tawait this.#settleExit()\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tif (this.#status === 'connected') return\n\n\t\tthis.#assertNotAborted()\n\t\tthis.#status = 'connecting'\n\n\t\ttry {\n\t\t\tif (this.#owned === true && this.#endpoint !== undefined) {\n\t\t\t\tawait this.#connectCDP(this.#endpoint)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst endpoint = this.#options.cdp?.endpoint\n\t\t\tif (endpoint !== undefined) {\n\t\t\t\tawait this.#connectCDP(endpoint)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst discover = this.#options.cdp?.discover ?? true\n\t\t\tif (discover) {\n\t\t\t\tconst discovery = await this.#raceAbort(this.#discoverCDP(this.#signal()))\n\t\t\t\tif (discovery.endpoint !== undefined) {\n\t\t\t\t\tthis.#engine = browserToEngine(discovery.browser)\n\t\t\t\t\tawait this.#connectCDP(discovery.endpoint)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait this.#raceAbort(this.#assertPortFree())\n\t\t\t}\n\n\t\t\tthis.#assertNotAborted()\n\t\t\tawait this.#launch()\n\t\t} catch (error) {\n\t\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\n\t\t\tthis.#status = 'error'\n\t\t\tthis.#emitter.emit('error', error)\n\t\t\tif (isBrowserConnectionError(error)) throw error\n\n\t\t\tconst message = isError(error) ? error.message : String(error)\n\t\t\tthrow new BrowserConnectionError(message, { executable: this.#options.executable })\n\t\t}\n\t}\n\n\tasync #detach(): Promise<void> {\n\t\tthis.#status = 'disconnected'\n\t\tthis.#connection = undefined\n\t\tthis.#unbindTransport()\n\n\t\tconst client = this.#client\n\t\tthis.#client = undefined\n\t\tawait this.#destroyContexts()\n\t\tthis.#contexts = []\n\n\t\tif (this.#owned !== true) {\n\t\t\tthis.#owned = undefined\n\t\t\tthis.#endpoint = undefined\n\t\t}\n\n\t\tawait this.#closeClient(client)\n\t\tif (this.#destroyed) return\n\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t#assertNotAborted(): void {\n\t\tif (this.#signal().aborted) throw new BrowserConnectionError('Connection aborted')\n\t}\n\n\t#signal(): AbortSignal {\n\t\tconst external = this.#options.signal\n\t\treturn external === undefined\n\t\t\t? this.#abort.signal\n\t\t\t: AbortSignal.any([this.#abort.signal, external])\n\t}\n\n\tasync #raceAbort<T>(promise: Promise<T>): Promise<T> {\n\t\tconst signal = this.#signal()\n\t\tif (signal.aborted) throw new BrowserConnectionError('Connection aborted')\n\n\t\tconst aborted = Promise.withResolvers<never>()\n\t\tconst listener = addAbortListener(signal, () => {\n\t\t\taborted.reject(new BrowserConnectionError('Connection aborted'))\n\t\t})\n\n\t\ttry {\n\t\t\treturn await Promise.race([promise, aborted.promise])\n\t\t} finally {\n\t\t\tlistener[Symbol.dispose]()\n\t\t\tvoid promise.catch(() => undefined)\n\t\t}\n\t}\n\n\t#handleProcessExit(): void {\n\t\tif (this.#destroyed) return\n\n\t\tconst connected = this.#status === 'connected'\n\t\tconst client = this.#client\n\t\tconst contexts = this.#contexts\n\t\tconst process = this.#process\n\t\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\t\tthis.#process = undefined\n\t\tthis.#servingPid = undefined\n\t\tconst cleanup = this.#cleanupExitedProcess(process, contexts, client)\n\t\tthis.#exitCleanup = cleanup\n\t\tvoid cleanup.catch((error: unknown) => this.#emitter.emit('error', error))\n\t\tthis.#client = undefined\n\t\tthis.#contexts = []\n\t\tthis.#connection = undefined\n\t\tthis.#owned = undefined\n\t\tthis.#endpoint = undefined\n\t\tif (connected) this.#status = 'disconnected'\n\n\t\tthis.#emitter.emit(\n\t\t\t'error',\n\t\t\tnew BrowserConnectionError('The browser process exited unexpectedly', {\n\t\t\t\tcause: BROWSER_PROCESS_EXIT_CAUSE,\n\t\t\t}),\n\t\t)\n\n\t\tif (connected) {\n\t\t\tthis.#emitter.emit('disconnect')\n\t\t\tthis.#emitter.emit('idle')\n\t\t}\n\t}\n\n\t#handleTransportLoss(): void {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\tif (this.#process === undefined) {\n\t\t\tthis.#confirmTransportLoss()\n\t\t\treturn\n\t\t}\n\n\t\tif (!this.#alive()) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\t// A spawned child that is already dead is diagnosed by its own `exit`\n\t\t// event, never by a probe here: Node sets `exitCode` in the same callback\n\t\t// that emits `exit`, and reports ESRCH from `ChildProcess.kill(0)` as a\n\t\t// `false` return rather than a throw, so no reading of the handle can see\n\t\t// the death before the event does. The defer only has to outlast the loop\n\t\t// turn that delivers it.\n\t\tsetTimeout(() => this.#confirmTransportLoss(), BROWSER_TRANSPORT_LOSS_DEFER_MS)\n\t}\n\n\t#confirmTransportLoss(): void {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\tif (this.#process !== undefined && !this.#alive()) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tconst client = this.#client\n\t\tconst owned = this.#owned === true\n\t\tconst contexts = this.#contexts\n\t\tthis.#unbindTransport()\n\t\tthis.#client = undefined\n\t\tthis.#contexts = []\n\t\tthis.#connection = undefined\n\t\tthis.#status = 'disconnected'\n\n\t\tif (!owned) {\n\t\t\tthis.#owned = undefined\n\t\t\tthis.#endpoint = undefined\n\t\t}\n\n\t\tvoid this.#destroyContextList(contexts)\n\t\tvoid this.#closeClient(client)\n\t\tthis.#emitter.emit(\n\t\t\t'error',\n\t\t\tnew BrowserConnectionError('The CDP transport connection was lost', {\n\t\t\t\tcause: BROWSER_TRANSPORT_LOSS_CAUSE,\n\t\t\t}),\n\t\t)\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t#bindTransport(transport: CDPTransportInterface): void {\n\t\tthis.#unbindTransport()\n\t\tthis.#transport = transport\n\t\ttransport.emitter.on('close', this.#transportCloseHandler)\n\t\ttransport.emitter.on('error', this.#transportErrorHandler)\n\t}\n\n\t#unbindTransport(): void {\n\t\tconst transport = this.#transport\n\t\tif (transport === undefined) return\n\t\ttransport.emitter.off('close', this.#transportCloseHandler)\n\t\ttransport.emitter.off('error', this.#transportErrorHandler)\n\t\tthis.#transport = undefined\n\t}\n\n\t#bindProcess(process: ChildProcess): void {\n\t\tthis.#unbindProcess()\n\t\t// A launcher that handed the endpoint on has already exited, and its exit\n\t\t// says nothing about the browser now serving CDP. That browser has no\n\t\t// child handle, so the transport reports its death.\n\t\tif (this.#servingPid !== undefined) return\n\t\tprocess.once('exit', this.#processExitHandler)\n\t\tif (process.exitCode !== null || process.signalCode !== null) {\n\t\t\tqueueMicrotask(this.#processExitHandler)\n\t\t}\n\t}\n\n\t#unbindProcess(): void {\n\t\tthis.#process?.off('exit', this.#processExitHandler)\n\t}\n\n\t#timeout(): number {\n\t\treturn this.#options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS\n\t}\n\n\tasync #discoverCDP(signal?: AbortSignal): Promise<BrowserDiscoveryResult> {\n\t\tconst url = `${BROWSER_CDP_PROTOCOL}://${this.#cdpHost}:${this.#cdpPort}${BROWSER_CDP_VERSION_PATH}`\n\t\tconst requestSignal =\n\t\t\tsignal === undefined\n\t\t\t\t? AbortSignal.timeout(this.#timeout())\n\t\t\t\t: AbortSignal.any([signal, AbortSignal.timeout(this.#timeout())])\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: requestSignal })\n\t\t\tif (!response.ok) return this.#notFound()\n\n\t\t\tconst info: unknown = await response.json()\n\t\t\tif (!isRecord(info)) return this.#notFound()\n\n\t\t\tconst endpoint = isString(info['webSocketDebuggerUrl'])\n\t\t\t\t? info['webSocketDebuggerUrl']\n\t\t\t\t: undefined\n\t\t\tconst browser = isString(info['Browser']) ? info['Browser'] : undefined\n\n\t\t\treturn { endpoint, browser }\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted === true) throw error\n\t\t\treturn this.#notFound()\n\t\t}\n\t}\n\n\t#notFound(): BrowserDiscoveryResult {\n\t\treturn { endpoint: undefined, browser: undefined }\n\t}\n\n\tasync #assertPortFree(): Promise<void> {\n\t\tif (await this.#probePort()) {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t`Port ${this.#cdpPort} on ${this.#cdpHost} is already occupied by another CDP endpoint`,\n\t\t\t\t{ port: this.#cdpPort, host: this.#cdpHost },\n\t\t\t)\n\t\t}\n\t}\n\n\tasync #probePort(): Promise<boolean> {\n\t\tconst url = `${BROWSER_CDP_PROTOCOL}://${this.#cdpHost}:${this.#cdpPort}${BROWSER_CDP_VERSION_PATH}`\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tsignal: AbortSignal.timeout(BROWSER_PORT_PROBE_TIMEOUT_MS),\n\t\t\t})\n\t\t\treturn response.ok\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tasync #connectCDP(endpoint: string): Promise<void> {\n\t\tconst transport = createCDPTransport({ url: endpoint, timeout: this.#timeout() })\n\t\tconst client = new CDPClient({ transport, timeout: this.#timeout() })\n\t\tconst retained = this.#owned === true && this.#endpoint === endpoint\n\n\t\ttry {\n\t\t\tawait this.#raceAbort(client.connect())\n\n\t\t\tthis.#client = client\n\t\t\tthis.#endpoint = endpoint\n\t\t\tthis.#connection = retained ? this.#retainedConnection() : 'cdp'\n\t\t\tthis.#owned = retained\n\t\t\tthis.#status = 'connected'\n\t\t\tthis.#bindTransport(transport)\n\n\t\t\tawait this.#syncContexts()\n\t\t\tthis.#emitter.emit('connect', this.#connection)\n\t\t} catch (error) {\n\t\t\tthis.#unbindTransport()\n\t\t\tif (this.#client === client) this.#client = undefined\n\t\t\tthis.#contexts = []\n\t\t\tthis.#connection = undefined\n\t\t\tif (!retained) {\n\t\t\t\tthis.#owned = undefined\n\t\t\t\tthis.#endpoint = undefined\n\t\t\t}\n\t\t\tawait this.#closeClient(client)\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tasync #launch(): Promise<void> {\n\t\tif (this.#process !== undefined) {\n\t\t\tthrow new BrowserConnectionError('A browser process is already active on this instance')\n\t\t}\n\n\t\tconst requestedEngine = this.#options.engine ?? this.#options.browsers?.engine\n\t\tlet executable = this.#options.executable\n\t\tlet resolvedEngine: BrowserEngine | undefined\n\n\t\tif (executable !== undefined) {\n\t\t\tresolvedEngine = parseBrowserEngine(executable) ?? 'chromium'\n\t\t} else {\n\t\t\tconst found = findSystemBrowser({\n\t\t\t\t...this.#options.browsers,\n\t\t\t\t...(requestedEngine !== undefined ? { engine: requestedEngine } : {}),\n\t\t\t})\n\t\t\texecutable = found?.executable\n\t\t\tresolvedEngine = found?.engine\n\t\t}\n\n\t\tif (executable === undefined) {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t'No Chromium browser found. Install Chrome, Edge, or Chromium.',\n\t\t\t\trequestedEngine === undefined ? undefined : { engine: requestedEngine },\n\t\t\t)\n\t\t}\n\n\t\tthis.#engine = resolvedEngine ?? 'chromium'\n\t\tawait this.#releaseProfile()\n\t\tconst profile = await createBrowserProfile(this.#options.profile)\n\t\tthis.#profile = profile\n\t\tlet process: ChildProcess\n\t\ttry {\n\t\t\tprocess = launchBrowserProcess(\n\t\t\t\texecutable,\n\t\t\t\tthis.#options.cdp?.port,\n\t\t\t\tthis.#options.headless ?? true,\n\t\t\t\tprofile.path,\n\t\t\t\tthis.#options.args,\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tawait this.#releaseProfile()\n\t\t\tthrow error\n\t\t}\n\t\tthis.#process = process\n\n\t\tlet client: CDPClient | undefined\n\n\t\ttry {\n\t\t\tconst endpoint = await this.#waitForLaunch(process, executable, this.#options.args)\n\t\t\tconst transport = createCDPTransport({ url: endpoint, timeout: this.#timeout() })\n\t\t\tclient = new CDPClient({ transport, timeout: this.#timeout() })\n\t\t\tawait this.#raceAbort(client.connect())\n\t\t\tawait this.#takeEndpointOwner(process, client)\n\n\t\t\tconst connection = this.#options.profile === undefined ? 'launch' : 'persistent'\n\t\t\tthis.#client = client\n\t\t\tthis.#endpoint = endpoint\n\t\t\tthis.#connection = connection\n\t\t\tthis.#owned = true\n\t\t\tthis.#status = 'connected'\n\t\t\tthis.#bindTransport(transport)\n\t\t\tthis.#bindProcess(process)\n\n\t\t\tawait this.#syncContexts()\n\t\t\tthis.#emitter.emit('launch', this.#engine)\n\t\t\tthis.#emitter.emit('connect', connection)\n\t\t} catch (error) {\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\t\t\tawait this.#closeClient(client)\n\t\t\tawait this.#terminate(process)\n\t\t\tawait this.#releaseProfile()\n\t\t\tthis.#process = undefined\n\t\t\tthis.#servingPid = undefined\n\t\t\tthis.#client = undefined\n\t\t\tthis.#endpoint = undefined\n\t\t\tthis.#owned = undefined\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Takes over the process serving the CDP endpoint when the spawned child is\n\t * no longer it.\n\t *\n\t * @remarks\n\t * A Windows launcher — Microsoft Edge — re-executes the browser with the\n\t * same `--remote-debugging-port` and exits 0 before the endpoint answers, so\n\t * the child this instance spawned parents the real tree without being part\n\t * of it. Chromium names the process behind the endpoint as the `browser`\n\t * entry of `SystemInfo.getProcessInfo`, which identifies it without a\n\t * platform branch. An endpoint that names no such process cannot be owned,\n\t * so the launch closes it and fails rather than leaking it.\n\t */\n\tasync #takeEndpointOwner(process: ChildProcess, client: CDPClient): Promise<void> {\n\t\tif (process.exitCode === null && process.signalCode === null) return\n\n\t\tlet result: unknown\n\t\ttry {\n\t\t\tresult = await client.send('SystemInfo.getProcessInfo')\n\t\t} catch {\n\t\t\tresult = undefined\n\t\t}\n\n\t\tlet pid: number | undefined\n\t\tif (isRecord(result) && isArray(result['processInfo'])) {\n\t\t\tfor (const entry of result['processInfo']) {\n\t\t\t\tif (!isRecord(entry) || entry['type'] !== 'browser' || !isInteger(entry['id'])) continue\n\t\t\t\tpid = entry['id']\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (pid === undefined) {\n\t\t\tawait this.#closeRemote(client)\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t'The browser launcher exited without naming the process serving its CDP endpoint',\n\t\t\t\t{ executable: this.#options.executable, pid: process.pid },\n\t\t\t)\n\t\t}\n\n\t\tthis.#servingPid = pid\n\t}\n\n\tasync #waitForLaunch(\n\t\tprocess: ChildProcess,\n\t\texecutable: string,\n\t\targs?: readonly string[],\n\t): Promise<string> {\n\t\tconst context = { executable, args }\n\t\tconst timeout = this.#timeout()\n\t\tconst controller = new AbortController()\n\t\tconst deadline = AbortSignal.timeout(timeout)\n\t\tconst signal = AbortSignal.any([controller.signal, this.#signal(), deadline])\n\t\tconst stderr = process.stderr\n\t\tif (stderr === null) {\n\t\t\tthrow new BrowserConnectionError('The browser process has no standard error to read', context)\n\t\t}\n\t\tconst exit = once(process, 'exit', { signal })\n\t\tvoid exit.catch(() => undefined)\n\t\tconst ready = readBrowserEndpoint(stderr, signal).catch(async (error: unknown) => {\n\t\t\t// A stream that closes without the line ends the launch, and the exit\n\t\t\t// that closed it names the cause: a nonzero exit is the launch-exit\n\t\t\t// fault, while a clean exit leaves the readiness failure standing.\n\t\t\tif (signal.aborted) throw error\n\t\t\tconst values = await exit\n\t\t\tif (values[0] === 0 && values[1] === null) throw error\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\tthis.#formatLaunchExit(\n\t\t\t\t\tisInteger(values[0]) ? values[0] : null,\n\t\t\t\t\tisString(values[1]) ? values[1] : null,\n\t\t\t\t),\n\t\t\t\tcontext,\n\t\t\t)\n\t\t})\n\t\tconst exited = exit.then((values) => {\n\t\t\tconst code = isInteger(values[0]) ? values[0] : null\n\t\t\tconst exitSignal = isString(values[1]) ? values[1] : null\n\t\t\t// A launcher that re-executes the browser exits cleanly and hands the\n\t\t\t// inherited standard error to the process it spawned, so a clean exit\n\t\t\t// ends the child rather than the launch. Keep reading the same pipe on\n\t\t\t// the same readiness budget, which still fails when the line never\n\t\t\t// arrives.\n\t\t\tif (code === 0 && exitSignal === null) return ready\n\t\t\tthrow new BrowserConnectionError(this.#formatLaunchExit(code, exitSignal), context)\n\t\t})\n\n\t\ttry {\n\t\t\treturn await Promise.race([ready, exited])\n\t\t} catch (error) {\n\t\t\tif (isBrowserConnectionError(error)) throw error\n\t\t\tif (this.#signal().aborted) throw new BrowserConnectionError('Connection aborted', context)\n\t\t\tif (deadline.aborted) {\n\t\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t\t`Browser did not report a CDP endpoint within ${timeout}ms`,\n\t\t\t\t\t{ ...context, timeout },\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst message = isError(error) ? error.message : String(error)\n\t\t\tthrow new BrowserConnectionError(message, context)\n\t\t} finally {\n\t\t\tcontroller.abort()\n\t\t\tvoid ready.catch(() => undefined)\n\t\t\tvoid exited.catch(() => undefined)\n\t\t}\n\t}\n\n\t#formatLaunchExit(code: number | null, signal: string | null): string {\n\t\tif (signal !== null) {\n\t\t\treturn `Browser process exited before CDP became ready (signal: ${signal})`\n\t\t}\n\t\tif (code !== null) return `Browser process exited before CDP became ready (code: ${code})`\n\t\treturn 'Browser process exited before CDP became ready'\n\t}\n\n\t#retainedConnection(): BrowserConnection {\n\t\tif (this.#process === undefined) return 'cdp'\n\t\treturn this.#options.profile === undefined ? 'launch' : 'persistent'\n\t}\n\n\tasync #syncContexts(): Promise<void> {\n\t\tconst client = this.#client\n\t\tif (client === undefined) return\n\n\t\tlet result: unknown\n\t\ttry {\n\t\t\tresult = await client.send('Target.getTargets')\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t\tif (!isRecord(result) || !isArray(result['targetInfos'])) return\n\n\t\tconst pages: CDPTarget[] = []\n\t\tfor (const target of result['targetInfos']) {\n\t\t\tif (\n\t\t\t\t!isRecord(target) ||\n\t\t\t\t!isString(target['targetId']) ||\n\t\t\t\ttarget['type'] !== 'page' ||\n\t\t\t\t!isString(target['title']) ||\n\t\t\t\t!isString(target['url'])\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpages.push({\n\t\t\t\tid: target['targetId'],\n\t\t\t\tcategory: target['type'],\n\t\t\t\ttitle: target['title'],\n\t\t\t\turl: target['url'],\n\t\t\t})\n\t\t}\n\t\tif (pages.length === 0 || this.#contexts.length > 0) return\n\n\t\tconst context = new BrowserContext(\n\t\t\tclient,\n\t\t\tundefined,\n\t\t\tthis.#options.viewport,\n\t\t\tcreateBrowserWriter(),\n\t\t)\n\t\tawait context.sync(pages)\n\t\tthis.#registerContext(context)\n\t}\n\n\tasync #destroyResources(): Promise<void> {\n\t\tlet terminated = false\n\t\ttry {\n\t\t\tawait this.#settle()\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\n\t\t\tconst client = this.#client\n\t\t\tif (this.#owned === true) {\n\t\t\t\tawait this.#closeContexts()\n\t\t\t\tif (this.#process === undefined) await this.#closeRemote(client)\n\t\t\t} else {\n\t\t\t\tawait this.#destroyContexts()\n\t\t\t}\n\t\t\tthis.#contexts = []\n\n\t\t\tawait this.#terminate(this.#process)\n\t\t\tthis.#process = undefined\n\t\t\tthis.#servingPid = undefined\n\t\t\tterminated = true\n\t\t} finally {\n\t\t\tconst contexts = this.#contexts\n\t\t\tthis.#contexts = []\n\t\t\tconst client = this.#client\n\t\t\tthis.#client = undefined\n\t\t\ttry {\n\t\t\t\tawait this.#cleanupLocal(contexts, client)\n\t\t\t\tif (terminated) await this.#releaseProfile()\n\t\t\t} finally {\n\t\t\t\tthis.#finish()\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #closeResources(): Promise<void> {\n\t\tlet terminated = false\n\t\ttry {\n\t\t\tawait this.#settle()\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\n\t\t\tconst client = this.#client\n\t\t\tawait this.#closeContexts()\n\t\t\tthis.#contexts = []\n\t\t\tawait this.#closeRemote(client)\n\n\t\t\tconst process = this.#process\n\t\t\tif (process !== undefined) {\n\t\t\t\tconst exited = await this.#waitForTerminationWithin(process, BROWSER_KILL_GRACE_MS)\n\t\t\t\tif (!exited) await this.#terminate(process)\n\t\t\t}\n\t\t\tthis.#process = undefined\n\t\t\tthis.#servingPid = undefined\n\t\t\tterminated = true\n\t\t} finally {\n\t\t\tconst contexts = this.#contexts\n\t\t\tthis.#contexts = []\n\t\t\tconst client = this.#client\n\t\t\tthis.#client = undefined\n\t\t\ttry {\n\t\t\t\tawait this.#cleanupLocal(contexts, client)\n\t\t\t\tif (terminated) await this.#releaseProfile()\n\t\t\t} finally {\n\t\t\t\tthis.#finish()\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #settle(): Promise<void> {\n\t\tawait this.#connecting.pending?.catch(() => undefined)\n\t\tawait this.#disconnecting.pending?.catch(() => undefined)\n\t\tawait this.#settleExit()\n\t}\n\n\tasync #settleExit(): Promise<void> {\n\t\tconst cleanup = this.#exitCleanup\n\t\tif (cleanup === undefined) return\n\t\tawait cleanup\n\t\tif (this.#exitCleanup === cleanup) this.#exitCleanup = undefined\n\t}\n\n\tasync #closeRemote(client: CDPClient | undefined): Promise<void> {\n\t\tlet remote = client\n\t\tlet temporary = false\n\n\t\tif (remote === undefined && this.#owned === true && this.#endpoint !== undefined) {\n\t\t\tconst transport = createCDPTransport({\n\t\t\t\turl: this.#endpoint,\n\t\t\t\ttimeout: this.#timeout(),\n\t\t\t})\n\t\t\tremote = new CDPClient({ transport, timeout: this.#timeout() })\n\t\t\ttry {\n\t\t\t\tawait remote.connect()\n\t\t\t\ttemporary = true\n\t\t\t} catch {\n\t\t\t\tawait this.#closeClient(remote)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif (remote !== undefined) {\n\t\t\ttry {\n\t\t\t\tawait remote.send('Browser.close')\n\t\t\t} catch {\n\t\t\t\t// The remote may already be gone or close before acknowledging.\n\t\t\t}\n\t\t}\n\n\t\tif (temporary) await this.#closeClient(remote)\n\t}\n\n\tasync #closeContexts(): Promise<void> {\n\t\tfor (const context of [...this.#contexts]) {\n\t\t\ttry {\n\t\t\t\tawait context.close()\n\t\t\t} catch {\n\t\t\t\t// Teardown is best-effort after the browser begins shutting down.\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #destroyContexts(): Promise<void> {\n\t\tawait this.#destroyContextList([...this.#contexts])\n\t}\n\n\t#registerContext(context: BrowserContext): void {\n\t\tthis.#contexts.push(context)\n\t\tcontext.emitter.on('close', () => {\n\t\t\tconst index = this.#contexts.indexOf(context)\n\t\t\tif (index >= 0) this.#contexts.splice(index, 1)\n\t\t})\n\t\tthis.#emitter.emit('context', context)\n\t}\n\n\tasync #destroyContextList(contexts: readonly BrowserContext[]): Promise<void> {\n\t\tfor (const context of contexts) {\n\t\t\ttry {\n\t\t\t\tawait context.destroy()\n\t\t\t} catch {\n\t\t\t\t// The transport may already be unavailable.\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #closeClient(client: CDPClient | undefined): Promise<void> {\n\t\tif (client === undefined) return\n\t\ttry {\n\t\t\tawait client.close()\n\t\t} catch {\n\t\t\t// Teardown is best-effort after a connection fault.\n\t\t}\n\t}\n\n\tasync #releaseProfile(): Promise<void> {\n\t\tconst profile = this.#profile\n\t\tthis.#profile = undefined\n\t\tif (profile !== undefined) await removeBrowserProfile(profile)\n\t}\n\n\tasync #cleanupExitedProcess(\n\t\tprocess: ChildProcess | undefined,\n\t\tcontexts: readonly BrowserContext[],\n\t\tclient: CDPClient | undefined,\n\t): Promise<void> {\n\t\tlet terminated = false\n\t\ttry {\n\t\t\tawait this.#terminate(process)\n\t\t\tterminated = true\n\t\t} finally {\n\t\t\tawait this.#cleanupLocal(contexts, client)\n\t\t}\n\t\tif (terminated) await this.#releaseProfile()\n\t}\n\n\tasync #cleanupLocal(\n\t\tcontexts: readonly BrowserContext[],\n\t\tclient: CDPClient | undefined,\n\t): Promise<void> {\n\t\tawait this.#destroyContextList(contexts)\n\t\tawait this.#closeClient(client)\n\t}\n\n\tasync #waitForProcessWithin(process: ChildProcess, timeout: number): Promise<boolean> {\n\t\tif (process.exitCode !== null || process.signalCode !== null) return true\n\n\t\tconst signal = AbortSignal.timeout(timeout)\n\t\ttry {\n\t\t\tawait once(process, 'exit', { signal })\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tif (signal.aborted) {\n\t\t\t\treturn process.exitCode !== null || process.signalCode !== null\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t#hasProcessGroup(process: ChildProcess): boolean {\n\t\tconst pid = process.pid\n\t\treturn globalThis.process.platform !== 'win32' && pid !== undefined && pid > 0\n\t}\n\n\t// Whether the process serving the CDP endpoint is still running. The spawned\n\t// child reports through its own handle; a process the launcher handed the\n\t// endpoint to has none, so it is probed by identifier.\n\t#alive(): boolean {\n\t\tconst process = this.#process\n\t\tif (process === undefined) return false\n\t\tif (this.#servingPid !== undefined) return this.#signalProcess(process, 0) !== false\n\t\treturn process.exitCode === null && process.signalCode === null\n\t}\n\n\t// Whether the launch retains a process the reaped child does not account\n\t// for: the POSIX process group, or the process the launcher handed the\n\t// endpoint to.\n\t#inspectRemainder(process: ChildProcess): boolean | undefined {\n\t\tif (!this.#hasProcessGroup(process) && this.#servingPid === undefined) return false\n\t\treturn this.#signalProcess(process, 0)\n\t}\n\n\t#signalProcess(process: ChildProcess, signal: NodeJS.Signals | 0): boolean | undefined {\n\t\tconst pid = process.pid\n\t\tconst serving = this.#servingPid\n\t\ttry {\n\t\t\tif (this.#hasProcessGroup(process) && pid !== undefined) {\n\t\t\t\treturn globalThis.process.kill(-pid, signal)\n\t\t\t}\n\t\t\t// Terminating the Chromium browser process takes its whole tree with\n\t\t\t// it, so Windows needs no separate tree walk to reach the renderers,\n\t\t\t// GPU, and utility children the serving process parents.\n\t\t\tif (serving !== undefined) return globalThis.process.kill(serving, signal)\n\t\t\treturn process.kill(signal)\n\t\t} catch (error) {\n\t\t\tconst code =\n\t\t\t\tisError(error) && 'code' in error && isString(error.code) ? error.code : undefined\n\t\t\tif (code === 'ESRCH') return false\n\t\t\tif (signal === 0) return code === 'EPERM' ? true : undefined\n\t\t\tthrow new BrowserConnectionError('Failed to signal the browser process', {\n\t\t\t\tpid: serving ?? pid,\n\t\t\t\tsignal,\n\t\t\t\tcause: error,\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Waits within a bound for the rest of a terminated process group, or the process a\n\t * launcher handed the endpoint to, to disappear.\n\t *\n\t * @remarks\n\t * This is the one interval loop in the server. Node raises an exit event for the direct\n\t * child only, so no event source reports the remainder of a POSIX process group or a\n\t * handed-off process, and the drain probes on `BROWSER_DRAIN_INTERVAL_MS` until the\n\t * remainder is gone or `timeout` elapses.\n\t */\n\tasync #waitForRemainderWithin(\n\t\tprocess: ChildProcess,\n\t\ttimeout: number,\n\t): Promise<boolean | undefined> {\n\t\tconst deadline = performance.now() + timeout\n\t\tlet confirmed = false\n\t\twhile (true) {\n\t\t\tconst alive = this.#inspectRemainder(process)\n\t\t\tif (alive === false) return true\n\t\t\tif (alive === true) confirmed = true\n\t\t\tconst remaining = deadline - performance.now()\n\t\t\tif (remaining <= 0) return confirmed ? false : undefined\n\t\t\tawait new Promise<void>((resolve) =>\n\t\t\t\tsetTimeout(resolve, Math.min(BROWSER_DRAIN_INTERVAL_MS, remaining)),\n\t\t\t)\n\t\t}\n\t}\n\n\tasync #waitForTerminationWithin(\n\t\tprocess: ChildProcess,\n\t\ttimeout: number,\n\t\tfinal = false,\n\t): Promise<boolean> {\n\t\tconst exited = this.#waitForProcessWithin(process, timeout)\n\t\tconst drained = this.#waitForRemainderWithin(process, timeout)\n\t\tconst results = await Promise.all([exited, drained])\n\t\treturn results[0] && (results[1] === true || (final && results[1] === undefined))\n\t}\n\n\tasync #terminate(process: ChildProcess | undefined): Promise<void> {\n\t\tif (\n\t\t\tprocess === undefined ||\n\t\t\t((process.exitCode !== null || process.signalCode !== null) &&\n\t\t\t\tthis.#inspectRemainder(process) === false)\n\t\t) {\n\t\t\treturn\n\t\t}\n\n\t\tif (this.#signalProcess(process, 'SIGTERM') === false) return\n\t\tif (await this.#waitForTerminationWithin(process, BROWSER_KILL_GRACE_MS)) return\n\n\t\tif (this.#signalProcess(process, 'SIGKILL') === false) return\n\t\tif (await this.#waitForTerminationWithin(process, BROWSER_KILL_GRACE_MS, true)) return\n\n\t\tthrow new BrowserConnectionError('Browser process did not exit after SIGKILL', {\n\t\t\tpid: this.#servingPid ?? process.pid,\n\t\t})\n\t}\n\n\t#finish(): void {\n\t\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\t\tthis.#status = 'disconnected'\n\t\tthis.#connection = undefined\n\t\tthis.#owned = undefined\n\t\tthis.#endpoint = undefined\n\t\tthis.#client = undefined\n\t\tthis.#process = undefined\n\t\tthis.#servingPid = undefined\n\t\tthis.#exitCleanup = undefined\n\t\tthis.#contexts = []\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#emitter.destroy()\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["BrowserError","isInstance","pathWin32","pathPosix","mkdtemp","join","tmpdir","resolve","dirname","basename","BrowserError","rm","existsSync","spawnSync","globSync","spawn","isString","BrowserConnectionError","isArray","isRecord","BrowserTransition","Emitter","BROWSER_DEFAULT_TIMEOUT_MS","WEBSOCKET_READY_OPEN","BrowserConnectionError","attempt","randomBytes","WEBSOCKET_VERSION","httpsRequest","httpRequest","WEBSOCKET_READY_CLOSED","isString","computeWebSocketAccept","createNodeWebSocket","mkdir","dirname","writeFile","resolve","createToolManager","BROWSER_TOOL_NAMES","BROWSER_JOURNEY_TOOL_NAMES","createTool","BROWSER_TOOL_COPY","createMCPServer","createStdioServer","createMCPLegacy","rm","BrowserError","mkdir","join","randomUUID","createBrowserToolset","toolToDefinition","BrowserError","realpathSync","BROWSER_JOURNEY_NAME_PATTERN","BROWSER_RUN_ID_PATTERN","resolve","sep","relative","lstat","dirname","mkdir","readFile","randomUUID","open","rename","unlink","readdir","rmdir","parseJSON","isRecord","BrowserError","normalizeBrowserJourneyReason","BROWSER_JOURNEY_NAME_PATTERN","generateBrowserRunId","parseJSON","isRecord","BrowserError","BROWSER_JOURNEY_FORMAT_VERSION","rm","readdir","lstat","BrowserTransition","Emitter","isRecord","isString","BrowserConnectionError","BrowserContext","isBrowserConnectionError","isError","addAbortListener","BROWSER_DEFAULT_TIMEOUT_MS","CDPClient","isArray","isInteger","once"],"sources":["../../../src/server/constants.ts","../../../src/server/errors.ts","../../../src/server/helpers.ts","../../../src/server/transports/WebSocketCDPTransport.ts","../../../src/server/writers/FileBrowserWriter.ts","../../../package.json","../../../src/server/BrowserMCPServer.ts","../../../src/server/stores/FileBrowserStore.ts","../../../src/server/stores/FileBrowserJourneyStore.ts","../../../src/server/stores/FileBrowserRunStore.ts","../../../src/server/factories.ts","../../../src/server/Browser.ts"],"sourcesContent":["import type { BrowserEngine } from './types.js'\n\n// === CDP discovery\n\n/**\n * Sets the default CDP port probed for an existing browser and used for launches, `9222`.\n */\nexport const BROWSER_DEFAULT_CDP_PORT = 9222\n\n/**\n * Sets the default host probed for an existing browser and used for launches, `'127.0.0.1'`,\n * which avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`.\n */\nexport const BROWSER_DEFAULT_HOST = '127.0.0.1'\n\n/** Names the protocol prefix for CDP discovery requests, `'http'`. */\nexport const BROWSER_CDP_PROTOCOL = 'http'\n\n/**\n * Names the path appended to the CDP host to fetch version metadata, `'/json/version'`, which\n * is where endpoint discovery reads.\n */\nexport const BROWSER_CDP_VERSION_PATH = '/json/version'\n\n/**\n * Names the path appended to the CDP host to list open targets — pages, workers, and every\n * other target category Chromium reports — `'/json/list'`.\n */\nexport const BROWSER_CDP_LIST_PATH = '/json/list'\n\n// === Browser launch\n\n/** Lists the flags always passed to a launched browser process, alongside the caller's own. */\nexport const BROWSER_LAUNCH_ARGS: readonly string[] = Object.freeze([\n\t'--no-first-run',\n\t'--no-default-browser-check',\n])\n\n/**\n * Names the flag that enables headless mode on a launched browser process, `'--headless=new'`.\n */\nexport const BROWSER_HEADLESS_ARG = '--headless=new'\n\n/**\n * Names the prefix for isolated browser profiles created beneath the operating-system temp\n * directory, `'orkestrel-browser-'`.\n */\nexport const BROWSER_PROFILE_PREFIX = 'orkestrel-browser-'\n\n/**\n * Bounds each launched-process exit window during TERM-to-KILL teardown at `3_000`\n * milliseconds.\n */\nexport const BROWSER_KILL_GRACE_MS = 3_000\n\n/**\n * Bounds the `discover: false` port-occupancy probe before launching at `200` milliseconds,\n * which is short because the probe only needs to detect an already-listening CDP endpoint\n * rather than perform full discovery.\n */\nexport const BROWSER_PORT_PROBE_TIMEOUT_MS = 200\n\n/**\n * Matches the stderr line Chromium prints when its CDP endpoint accepts connections, and\n * captures the `ws://` endpoint the line names.\n *\n * @remarks\n * Chromium prints the line only when launched with `--remote-debugging-port`, which is why an\n * owned launch always passes that flag.\n */\nexport const BROWSER_DEVTOOLS_PATTERN = /DevTools listening on (ws:\\/\\/\\S+)/\n\n/**\n * Sets the interval in milliseconds between liveness probes of a terminated browser process\n * group.\n *\n * @remarks\n * Node raises an exit event for the direct child only. Neither the rest of a POSIX process\n * group nor a process a launcher handed the endpoint to raises one, so the bounded drain in\n * `Browser` probes on this interval until the group is gone or the grace period ends.\n */\nexport const BROWSER_DRAIN_INTERVAL_MS = 100\n\n/**\n * Defers once for `50` milliseconds when a transport loss is observed on an owned process,\n * so a near-simultaneous process-exit event, which libuv might reap slightly later than the\n * socket close, decides the diagnosis first.\n */\nexport const BROWSER_TRANSPORT_LOSS_DEFER_MS = 50\n\n/**\n * Names the machine-readable error-context cause for an owned browser process exiting,\n * `'process-exit'`.\n */\nexport const BROWSER_PROCESS_EXIT_CAUSE = 'process-exit'\n\n/**\n * Names the machine-readable error-context cause for a CDP transport disconnecting while its\n * browser remains alive, `'transport-loss'`.\n */\nexport const BROWSER_TRANSPORT_LOSS_CAUSE = 'transport-loss'\n\n/**\n * Lists the environment variables checked, in order, for an explicit browser executable path\n * override: `PLAYWRIGHT_EXECUTABLE_PATH`, then `CHROME_PATH`.\n */\nexport const BROWSER_ENV_PATH_KEYS: readonly string[] = Object.freeze([\n\t'PLAYWRIGHT_EXECUTABLE_PATH',\n\t'CHROME_PATH',\n])\n\n/**\n * Lists the well-known Chrome/Chromium/Edge executable paths with no platform-specific root,\n * keyed by `process.platform`, leaving `win32` empty because its roots come from\n * `BROWSER_WINDOWS_SUFFIXES`.\n */\nexport const BROWSER_EXECUTABLE_PATHS: Readonly<Record<string, readonly string[]>> = Object.freeze({\n\tlinux: Object.freeze([\n\t\t'/usr/bin/google-chrome',\n\t\t'/usr/bin/google-chrome-stable',\n\t\t'/usr/bin/microsoft-edge',\n\t\t'/usr/bin/microsoft-edge-stable',\n\t\t'/usr/bin/chromium',\n\t\t'/usr/bin/chromium-browser',\n\t\t'/snap/bin/chromium',\n\t\t'/opt/google/chrome/chrome',\n\t\t'/opt/microsoft/msedge/msedge',\n\t]),\n\tdarwin: Object.freeze([\n\t\t'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',\n\t\t'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',\n\t\t'/Applications/Chromium.app/Contents/MacOS/Chromium',\n\t]),\n\twin32: Object.freeze([]),\n})\n\n/** Lists the Windows install-root-relative suffixes for Chrome/Edge/Chromium, joined against each candidate root (`PROGRAMFILES`, `PROGRAMFILES(X86)`, `LOCALAPPDATA`). */\nexport const BROWSER_WINDOWS_SUFFIXES: readonly string[] = Object.freeze([\n\t'Google\\\\Chrome\\\\Application\\\\chrome.exe',\n\t'Microsoft\\\\Edge\\\\Application\\\\msedge.exe',\n\t'Chromium\\\\Application\\\\chrome.exe',\n])\n\n/**\n * Lists the fallback Windows install roots used when `PROGRAMFILES`, `PROGRAMFILES(X86)`, or\n * `LOCALAPPDATA` is absent.\n */\nexport const BROWSER_WINDOWS_ROOT_FALLBACKS: Readonly<Record<string, string>> = Object.freeze({\n\tPROGRAMFILES: 'C:\\\\Program Files',\n\t'PROGRAMFILES(X86)': 'C:\\\\Program Files (x86)',\n})\n\n/** Lists the command names probed on PATH when no well-known executable path exists. */\nexport const BROWSER_EXECUTABLE_NAMES: readonly string[] = Object.freeze([\n\t'google-chrome',\n\t'google-chrome-stable',\n\t'msedge',\n\t'microsoft-edge',\n\t'chromium',\n\t'chromium-browser',\n\t'chrome',\n])\n\n/**\n * Names the environment variable that carries an additional Playwright browser store base\n * directory, `'PLAYWRIGHT_BROWSERS_PATH'`.\n */\nexport const BROWSER_STORE_ENV_KEY = 'PLAYWRIGHT_BROWSERS_PATH'\n\n/**\n * Lists the well-known Playwright browser store base directories checked in addition to\n * `PLAYWRIGHT_BROWSERS_PATH`, starting with `/opt/pw-browsers`.\n */\nexport const BROWSER_STORE_DEFAULT_DIRS: readonly string[] = Object.freeze(['/opt/pw-browsers'])\n\n/** Names the per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */\nexport const BROWSER_STORE_CACHE_DIRS: Readonly<Record<string, string>> = Object.freeze({\n\tlinux: '.cache/ms-playwright',\n\tdarwin: 'Library/Caches/ms-playwright',\n})\n\n/**\n * Names the top-level Chromium symlink or binary Playwright maintains inside a browser store\n * base, `'chromium'`.\n */\nexport const BROWSER_STORE_LINK_NAME = 'chromium'\n\n/**\n * Lists the case-insensitive substrings identifying an executable path/name's browser\n * engine, checked by `parseBrowserEngine` in the order `edge` → `chromium` → `chrome`.\n */\nexport const BROWSER_ENGINE_HINTS: Readonly<Record<BrowserEngine, readonly string[]>> =\n\tObject.freeze({\n\t\tedge: Object.freeze(['msedge', 'microsoft-edge', 'edge']),\n\t\tchromium: Object.freeze([\n\t\t\t'chromium',\n\t\t\t'pw-browsers',\n\t\t\t'chrome-linux',\n\t\t\t'chrome-win',\n\t\t\t'chrome-mac',\n\t\t\t'chrome_headless',\n\t\t]),\n\t\tchrome: Object.freeze(['google-chrome', 'google/chrome', 'google\\\\chrome', 'chrome']),\n\t})\n\n/** Names the glob pattern (relative to a store base) matching a versioned Chromium binary, keyed by `process.platform`. */\nexport const BROWSER_STORE_GLOBS: Readonly<Record<string, string>> = Object.freeze({\n\tlinux: 'chromium-*/chrome-linux*/chrome',\n\tdarwin: 'chromium-*/chrome-mac*/Chromium.app/Contents/MacOS/Chromium',\n\twin32: 'chromium-*/chrome-win*/chrome.exe',\n})\n\n/** Names the persisted journey snapshot. */\nexport const BROWSER_JOURNEY_SNAPSHOT_FILE = 'journey.json'\n/** Names the retained journey revision counter. */\nexport const BROWSER_JOURNEY_REVISION_FILE = 'revision'\n/** Names the exclusive journey write lock directory. */\nexport const BROWSER_JOURNEY_LOCK_DIRECTORY = 'journey.lock'\n/** Bounds attempts to acquire a journey lock after concurrent recovery. */\nexport const BROWSER_JOURNEY_LOCK_ATTEMPTS = 8\n/** Names the persisted run snapshot. */\nexport const BROWSER_RUN_FILE = 'run.json'\n/** Names the journey directory holding its runs. */\nexport const BROWSER_RUN_DIRECTORY = 'runs'\n/** Bounds a file-store listing page by default. */\nexport const BROWSER_FILE_STORE_LIMIT = 100\n","import { BrowserError } from '@src/core'\nimport { isInstance } from '@orkestrel/contract'\n\n// === Server browser errors\n\n/**\n * Reports that an operation requiring an active connection was attempted while disconnected,\n * under the code `BROWSER_NOT_CONNECTED_ERROR`.\n */\nexport class BrowserNotConnectedError extends BrowserError {\n\tconstructor(context?: Readonly<Record<string, unknown>>) {\n\t\tsuper('Browser is not connected', 'BROWSER_NOT_CONNECTED_ERROR', context)\n\t\tthis.name = 'BrowserNotConnectedError'\n\t}\n}\n\n/**\n * Reports that an operation was attempted after the browser wrapper was destroyed, under the\n * code `BROWSER_DESTROYED_ERROR`.\n */\nexport class BrowserDestroyedError extends BrowserError {\n\tconstructor(context?: Readonly<Record<string, unknown>>) {\n\t\tsuper('Browser has been destroyed', 'BROWSER_DESTROYED_ERROR', context)\n\t\tthis.name = 'BrowserDestroyedError'\n\t}\n}\n\n// === Server browser type guards\n\n/**\n * Narrows an unknown value to a `BrowserNotConnectedError`.\n *\n * @param value - Value to check\n * @returns True if value is a BrowserNotConnectedError instance; false otherwise\n */\nexport function isBrowserNotConnectedError(value: unknown): value is BrowserNotConnectedError {\n\treturn isInstance(value, BrowserNotConnectedError)\n}\n\n/**\n * Narrows an unknown value to a `BrowserDestroyedError`.\n *\n * @param value - Value to check\n * @returns True if value is a BrowserDestroyedError instance; false otherwise\n */\nexport function isBrowserDestroyedError(value: unknown): value is BrowserDestroyedError {\n\treturn isInstance(value, BrowserDestroyedError)\n}\n","import type { ChildProcess } from 'node:child_process'\nimport type { Readable } from 'node:stream'\nimport type { CDPTarget } from '@src/core'\nimport type { Result } from '@orkestrel/contract'\nimport type {\n\tBrowserEngine,\n\tBrowserProfileResult,\n\tSystemBrowser,\n\tSystemBrowserOptions,\n} from './types.js'\nimport { existsSync, globSync } from 'node:fs'\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { basename, dirname, join, resolve, win32 as pathWin32, posix as pathPosix } from 'node:path'\nimport { spawn, spawnSync } from 'node:child_process'\nimport { isArray, isRecord, isString } from '@orkestrel/contract'\nimport { BrowserConnectionError, BrowserError } from '@src/core'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_LIST_PATH,\n\tBROWSER_DEVTOOLS_PATTERN,\n\tBROWSER_ENV_PATH_KEYS,\n\tBROWSER_EXECUTABLE_PATHS,\n\tBROWSER_EXECUTABLE_NAMES,\n\tBROWSER_WINDOWS_SUFFIXES,\n\tBROWSER_WINDOWS_ROOT_FALLBACKS,\n\tBROWSER_STORE_ENV_KEY,\n\tBROWSER_STORE_DEFAULT_DIRS,\n\tBROWSER_STORE_CACHE_DIRS,\n\tBROWSER_STORE_LINK_NAME,\n\tBROWSER_STORE_GLOBS,\n\tBROWSER_ENGINE_HINTS,\n\tBROWSER_LAUNCH_ARGS,\n\tBROWSER_HEADLESS_ARG,\n\tBROWSER_DEFAULT_HOST,\n\tBROWSER_PROFILE_PREFIX,\n} from './constants.js'\n\n/**\n * Formats a process identifier and UUID token as a lock entry name.\n * @param pid - Positive safe integer identifying the holder process\n * @param token - Lowercase UUID token identifying this acquisition\n * @returns The entry name\n * @example\n * formatBrowserLockEntry(123, '11111111-1111-4111-8111-111111111111')\n */\nexport function formatBrowserLockEntry(pid: number, token: string): string {\n\treturn `${pid}-${token}`\n}\n\n/**\n * Parses the holder process identifier from a lock entry name.\n * @remarks Requires a positive safe integer followed by a lowercase UUID token.\n * @param name - Directory entry name\n * @returns The process identifier, or undefined when the entry is malformed\n * @example\n * parseBrowserLockEntry('123-11111111-1111-4111-8111-111111111111') // 123\n */\nexport function parseBrowserLockEntry(name: string): number | undefined {\n\tconst match = /^([1-9]\\d*)-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.exec(\n\t\tname,\n\t)\n\tconst pid = Number(match?.[1])\n\treturn Number.isSafeInteger(pid) && pid > 0 ? pid : undefined\n}\n\n// === Discovery helpers\n\n/**\n * Enumerates every Chrome/Chromium/Edge executable discoverable on this\n * machine, deduplicated by normalized absolute path.\n *\n * @remarks\n * Resolution precedence (candidates appended in this order):\n * 1. `PLAYWRIGHT_EXECUTABLE_PATH`, then `CHROME_PATH` — explicit environment\n * overrides that exist on disk\n * 2. Well-known platform install locations (Chrome, Edge, Chromium); Windows\n * roots are derived from `PROGRAMFILES` / `PROGRAMFILES(X86)` / `LOCALAPPDATA`\n * 3. PATH probe for known command names (`which` on POSIX, `where` on Windows)\n * 4. Playwright-managed browser stores (`PLAYWRIGHT_BROWSERS_PATH`, `/opt/pw-browsers`,\n * and the per-OS Playwright cache directory) — the top-level `chromium`\n * link/binary, then the highest-revision `chromium-*` install found\n *\n * Each candidate is classified into a {@link BrowserEngine} through\n * `parseBrowserEngine` (unclassifiable candidates default to `'chromium'`),\n * and `options.engine` (when given) narrows the result to that engine.\n *\n * @param options - Overrides for the candidate sources; see {@link SystemBrowserOptions}\n * @returns Every discovered browser, in resolution-precedence order\n */\nexport function findSystemBrowsers(options?: SystemBrowserOptions): readonly SystemBrowser[] {\n\tconst platform = process.platform\n\tconst env = options?.env ?? process.env\n\n\tconst candidates: string[] = []\n\n\tcandidates.push(...findEnvOverrides(env))\n\n\tconst paths = options?.paths ?? buildInstallPaths(platform, env)\n\tcandidates.push(...findInstallPaths(paths))\n\n\tconst names = options?.names ?? BROWSER_EXECUTABLE_NAMES\n\tcandidates.push(...probePathNames(names, platform))\n\n\tconst stores = options?.stores ?? buildStoreBases(env, platform)\n\tfor (const store of stores) {\n\t\tcandidates.push(...findStorePaths(store, platform))\n\t}\n\n\tconst seen = new Set<string>()\n\tconst browsers: SystemBrowser[] = []\n\n\tfor (const executable of candidates) {\n\t\tconst key = normalizeExecutablePath(executable, platform)\n\t\tif (seen.has(key)) continue\n\t\tseen.add(key)\n\n\t\tconst engine = parseBrowserEngine(executable) ?? 'chromium'\n\t\tif (options?.engine !== undefined && engine !== options.engine) continue\n\n\t\tbrowsers.push({ executable, engine })\n\t}\n\n\treturn browsers\n}\n\n/**\n * Locates a Chrome/Chromium/Edge executable on this machine — the first entry\n * of {@link findSystemBrowsers}.\n *\n * @param options - Overrides for the candidate sources; see {@link SystemBrowserOptions}\n * @returns The first discovered browser, or undefined\n */\nexport function findSystemBrowser(options?: SystemBrowserOptions): SystemBrowser | undefined {\n\treturn findSystemBrowsers(options)[0]\n}\n\n/**\n * Classifies an executable path/name into a {@link BrowserEngine} by\n * case-insensitive hint, checked in the order edge → chromium → chrome.\n *\n * @param executable - Executable path or command name to classify\n * @returns The classified engine, or undefined when no hint matches\n */\nexport function parseBrowserEngine(executable: string): BrowserEngine | undefined {\n\tconst lower = executable.toLowerCase()\n\tconst order: readonly BrowserEngine[] = ['edge', 'chromium', 'chrome']\n\tfor (const engine of order) {\n\t\tconst hints = BROWSER_ENGINE_HINTS[engine]\n\t\tif (hints.some((hint) => lower.includes(hint))) return engine\n\t}\n\treturn undefined\n}\n\n/** Normalizes an executable path for cross-source deduplication (case-insensitive on Windows). */\nexport function normalizeExecutablePath(path: string, platform: string): string {\n\tconst normalized = platform === 'win32' ? pathWin32.normalize(path) : pathPosix.normalize(path)\n\treturn platform === 'win32' ? normalized.toLowerCase() : normalized\n}\n\n/** Classifies a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */\nexport function browserToEngine(browser?: string): BrowserEngine {\n\tif (browser?.includes('Edg/') === true) return 'edge'\n\tif (browser?.includes('Chrome/') === true) return 'chrome'\n\treturn 'chromium'\n}\n\n/**\n * Resolves a persistent caller profile or creates an isolated temporary one.\n *\n * @param path - Optional caller-owned persistent user-data directory\n * @returns The resolved profile and whether the library owns its lifecycle\n */\nexport async function createBrowserProfile(path?: string): Promise<BrowserProfileResult> {\n\tif (path !== undefined) return { path, temporary: false }\n\tconst directory = await mkdtemp(join(tmpdir(), BROWSER_PROFILE_PREFIX))\n\treturn { path: directory, temporary: true }\n}\n\n/**\n * Removes a library-owned isolated browser profile.\n *\n * @remarks\n * The path must remain a direct child of the operating-system temp directory\n * with {@link BROWSER_PROFILE_PREFIX}; this defensive check prevents a\n * malformed profile value from widening recursive deletion.\n *\n * @param profile - Resolved profile lifecycle result\n */\nexport async function removeBrowserProfile(profile: BrowserProfileResult): Promise<void> {\n\tif (!profile.temporary) return\n\tconst path = resolve(profile.path)\n\tconst temporary = resolve(tmpdir())\n\tif (dirname(path) !== temporary || !basename(path).startsWith(BROWSER_PROFILE_PREFIX)) {\n\t\tthrow new BrowserError('Refusing to remove an unsafe browser profile path', undefined, {\n\t\t\tpath,\n\t\t})\n\t}\n\tawait rm(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })\n}\n\n/** Checks the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order and returns every one that exists. */\nexport function findEnvOverrides(\n\tenv: Readonly<Record<string, string | undefined>>,\n): readonly string[] {\n\tconst found: string[] = []\n\tfor (const key of BROWSER_ENV_PATH_KEYS) {\n\t\tconst value = env[key]\n\t\tif (value !== undefined && value.length > 0 && existsSync(value)) found.push(value)\n\t}\n\treturn found\n}\n\n/** Builds the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */\nexport function buildInstallPaths(\n\tplatform: string,\n\tenv: Readonly<Record<string, string | undefined>>,\n): readonly string[] {\n\tif (platform !== 'win32') return BROWSER_EXECUTABLE_PATHS[platform] ?? []\n\n\tconst roots = buildWindowsRoots(env)\n\tconst paths: string[] = []\n\tfor (const root of roots) {\n\t\tfor (const suffix of BROWSER_WINDOWS_SUFFIXES) {\n\t\t\tpaths.push(pathWin32.join(root, suffix))\n\t\t}\n\t}\n\treturn paths\n}\n\n/** Derives Windows install roots from env vars, falling back to well-known literals when absent. */\nexport function buildWindowsRoots(\n\tenv: Readonly<Record<string, string | undefined>>,\n): readonly string[] {\n\tconst programFiles = env['PROGRAMFILES'] ?? BROWSER_WINDOWS_ROOT_FALLBACKS['PROGRAMFILES']\n\tconst programFilesX86 =\n\t\tenv['PROGRAMFILES(X86)'] ?? BROWSER_WINDOWS_ROOT_FALLBACKS['PROGRAMFILES(X86)']\n\tconst localAppData = env['LOCALAPPDATA']\n\n\tconst roots = [programFiles, programFilesX86, localAppData]\n\treturn roots.filter((root): root is string => root !== undefined)\n}\n\n/** Returns every candidate path that exists on disk, in the given order. */\nexport function findInstallPaths(paths: readonly string[]): readonly string[] {\n\treturn paths.filter((path) => existsSync(path))\n}\n\n/** Probes PATH (`which`/`where`) for every resolvable command name, in the given order. */\nexport function probePathNames(names: readonly string[], platform: string): readonly string[] {\n\tconst finder = platform === 'win32' ? 'where' : 'which'\n\tconst found: string[] = []\n\tfor (const name of names) {\n\t\tconst result = spawnSync(finder, [name], { stdio: 'pipe' })\n\t\tif (result.status === 0) {\n\t\t\tconst executable = readFirstLine(result.stdout.toString('utf-8'))\n\t\t\tif (executable !== undefined) found.push(executable)\n\t\t}\n\t}\n\treturn found\n}\n\n/**\n * Returns the first non-empty line of a command's output, without its\n * surrounding whitespace.\n *\n * @remarks\n * `where` reports every PATH match on its own CRLF-terminated line, so a\n * carriage return left on the first line would travel into `existsSync` and\n * `spawn` as part of the executable path.\n *\n * @param output - Raw decoded standard output of a command\n * @returns The first line carrying text, or undefined when the output has none\n *\n * @example\n * ```ts\n * readFirstLine('C:\\\\bin\\\\chrome.exe\\r\\nC:\\\\other\\\\chrome.exe\\r\\n') // 'C:\\\\bin\\\\chrome.exe'\n * ```\n */\nexport function readFirstLine(output: string): string | undefined {\n\tfor (const line of output.split(/\\r?\\n/)) {\n\t\tconst text = line.trim()\n\t\tif (text.length > 0) return text\n\t}\n\treturn undefined\n}\n\n/** Builds the default Playwright browser store base directories to search for a managed Chromium. */\nexport function buildStoreBases(\n\tenv: Readonly<Record<string, string | undefined>>,\n\tplatform: string,\n): readonly string[] {\n\tconst bases: string[] = []\n\n\tconst envBase = env[BROWSER_STORE_ENV_KEY]\n\tif (envBase !== undefined && envBase.length > 0) bases.push(envBase)\n\n\tbases.push(...BROWSER_STORE_DEFAULT_DIRS)\n\n\tif (platform === 'win32') {\n\t\tconst localAppData = env['LOCALAPPDATA']\n\t\tif (localAppData !== undefined) bases.push(pathWin32.join(localAppData, 'ms-playwright'))\n\t} else {\n\t\tconst cacheDir = BROWSER_STORE_CACHE_DIRS[platform]\n\t\tconst home = env['HOME']\n\t\tif (cacheDir !== undefined && home !== undefined) bases.push(pathPosix.join(home, cacheDir))\n\t}\n\n\treturn bases\n}\n\n/** Searches one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */\nexport function findStorePaths(base: string, platform: string): readonly string[] {\n\tconst joiner = platform === 'win32' ? pathWin32.join : pathPosix.join\n\tconst found: string[] = []\n\n\tconst linkPath = joiner(base, BROWSER_STORE_LINK_NAME)\n\tif (existsSync(linkPath)) found.push(linkPath)\n\n\tconst glob = BROWSER_STORE_GLOBS[platform]\n\tif (glob === undefined) return found\n\n\tconst pattern = `${base.replaceAll('\\\\', '/')}/${glob}`\n\tconst matches = globSync(pattern).filter((match) => existsSync(match))\n\tmatches.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))\n\tfound.push(...matches)\n\n\treturn found\n}\n\n/**\n * Launches a browser process with raw-CDP debugging flags.\n *\n * @remarks\n * POSIX launches own an isolated process group so lifecycle teardown can\n * signal and await every Chromium subprocess without affecting the caller.\n * Windows launches are not detached and own no group, so teardown there\n * signals one process by identifier: the spawned process, or the process the\n * launcher handed the endpoint to when that spawned process re-executed the\n * browser and exited. Terminating a Chromium browser process takes its own\n * subprocesses with it, so that single signal drains the tree.\n *\n * @param executable - Absolute path to the browser executable\n * @param port - Port the browser exposes its CDP endpoint on, or undefined for a port the operating system picks\n * @param headless - Whether to launch in headless mode\n * @param profile - Optional user-data-dir for a persistent profile\n * @param extra - Additional command-line flags\n * @returns The spawned ChildProcess, whose standard error carries the endpoint line `readBrowserEndpoint` reads\n */\nexport function launchBrowserProcess(\n\texecutable: string,\n\tport: number | undefined,\n\theadless: boolean,\n\tprofile?: string,\n\textra?: readonly string[],\n): ChildProcess {\n\t// Caller-supplied args come first so a script path (for example `node <script>`,\n\t// used to spawn a Node stand-in executable cross-platform in tests) lands\n\t// as an early positional argv entry ahead of the CDP flags that follow —\n\t// Chromium itself accepts flags in any order, so production is unaffected.\n\tconst args: string[] = []\n\tif (extra !== undefined) args.push(...extra)\n\targs.push(`--remote-debugging-port=${port ?? 0}`, ...BROWSER_LAUNCH_ARGS)\n\n\tif (headless) args.push(BROWSER_HEADLESS_ARG)\n\tif (profile !== undefined) args.push(`--user-data-dir=${profile}`)\n\n\treturn spawn(executable, args, {\n\t\tstdio: ['ignore', 'ignore', 'pipe'],\n\t\tdetached: process.platform !== 'win32',\n\t})\n}\n\n/**\n * Reads the CDP endpoint a launched browser announces on its standard error.\n *\n * @remarks\n * Chromium prints `DevTools listening on ws://HOST:PORT/devtools/browser/ID` after it binds the\n * debugging port. The read splits arriving text on line breaks across chunks, so a line split\n * between two chunks and a line ending `\\r\\n` both resolve. After resolving, the stream keeps\n * draining until it closes so the browser's logging never fills the pipe.\n *\n * @param stream - The browser's standard error\n * @param signal - Abort that rejects the read with its reason\n * @returns The `ws://` endpoint the browser announced\n *\n * @throws When the stream closes without the line, or the signal aborts first\n */\nexport function readBrowserEndpoint(stream: Readable, signal: AbortSignal): Promise<string> {\n\tconst read = Promise.withResolvers<string>()\n\tlet pending = ''\n\tlet found = false\n\n\tif (signal.aborted) read.reject(signal.reason)\n\tsignal.addEventListener('abort', () => read.reject(signal.reason), { once: true })\n\tstream.on('error', read.reject)\n\tstream.setEncoding('utf8')\n\tstream.on('data', (chunk) => {\n\t\tif (found || !isString(chunk)) return\n\t\tconst lines = (pending + chunk).split(/\\r\\n|\\n/)\n\t\tpending = lines.pop() ?? ''\n\t\tfor (const line of lines) {\n\t\t\tconst endpoint = BROWSER_DEVTOOLS_PATTERN.exec(line)?.[1]\n\t\t\tif (endpoint === undefined) continue\n\t\t\tfound = true\n\t\t\tpending = ''\n\t\t\tread.resolve(endpoint)\n\t\t\treturn\n\t\t}\n\t})\n\tstream.on('close', () => {\n\t\tconst endpoint = found ? undefined : BROWSER_DEVTOOLS_PATTERN.exec(pending)?.[1]\n\t\tif (endpoint !== undefined) read.resolve(endpoint)\n\t\telse {\n\t\t\tread.reject(\n\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t'Browser closed its standard error before reporting a CDP endpoint',\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t})\n\n\treturn read.promise\n}\n\n/**\n * Fetches the current CDP target list from a browser's `/json/list` endpoint, as a `Result`\n * carrying either the targets or a coded `BrowserConnectionError`.\n *\n * @remarks\n * The endpoint is a network boundary, so an unreachable host, a non-2xx\n * response, and a body that is not a JSON array each come back as a failed\n * `Result` carrying a coded `BrowserConnectionError`. An entry missing a\n * required string field is skipped rather than failing the whole list.\n *\n * @param port - Port the browser exposes its CDP endpoint on\n * @param timeout - Request timeout in milliseconds\n * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)\n * @returns The normalized CDP targets, or the fault that stopped the request\n *\n * @example\n * ```ts\n * import { fetchCDPTargets } from '@orkestrel/browser/server'\n *\n * const result = await fetchCDPTargets(9222, 2000)\n * if (result.success) log(result.value.length)\n * else log(result.error.code)\n * ```\n */\nexport async function fetchCDPTargets(\n\tport: number,\n\ttimeout: number,\n\thost: string = BROWSER_DEFAULT_HOST,\n): Promise<Result<readonly CDPTarget[], BrowserError>> {\n\tconst url = `${BROWSER_CDP_PROTOCOL}://${host}:${port}${BROWSER_CDP_LIST_PATH}`\n\tconst controller = new AbortController()\n\tconst timer = setTimeout(() => controller.abort(), timeout)\n\n\ttry {\n\t\tconst response = await fetch(url, { signal: controller.signal })\n\n\t\tif (!response.ok) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: new BrowserConnectionError('CDP target list request was refused', {\n\t\t\t\t\turl,\n\t\t\t\t\tstatus: response.status,\n\t\t\t\t}),\n\t\t\t}\n\t\t}\n\n\t\tconst list: unknown = await response.json()\n\t\tif (!isArray(list)) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: new BrowserConnectionError('CDP target list is not a JSON array', { url }),\n\t\t\t}\n\t\t}\n\n\t\tconst targets: CDPTarget[] = []\n\t\tfor (const entry of list) {\n\t\t\tif (!isRecord(entry)) continue\n\t\t\tif (\n\t\t\t\t!isString(entry['id']) ||\n\t\t\t\t!isString(entry['type']) ||\n\t\t\t\t!isString(entry['title']) ||\n\t\t\t\t!isString(entry['url'])\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttargets.push({\n\t\t\t\tid: entry['id'],\n\t\t\t\tcategory: entry['type'],\n\t\t\t\ttitle: entry['title'],\n\t\t\t\turl: entry['url'],\n\t\t\t})\n\t\t}\n\n\t\treturn { success: true, value: targets }\n\t} catch (error) {\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: new BrowserConnectionError('CDP target list is unreachable', { url, error }),\n\t\t}\n\t} finally {\n\t\tclearTimeout(timer)\n\t}\n}\n","import type { CDPTransportEventMap, CDPTransportInterface } from '@src/core'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { NodeWebSocketInterface } from '@orkestrel/websocket'\nimport type { WebSocketCDPTransportOptions } from '../types.js'\nimport type { ClientRequest, IncomingMessage, RequestOptions } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport { randomBytes } from 'node:crypto'\nimport { request as httpRequest } from 'node:http'\nimport { request as httpsRequest } from 'node:https'\nimport { attempt, isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport {\n\tcomputeWebSocketAccept,\n\tcreateNodeWebSocket,\n\tWEBSOCKET_READY_CLOSED,\n\tWEBSOCKET_READY_OPEN,\n\tWEBSOCKET_VERSION,\n} from '@orkestrel/websocket'\nimport { BROWSER_DEFAULT_TIMEOUT_MS, BrowserConnectionError, BrowserTransition } from '@src/core'\n\n// === WebSocketCDPTransport\n\n/**\n * Provides a raw CDP text transport backed by `@orkestrel/websocket`.\n *\n * @remarks\n * Performs and validates the RFC 6455 HTTP upgrade, then delegates frame\n * handling to `@orkestrel/websocket`. Concurrent and repeated `start()` /\n * `close()` calls share their active transition, and a later `start()` opens a\n * fresh socket after the prior one closes.\n *\n * @example\n * ```ts\n * import { WebSocketCDPTransport } from '@orkestrel/browser/server'\n *\n * const transport = new WebSocketCDPTransport({ url: 'ws://127.0.0.1:9222/devtools/browser/abc' })\n * await transport.start()\n * await transport.close()\n * ```\n */\nexport class WebSocketCDPTransport implements CDPTransportInterface {\n\treadonly #emitter: Emitter<CDPTransportEventMap>\n\treadonly #url: string\n\treadonly #timeout: number\n\t#socket: NodeWebSocketInterface | undefined\n\treadonly #starting: BrowserTransition = new BrowserTransition()\n\treadonly #closing: BrowserTransition = new BrowserTransition()\n\t#request: ClientRequest | undefined\n\t#resolve: ((socket: NodeWebSocketInterface) => void) | undefined\n\t#reject: ((error: unknown) => void) | undefined\n\t#timer: ReturnType<typeof setTimeout> | undefined\n\t#closeResolve: (() => void) | undefined\n\treadonly #socketCloseHandler = this.#handleSocketClose.bind(this)\n\n\tconstructor(options: WebSocketCDPTransportOptions) {\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#url = options.url\n\t\tthis.#timeout = options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS\n\t}\n\n\tget emitter(): EmitterInterface<CDPTransportEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tasync start(): Promise<void> {\n\t\tconst closing = this.#closing.pending\n\t\tif (closing !== undefined) await closing\n\t\tif (this.#socket?.readyState === WEBSOCKET_READY_OPEN) return\n\n\t\tconst active = this.#starting.pending\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\n\t\tthis.#socket?.destroy()\n\t\tthis.#socket = undefined\n\t\tawait this.#starting.execute(() => this.#start())\n\t}\n\n\tasync send(data: string): Promise<void> {\n\t\tconst socket = this.#socket\n\t\tif (socket === undefined || socket.readyState !== WEBSOCKET_READY_OPEN) {\n\t\t\tthrow new BrowserConnectionError('WebSocket CDP transport is not open', { url: this.#url })\n\t\t}\n\t\tsocket.send(data)\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.#closing.execute(() => this.#close())\n\t}\n\n\t// === Private helpers\n\n\tasync #start(): Promise<void> {\n\t\tconst parsed = attempt(() => new URL(this.#url))\n\t\tif (!parsed.success) {\n\t\t\tthrow new BrowserConnectionError(`WebSocket CDP URL is invalid: ${this.#url}`, {\n\t\t\t\turl: this.#url,\n\t\t\t\terror: parsed.error,\n\t\t\t})\n\t\t}\n\t\tconst url = parsed.value\n\t\tif (url.protocol !== 'ws:' && url.protocol !== 'wss:') {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t`WebSocket CDP connection requires a ws: or wss: URL: ${this.#url}`,\n\t\t\t\t{ url: this.#url },\n\t\t\t)\n\t\t}\n\t\tconst key = randomBytes(16).toString('base64')\n\t\tconst deferred = Promise.withResolvers<NodeWebSocketInterface>()\n\t\tconst options: RequestOptions = {\n\t\t\thostname: url.hostname,\n\t\t\tport: url.port.length > 0 ? Number(url.port) : url.protocol === 'wss:' ? 443 : 80,\n\t\t\tpath: `${url.pathname}${url.search}`,\n\t\t\theaders: {\n\t\t\t\tConnection: 'Upgrade',\n\t\t\t\tUpgrade: 'websocket',\n\t\t\t\t'Sec-WebSocket-Key': key,\n\t\t\t\t'Sec-WebSocket-Version': WEBSOCKET_VERSION,\n\t\t\t},\n\t\t}\n\t\tconst request = url.protocol === 'wss:' ? httpsRequest(options) : httpRequest(options)\n\n\t\tthis.#request = request\n\t\tthis.#resolve = deferred.resolve\n\t\tthis.#reject = deferred.reject\n\t\tthis.#timer = setTimeout(() => this.#expire(request), this.#timeout)\n\n\t\trequest.on('upgrade', (response: IncomingMessage, socket: Duplex, head: Buffer) => {\n\t\t\tthis.#upgrade(request, key, response, socket, head)\n\t\t})\n\t\trequest.on('response', (response) => this.#decline(request, response))\n\t\trequest.on('error', (error) => this.#fail(request, error))\n\t\trequest.end()\n\n\t\tconst socket = await deferred.promise\n\t\tthis.#socket = socket\n\t\tthis.#bind(socket)\n\t}\n\n\tasync #close(): Promise<void> {\n\t\tconst request = this.#request\n\t\tif (request !== undefined) {\n\t\t\tthis.#rejectRequest(\n\t\t\t\trequest,\n\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t`WebSocket CDP connection to ${this.#url} was closed before it finished connecting`,\n\t\t\t\t\t{ url: this.#url },\n\t\t\t\t),\n\t\t\t)\n\t\t\trequest.destroy()\n\t\t}\n\t\tawait this.#starting.pending?.catch(() => undefined)\n\n\t\tconst socket = this.#socket\n\t\tthis.#socket = undefined\n\t\tif (socket === undefined || socket.readyState === WEBSOCKET_READY_CLOSED) return\n\n\t\tconst closed = Promise.withResolvers<void>()\n\t\tthis.#closeResolve = closed.resolve\n\t\tsocket.emitter.on('close', this.#socketCloseHandler)\n\t\ttry {\n\t\t\tsocket.close()\n\t\t\tif (socket.readyState !== WEBSOCKET_READY_CLOSED) await closed.promise\n\t\t} catch {\n\t\t\tsocket.destroy()\n\t\t\tif (socket.readyState !== WEBSOCKET_READY_CLOSED) await closed.promise\n\t\t} finally {\n\t\t\tsocket.emitter.off('close', this.#socketCloseHandler)\n\t\t\tthis.#closeResolve = undefined\n\t\t}\n\t}\n\n\t#upgrade(\n\t\trequest: ClientRequest,\n\t\tkey: string,\n\t\tresponse: IncomingMessage,\n\t\tsocket: Duplex,\n\t\thead: Buffer,\n\t): void {\n\t\tif (this.#request !== request) {\n\t\t\tsocket.destroy()\n\t\t\treturn\n\t\t}\n\n\t\tconst accept = response.headers['sec-websocket-accept']\n\t\tif (!isString(accept) || accept !== computeWebSocketAccept(key)) {\n\t\t\tsocket.destroy()\n\t\t\tthis.#rejectRequest(\n\t\t\t\trequest,\n\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: Sec-WebSocket-Accept mismatch`,\n\t\t\t\t\t{ url: this.#url },\n\t\t\t\t),\n\t\t\t)\n\t\t\treturn\n\t\t}\n\n\t\ttry {\n\t\t\tthis.#resolveRequest(request, createNodeWebSocket({ socket, head }))\n\t\t} catch (error) {\n\t\t\tsocket.destroy()\n\t\t\tthis.#rejectRequest(request, error)\n\t\t}\n\t}\n\n\t#decline(request: ClientRequest, response: IncomingMessage): void {\n\t\tresponse.resume()\n\t\tconst reason =\n\t\t\tresponse.statusCode === undefined\n\t\t\t\t? 'upgrade was declined without a status code'\n\t\t\t\t: `upgrade declined with status ${response.statusCode}`\n\t\tthis.#rejectRequest(\n\t\t\trequest,\n\t\t\tnew BrowserConnectionError(`WebSocket CDP connection to ${this.#url} failed: ${reason}`, {\n\t\t\t\turl: this.#url,\n\t\t\t}),\n\t\t)\n\t}\n\n\t#fail(request: ClientRequest, error: Error): void {\n\t\tthis.#rejectRequest(\n\t\t\trequest,\n\t\t\tnew BrowserConnectionError(\n\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: ${error.message}`,\n\t\t\t\t{ url: this.#url },\n\t\t\t),\n\t\t)\n\t}\n\n\t#expire(request: ClientRequest): void {\n\t\tthis.#rejectRequest(\n\t\t\trequest,\n\t\t\tnew BrowserConnectionError(\n\t\t\t\t`WebSocket CDP connection to ${this.#url} timed out after ${this.#timeout}ms`,\n\t\t\t\t{ url: this.#url, timeout: this.#timeout },\n\t\t\t),\n\t\t)\n\t\trequest.destroy()\n\t}\n\n\t#resolveRequest(request: ClientRequest, socket: NodeWebSocketInterface): void {\n\t\tif (this.#request !== request) {\n\t\t\tsocket.destroy()\n\t\t\treturn\n\t\t}\n\n\t\tconst resolve = this.#resolve\n\t\tthis.#clearRequest()\n\t\tresolve?.(socket)\n\t}\n\n\t#rejectRequest(request: ClientRequest, error: unknown): void {\n\t\tif (this.#request !== request) return\n\n\t\tconst reject = this.#reject\n\t\tthis.#clearRequest()\n\t\treject?.(error)\n\t}\n\n\t#clearRequest(): void {\n\t\tif (this.#timer !== undefined) clearTimeout(this.#timer)\n\t\tthis.#timer = undefined\n\t\tthis.#request = undefined\n\t\tthis.#resolve = undefined\n\t\tthis.#reject = undefined\n\t}\n\n\t#bind(socket: NodeWebSocketInterface): void {\n\t\tsocket.emitter.on('message', (data) => this.#emitter.emit('message', data))\n\t\tsocket.emitter.on('close', () => {\n\t\t\tif (this.#socket === socket) this.#socket = undefined\n\t\t\tthis.#emitter.emit('close')\n\t\t})\n\t\tsocket.emitter.on('error', (error) => this.#emitter.emit('error', error))\n\t}\n\n\t#handleSocketClose(): void {\n\t\tthis.#closeResolve?.()\n\t}\n}\n","import type { BrowserWriterInterface } from '@src/core'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n// === FileBrowserWriter\n\n/**\n * Persists captured browser bytes to the filesystem through `node:fs/promises`.\n *\n * @remarks\n * Creates every missing parent directory of the target path before writing, so\n * a caller may name a nested destination that does not exist yet.\n *\n * @example\n * ```ts\n * import { FileBrowserWriter } from '@orkestrel/browser/server'\n *\n * const writer = new FileBrowserWriter()\n * await writer.write('shots/hero.png', new Uint8Array([137, 80, 78, 71]))\n * ```\n */\nexport class FileBrowserWriter implements BrowserWriterInterface {\n\t/**\n\t * Writes the captured bytes to a path, creating its parent directories.\n\t *\n\t * @param path - Destination file path\n\t * @param data - Captured bytes to persist\n\t * @returns A promise resolving once the bytes are on disk\n\t */\n\tasync write(path: string, data: Uint8Array): Promise<void> {\n\t\tawait mkdir(dirname(path), { recursive: true })\n\t\tawait writeFile(path, data)\n\t}\n}\n","{\n\t\"name\": \"@orkestrel/browser\",\n\t\"version\": \"0.0.22\",\n\t\"description\": \"Chrome DevTools Protocol browser automation with an environment-agnostic core. Part of the @orkestrel line.\",\n\t\"keywords\": [\n\t\t\"automation\",\n\t\t\"browser\",\n\t\t\"cdp\",\n\t\t\"chrome\",\n\t\t\"chromium\",\n\t\t\"devtools\",\n\t\t\"orkestrel\",\n\t\t\"screenshot\",\n\t\t\"typescript\"\n\t],\n\t\"homepage\": \"https://github.com/orkestrel/browser#readme\",\n\t\"bugs\": \"https://github.com/orkestrel/browser/issues\",\n\t\"license\": \"MIT\",\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git+https://github.com/orkestrel/browser.git\"\n\t},\n\t\"bin\": {\n\t\t\"browse\": \"dist/bin/main.js\"\n\t},\n\t\"files\": [\n\t\t\"dist/src\",\n\t\t\"dist/bin\",\n\t\t\"README.md\"\n\t],\n\t\"type\": \"module\",\n\t\"sideEffects\": false,\n\t\"main\": \"./dist/src/core/index.cjs\",\n\t\"module\": \"./dist/src/core/index.js\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/src/core/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/src/core/index.js\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/src/core/index.d.cts\",\n\t\t\t\t\"default\": \"./dist/src/core/index.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./server\": {\n\t\t\t\"import\": {\n\t\t\t\t\"types\": \"./dist/src/server/index.d.ts\",\n\t\t\t\t\"default\": \"./dist/src/server/index.js\"\n\t\t\t},\n\t\t\t\"require\": {\n\t\t\t\t\"types\": \"./dist/src/server/index.d.cts\",\n\t\t\t\t\"default\": \"./dist/src/server/index.cjs\"\n\t\t\t}\n\t\t},\n\t\t\"./browser\": {\n\t\t\t\"types\": \"./dist/src/browser/index.d.ts\",\n\t\t\t\"default\": \"./dist/src/browser/index.js\"\n\t\t},\n\t\t\"./package.json\": \"./package.json\"\n\t},\n\t\"publishConfig\": {\n\t\t\"access\": \"public\"\n\t},\n\t\"scripts\": {\n\t\t\"clean\": \"node -e \\\"require('node:fs').rmSync('dist',{recursive:true,force:true})\\\"\",\n\t\t\"copy\": \"node -e \\\"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\\\"\",\n\t\t\"scaffold\": \"scaffold\",\n\t\t\"lint\": \"oxlint --config .oxlintrc.json --fix .\",\n\t\t\"check\": \"tsc --noEmit --project tsconfig.json && npm run check:src\",\n\t\t\"check:src\": \"npm run check:src:core && npm run check:src:server && npm run check:src:browser && npm run check:src:bin\",\n\t\t\"check:src:core\": \"tsc --noEmit -p configs/src/tsconfig.core.json\",\n\t\t\"check:src:server\": \"tsc --noEmit -p configs/src/tsconfig.server.json\",\n\t\t\"check:src:browser\": \"tsc --noEmit -p configs/src/tsconfig.browser.json\",\n\t\t\"check:src:bin\": \"tsc --noEmit -p configs/src/tsconfig.bin.json\",\n\t\t\"format\": \"oxfmt --config .oxfmtrc.json --write .\",\n\t\t\"format:check\": \"oxfmt --config .oxfmtrc.json --check .\",\n\t\t\"lint:check\": \"oxlint --config .oxlintrc.json --deny-warnings .\",\n\t\t\"test\": \"npm run test:src && npm run test:src:bin && npm run test:policy && npm run test:config && npm run test:setup && npm run test:setup:browser && npm run test:guides && npm run test:conformance\",\n\t\t\"test:conformance\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project conformance\",\n\t\t\"test:src\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core --project src:server --project src:browser\",\n\t\t\"test:src:core\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core\",\n\t\t\"test:src:server\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:server\",\n\t\t\"test:src:browser\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:browser\",\n\t\t\"test:src:bin\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin\",\n\t\t\"test:policy\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project policy\",\n\t\t\"test:config\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project config\",\n\t\t\"test:guides\": \"node --experimental-strip-types tests/guides.test.ts\",\n\t\t\"build\": \"npm run clean && npm run build:src\",\n\t\t\"build:src\": \"npm run build:src:core && npm run build:src:server && npm run build:src:browser && npm run build:src:bin\",\n\t\t\"build:src:core\": \"vite build --config configs/src/vite.core.config.ts && npm run copy dist/src/core/index.d.ts dist/src/core/index.d.cts\",\n\t\t\"build:src:server\": \"vite build --config configs/src/vite.server.config.ts && npm run copy dist/src/server/index.d.ts dist/src/server/index.d.cts\",\n\t\t\"build:src:browser\": \"vite build --config configs/src/vite.browser.config.ts\",\n\t\t\"build:src:bin\": \"vite build --config configs/src/vite.bin.config.ts\",\n\t\t\"prepack\": \"npm run build\",\n\t\t\"prepublishOnly\": \"npm run format:check && npm run lint:check && npm run check && npm run build && npm test && npm run test:distribution -- --mode release && npm run test:service\",\n\t\t\"test:distribution\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project distribution\",\n\t\t\"test:service\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project service\",\n\t\t\"test:probe\": \"vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe\",\n\t\t\"test:bench\": \"vitest bench --config vite.config.ts --no-cache --project probe\",\n\t\t\"test:setup\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project setup\",\n\t\t\"test:setup:browser\": \"vitest run --config vite.config.ts --no-cache --reporter=dot --project setup:browser\"\n\t},\n\t\"dependencies\": {\n\t\t\"@orkestrel/contract\": \"^0.0.19\",\n\t\t\"@orkestrel/emitter\": \"^0.0.11\",\n\t\t\"@orkestrel/html\": \"^0.0.12\",\n\t\t\"@orkestrel/markdown\": \"^0.0.17\",\n\t\t\"@orkestrel/mcp\": \"^0.0.36\",\n\t\t\"@orkestrel/router\": \"^0.0.16\",\n\t\t\"@orkestrel/server\": \"^0.0.22\",\n\t\t\"@orkestrel/tool\": \"^0.0.18\",\n\t\t\"@orkestrel/websocket\": \"^0.0.14\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@microsoft/api-extractor\": \"^7.59.3\",\n\t\t\"@orkestrel/guide\": \"^0.0.24\",\n\t\t\"@orkestrel/probe\": \"^0.0.19\",\n\t\t\"@orkestrel/scaffold\": \"^0.0.89\",\n\t\t\"@orkestrel/test\": \"^0.0.24\",\n\t\t\"@types/node\": \"^26.6.4\",\n\t\t\"@vitest/browser-playwright\": \"^4.1.11\",\n\t\t\"oxfmt\": \"^0.71.0\",\n\t\t\"oxlint\": \"^1.86.0\",\n\t\t\"playwright\": \"^1.63.0\",\n\t\t\"typescript\": \"^6.0.3\",\n\t\t\"vite\": \"^8.3.2\",\n\t\t\"vitest\": \"^4.1.11\"\n\t},\n\t\"engines\": {\n\t\t\"node\": \">=22.12.0\"\n\t}\n}\n","import type { BrowserToolsetInterface } from '@src/core'\nimport type { MCPCallResult, MCPExecutionContext } from '@orkestrel/mcp'\nimport type { StdioServerInterface } from '@orkestrel/mcp/server'\nimport type { ToolContext, ToolInterface, ToolManagerInterface, ToolResult } from '@orkestrel/tool'\nimport type {\n\tBrowserInterface,\n\tBrowserLaunchFunction,\n\tBrowserMCPServerInterface,\n\tBrowserMCPServerOptions,\n} from './types.js'\nimport { randomUUID } from 'node:crypto'\nimport { mkdir, rm } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport { createMCPLegacy, createMCPServer } from '@orkestrel/mcp'\nimport { createStdioServer } from '@orkestrel/mcp/server'\nimport { createTool, createToolManager, toolToDefinition } from '@orkestrel/tool'\nimport {\n\tBROWSER_JOURNEY_TOOL_NAMES,\n\tBROWSER_TOOL_COPY,\n\tBROWSER_TOOL_NAMES,\n\tBrowserError,\n\tcreateBrowserToolset,\n} from '@src/core'\nimport { version } from '../../package.json' with { type: 'json' }\nimport {\n\tcreateBrowser,\n\tcreateFileBrowserJourneyStore,\n\tcreateFileBrowserRunStore,\n} from './factories.js'\n\n/**\n * Implements `BrowserMCPServerInterface`: serves the browser vocabulary and the journey tools over\n * the Model Context Protocol on stdio, and launches Chromium on the first tool call.\n *\n * @remarks\n * The server's own manager holds one dispatcher per name of the vocabulary — `look`, `read`, `plain`,\n * `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, `switch`, `record`, `save`,\n * `journeys`, `edit`, `replay`, and `forget` — each carrying the description, parameters, and annotations\n * `BROWSER_TOOL_COPY` gives, so `tools/list` answers before Chromium starts and with Chromium\n * absent. After the launch, a tool the toolset's manager adds under another name, such as a page\n * tool it adopts, is mirrored as a dispatcher with that tool's definition, and the mirror is\n * removed when the toolset withdraws the tool, so the server's tool list changes and a subscribed\n * client is notified. The first call of any dispatcher launches Chromium one time: concurrent callers await\n * the same launch, a failed launch rejects every one of them, and the next call launches again.\n * A launch creates `ROOT/.profiles/ID/` exclusively, connects a browser that never attaches to an\n * existing endpoint, opens one page in an isolated context, and constructs the page toolset with\n * that context and the file journey and run stores under the root, on a manager the toolset owns.\n * A dispatcher forwards its arguments and the call's context, signal included, to the toolset's\n * manager and returns that manager's value, or rejects with its failure message; a text value\n * reaches the client as one text block rather than as its JSON text.\n *\n * `start()` serves stdio and destroys the server at the end of its input, on `SIGINT`, and on\n * `SIGTERM`. `destroy()` stops reading requests and removes every dispatcher, then destroys the\n * toolset, which aborts the active replay, then the browser it launched, then removes the profile.\n *\n * Chromium on Linux refuses to start as the root user unless its sandbox is disabled, so a server\n * running as root on Linux launches Chromium with `--no-sandbox`; a launch that could run\n * sandboxed is never changed.\n *\n * @example\n * ```ts\n * import { BrowserMCPServer } from '@orkestrel/browser/server'\n *\n * const server = new BrowserMCPServer({ root: 'tmp/browsers', readonly: true })\n * await server.start()\n * await server.destroy()\n * ```\n */\nexport class BrowserMCPServer implements BrowserMCPServerInterface {\n\treadonly #root: string\n\treadonly #headless: boolean\n\treadonly #executable: string | undefined\n\treadonly #readonly: boolean\n\treadonly #launcher: BrowserLaunchFunction\n\treadonly #input: NodeJS.ReadableStream\n\treadonly #tools: ToolManagerInterface\n\treadonly #transport: StdioServerInterface\n\treadonly #abort = new AbortController()\n\treadonly #signal: () => void\n\treadonly #vocabulary: ReadonlySet<string>\n\treadonly #added: (tool: ToolInterface) => void\n\treadonly #removed: (tool: ToolInterface) => void\n\treadonly #cleared: (tools: readonly ToolInterface[]) => void\n\t#mirrored: ToolManagerInterface | undefined\n\t#session: Promise<BrowserToolsetInterface> | undefined\n\t#browser: BrowserInterface | undefined\n\t#profile: string | undefined\n\t#started = false\n\t#closing: Promise<void> | undefined\n\n\t/**\n\t * Registers the dispatchers and binds the protocol to the stdio streams without reading them.\n\t *\n\t * @param options - The root, the launch, the journeys' read-only switch, and the streams\n\t */\n\tconstructor(options?: BrowserMCPServerOptions) {\n\t\tthis.#root = resolve(options?.root ?? 'tmp/browsers')\n\t\tthis.#headless = options?.headless ?? true\n\t\tthis.#executable = options?.executable\n\t\tthis.#readonly = options?.readonly ?? false\n\t\tthis.#launcher = options?.launch ?? createBrowser\n\t\tthis.#input = options?.stdio?.input ?? process.stdin\n\t\tthis.#tools = createToolManager()\n\t\tconst names = [...BROWSER_TOOL_NAMES, ...BROWSER_JOURNEY_TOOL_NAMES]\n\t\tthis.#vocabulary = new Set(names)\n\t\tfor (const name of names) {\n\t\t\tthis.#tools.add(\n\t\t\t\tcreateTool({\n\t\t\t\t\t...BROWSER_TOOL_COPY[name],\n\t\t\t\t\texecute: this.#forward.bind(this, name),\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\tconst server = createMCPServer({\n\t\t\tidentity: { name: 'browse', version },\n\t\t\ttools: this.#tools,\n\t\t\texecution: this.#execute.bind(this),\n\t\t})\n\t\tthis.#transport = createStdioServer(createMCPLegacy(server), {\n\t\t\tinput: this.#input,\n\t\t\t...(options?.stdio?.output === undefined ? {} : { output: options.stdio.output }),\n\t\t})\n\t\t// One reference serves the end of input and both signals, because a listener is removed by\n\t\t// identity.\n\t\tthis.#signal = this.#end.bind(this)\n\t\tthis.#added = this.#mirror.bind(this)\n\t\tthis.#removed = this.#withdraw.bind(this)\n\t\tthis.#cleared = this.#clear.bind(this)\n\t}\n\n\tasync start(): Promise<void> {\n\t\tif (this.#closing !== undefined) throw this.#ended()\n\t\tif (this.#started) return\n\t\tthis.#started = true\n\t\tthis.#transport.start()\n\t\tthis.#input.on('end', this.#signal)\n\t\tprocess.on('SIGINT', this.#signal)\n\t\tprocess.on('SIGTERM', this.#signal)\n\t}\n\n\tdestroy(): Promise<void> {\n\t\tthis.#closing ??= this.#destroy()\n\t\treturn this.#closing\n\t}\n\n\tasync #destroy(): Promise<void> {\n\t\t// The handlers go first: a second signal during a slow teardown asks for the process.\n\t\tprocess.removeListener('SIGINT', this.#signal)\n\t\tprocess.removeListener('SIGTERM', this.#signal)\n\t\tthis.#input.removeListener('end', this.#signal)\n\t\tthis.#transport.stop()\n\t\tfor (const tool of this.#tools.tools()) this.#tools.remove(tool.name)\n\t\tthis.#unmirror()\n\t\t// Aborting the launch signal ends a connect in flight, so its launch cleans up after itself.\n\t\tthis.#abort.abort()\n\t\t// Each step runs whether or not an earlier one failed, so the profile is always removed.\n\t\tconst failures: unknown[] = []\n\t\tconst toolset = await this.#session?.catch(() => undefined)\n\t\tawait toolset?.destroy().catch((error: unknown) => failures.push(error))\n\t\tawait this.#browser?.destroy().catch((error: unknown) => failures.push(error))\n\t\tthis.#browser = undefined\n\t\tconst profile = this.#profile\n\t\tthis.#profile = undefined\n\t\t// `rm` retries a busy directory within its budget, which a Chromium that has ended can leave.\n\t\tif (profile !== undefined) await rm(profile, { recursive: true, force: true, maxRetries: 5 })\n\t\tif (failures.length > 0) throw new AggregateError(failures, 'The browse server teardown failed')\n\t}\n\n\t// Runs the dispatcher and answers a text result as one text block, because the protocol's own\n\t// rendering of a value is its JSON text, which escapes every quote and line break of a receipt.\n\tasync #execute(context: MCPExecutionContext): Promise<ToolResult | MCPCallResult> {\n\t\tconst result = await context.tools.execute(context.call, {\n\t\t\tsignal: context.signal,\n\t\t\t...(context.caller === undefined ? {} : { caller: context.caller }),\n\t\t})\n\t\tif (!result.success || typeof result.value !== 'string') return result\n\t\treturn { resultType: 'complete', content: [{ type: 'text', text: result.value }] }\n\t}\n\n\t// Answers the end of input and a termination signal.\n\t#end(): void {\n\t\tvoid this.destroy()\n\t}\n\n\tasync #forward(\n\t\tname: string,\n\t\targs: Readonly<Record<string, unknown>>,\n\t\tcontext: ToolContext,\n\t): Promise<unknown> {\n\t\tconst toolset = await this.#open()\n\t\tconst result = await toolset.tools.execute({ id: name, name, arguments: args }, context)\n\t\tif (!result.success) throw new BrowserError(result.error)\n\t\treturn result.value\n\t}\n\n\t// Returns the launch every caller shares; a rejected launch is forgotten so the next call retries.\n\t// Stopping the transport aborts a call in flight and `destroy()` removes the dispatchers, so the\n\t// refusal here is the last of three layers that keep a call from launching after `destroy()`.\n\t#open(): Promise<BrowserToolsetInterface> {\n\t\tif (this.#closing !== undefined) return Promise.reject(this.#ended())\n\t\tconst current = this.#session\n\t\tif (current !== undefined) return current\n\t\tconst session = this.#launch()\n\t\tthis.#session = session\n\t\tsession.catch(() => {\n\t\t\tif (this.#session === session) this.#session = undefined\n\t\t})\n\t\treturn session\n\t}\n\n\tasync #launch(): Promise<BrowserToolsetInterface> {\n\t\tawait mkdir(this.#root, { recursive: true })\n\t\tconst profiles = join(this.#root, '.profiles')\n\t\tawait mkdir(profiles, { recursive: true })\n\t\tconst profile = join(profiles, randomUUID())\n\t\t// Without `recursive`, an existing directory refuses with `EEXIST`, so no two launches share one.\n\t\tawait mkdir(profile)\n\t\tthis.#profile = profile\n\t\tlet browser: BrowserInterface | undefined\n\t\tlet toolset: BrowserToolsetInterface | undefined\n\t\ttry {\n\t\t\tbrowser = this.#launcher({\n\t\t\t\theadless: this.#headless,\n\t\t\t\tprofile,\n\t\t\t\tcdp: { discover: false },\n\t\t\t\tsignal: this.#abort.signal,\n\t\t\t\t...(this.#executable === undefined ? {} : { executable: this.#executable }),\n\t\t\t\t...(process.platform === 'linux' && process.getuid?.() === 0\n\t\t\t\t\t? { args: ['--no-sandbox'] }\n\t\t\t\t\t: {}),\n\t\t\t})\n\t\t\tthis.#browser = browser\n\t\t\tawait browser.connect()\n\t\t\tconst context = await browser.isolate()\n\t\t\tconst page = await context.create()\n\t\t\ttoolset = createBrowserToolset(page, {\n\t\t\t\tcontext,\n\t\t\t\tjourneys: {\n\t\t\t\t\tstore: createFileBrowserJourneyStore({ root: this.#root }),\n\t\t\t\t\truns: createFileBrowserRunStore({ root: this.#root }),\n\t\t\t\t\treadonly: this.#readonly,\n\t\t\t\t},\n\t\t\t})\n\t\t\t// The toolset adopts page tools during `start()`, so the mirror follows it from before.\n\t\t\tthis.#mirrored = toolset.tools\n\t\t\ttoolset.tools.emitter.on('add', this.#added)\n\t\t\ttoolset.tools.emitter.on('remove', this.#removed)\n\t\t\ttoolset.tools.emitter.on('clear', this.#cleared)\n\t\t\tawait toolset.start()\n\t\t\treturn toolset\n\t\t} catch (error) {\n\t\t\tthis.#unmirror()\n\t\t\tif (this.#browser === browser) this.#browser = undefined\n\t\t\tif (this.#profile === profile) this.#profile = undefined\n\t\t\tawait toolset?.destroy().catch(() => undefined)\n\t\t\tawait browser?.destroy().catch(() => undefined)\n\t\t\tawait rm(profile, { recursive: true, force: true, maxRetries: 5 })\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t// Adds a dispatcher for a tool the toolset's manager added under a name outside the vocabulary.\n\t#mirror(tool: ToolInterface): void {\n\t\tif (this.#vocabulary.has(tool.name)) return\n\t\tthis.#tools.add(\n\t\t\tcreateTool({ ...toolToDefinition(tool), execute: this.#forward.bind(this, tool.name) }),\n\t\t)\n\t}\n\n\t// Removes the dispatcher of a withdrawn tool; a replacement publishes `remove` while it is\n\t// installed, so the mirror follows the manager's current tool rather than the event.\n\t#withdraw(tool: ToolInterface): void {\n\t\tif (this.#vocabulary.has(tool.name)) return\n\t\tconst current = this.#mirrored?.tool(tool.name)\n\t\tif (current === undefined) this.#tools.remove(tool.name)\n\t\telse this.#mirror(current)\n\t}\n\n\t#clear(tools: readonly ToolInterface[]): void {\n\t\tfor (const tool of tools) this.#withdraw(tool)\n\t}\n\n\t#unmirror(): void {\n\t\tconst mirrored = this.#mirrored\n\t\tif (mirrored === undefined) return\n\t\tthis.#mirrored = undefined\n\t\tmirrored.emitter.off('add', this.#added)\n\t\tmirrored.emitter.off('remove', this.#removed)\n\t\tmirrored.emitter.off('clear', this.#cleared)\n\t}\n\n\t#ended(): BrowserError {\n\t\treturn new BrowserError('the browser session ended', 'BROWSER_TOOLSET_ENDED')\n\t}\n}\n","import type { BrowserStoreOptions, BrowserStorePage, BrowserStoreFault } from '@src/core'\nimport type { FileBrowserStoreOptions } from '../types.js'\nimport { realpathSync } from 'node:fs'\nimport { lstat, mkdir, open, readFile, readdir, rename, rmdir, unlink } from 'node:fs/promises'\nimport { dirname, relative, resolve, sep } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport {\n\tBrowserError,\n\tBROWSER_JOURNEY_NAME_PATTERN,\n\tBROWSER_RUN_ID_PATTERN,\n\tvalidateBrowserStorePage,\n} from '@src/core'\nimport { BROWSER_FILE_STORE_LIMIT, BROWSER_JOURNEY_LOCK_ATTEMPTS } from '../constants.js'\nimport { formatBrowserLockEntry, parseBrowserLockEntry } from '../helpers.js'\n\n/**\n * Shares confined filesystem operations between the journey and run stores.\n * @remarks Requires an existing root directory. Links present during a component check are refused;\n * replacement between a check and its use by another filesystem writer is outside this boundary.\n * @example\n * const files = new FileBrowserStore({ root: directory })\n * files.validateName('check-ready')\n */\nexport class FileBrowserStore {\n\treadonly #root: string\n\treadonly #limit: number\n\n\tconstructor(options: FileBrowserStoreOptions) {\n\t\tthis.#limit = options.limit ?? BROWSER_FILE_STORE_LIMIT\n\t\tif (!Number.isSafeInteger(this.#limit) || this.#limit < 1)\n\t\t\tthrow new BrowserError(\n\t\t\t\t'The listing cap must be a positive integer',\n\t\t\t\t'BROWSER_JOURNEY_ARGUMENT',\n\t\t\t)\n\t\ttry {\n\t\t\tthis.#root = realpathSync(options.root)\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT')\n\t\t\t\tthrow new BrowserError(`Missing root: ${options.root}`, 'BROWSER_JOURNEY_PATH', {\n\t\t\t\t\tpath: options.root,\n\t\t\t\t})\n\t\t\tthrow this.translateError(options.root, error)\n\t\t}\n\t}\n\n\t/** Checks a journey name before filesystem access. @param name - Journey name */\n\tvalidateName(name: string): void {\n\t\tif (!BROWSER_JOURNEY_NAME_PATTERN.test(name))\n\t\t\tthrow new BrowserError(`Refused journey name: ${name}`, 'BROWSER_JOURNEY_PATH')\n\t}\n\n\t/** Checks a run id before filesystem access. @param id - Producer id */\n\tvalidateId(id: string): void {\n\t\tif (!BROWSER_RUN_ID_PATTERN.test(id))\n\t\t\tthrow new BrowserError(`Refused run id: ${id}`, 'BROWSER_JOURNEY_PATH')\n\t}\n\n\t/** Resolves a confined target. @param parts - Relative components @returns Absolute target */\n\tresolvePath(...parts: readonly string[]): string {\n\t\tconst path = resolve(this.#root, ...parts)\n\t\tif (\n\t\t\tpath !== this.#root &&\n\t\t\t!path.startsWith(this.#root.endsWith(sep) ? this.#root : this.#root + sep)\n\t\t)\n\t\t\tthrow new BrowserError(`Refused path: ${path}`, 'BROWSER_JOURNEY_PATH')\n\t\treturn path\n\t}\n\n\t/**\n\t * Checks every existing component including the root and target.\n\t * @param path - Absolute target\n\t * @param options - Cancellation options\n\t * @returns True if the target exists; false if a component is missing\n\t */\n\tasync check(path: string, options?: BrowserStoreOptions): Promise<boolean> {\n\t\tthis.resolvePath(path)\n\t\tlet current = this.#root\n\t\tconst parts = relative(this.#root, path).split(sep).filter(Boolean)\n\t\tfor (let index = 0; index <= parts.length; index += 1) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tconst status = await lstat(current)\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tif (status.isSymbolicLink())\n\t\t\t\t\tthrow new BrowserError(`Refused symbolic link: ${current}`, 'BROWSER_JOURNEY_PATH')\n\t\t\t\tif (index < parts.length && !status.isDirectory())\n\t\t\t\t\tthrow new BrowserError(`Not a directory: ${current}`, 'BROWSER_JOURNEY_PATH')\n\t\t\t} catch (error) {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT') return false\n\t\t\t\tthrow this.translateError(current, error)\n\t\t\t}\n\t\t\tconst part = parts[index]\n\t\t\tif (part !== undefined) current = this.resolvePath(current, part)\n\t\t}\n\t\treturn true\n\t}\n\n\t/** Creates checked directories one component at a time. @param path - Directory @param options - Cancellation options */\n\tasync createDirectory(path: string, options?: BrowserStoreOptions): Promise<void> {\n\t\tif (await this.check(path, options)) return\n\t\tif (path === this.#root) throw new BrowserError(`Missing root: ${path}`, 'BROWSER_JOURNEY_PATH')\n\t\tawait this.createDirectory(dirname(path), options)\n\t\toptions?.signal?.throwIfAborted()\n\t\ttry {\n\t\t\tawait mkdir(path)\n\t\t} catch (error) {\n\t\t\tif (!(error instanceof Error && 'code' in error && error.code === 'EEXIST'))\n\t\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t\tawait this.check(path, options)\n\t}\n\n\t/** Reads an existing file without collapsing a fault to absence. @param path - File @param options - Cancellation options @returns Bytes as UTF-8, or absence */\n\tasync read(path: string, options?: BrowserStoreOptions): Promise<string | undefined> {\n\t\tif (!(await this.check(path, options))) return undefined\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst value = await readFile(path, { encoding: 'utf8', signal: options?.signal })\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\treturn value\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT') return undefined\n\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t}\n\n\t/** Atomically replaces a file and cleans its owned temporary file on failure. @param path - Destination @param value - Bytes or UTF-8 @param options - Cancellation options */\n\tasync write(\n\t\tpath: string,\n\t\tvalue: string | Uint8Array,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<void> {\n\t\tconst temporary = this.resolvePath(dirname(path), `.${randomUUID()}.tmp`)\n\t\tlet owned = false\n\t\ttry {\n\t\t\tawait this.check(path, options)\n\t\t\tawait this.check(temporary, options)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst file = await open(temporary, 'wx')\n\t\t\towned = true\n\t\t\ttry {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tawait file.writeFile(value, { signal: options?.signal })\n\t\t\t} finally {\n\t\t\t\tawait file.close()\n\t\t\t}\n\t\t\tawait this.check(path, options)\n\t\t\tawait this.check(temporary, options)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tawait rename(temporary, path)\n\t\t\t} catch (error) {\n\t\t\t\t// A file cannot replace a directory: hosts report EISDIR or EPERM.\n\t\t\t\tconst target = await lstat(path).catch(() => undefined)\n\t\t\t\tif (\n\t\t\t\t\terror instanceof Error &&\n\t\t\t\t\t'code' in error &&\n\t\t\t\t\t(error.code === 'EISDIR' || error.code === 'EPERM') &&\n\t\t\t\t\ttarget?.isDirectory()\n\t\t\t\t)\n\t\t\t\t\tthrow new BrowserError(`Cannot replace directory: ${path}`, 'BROWSER_JOURNEY_FILE', {\n\t\t\t\t\t\tpath,\n\t\t\t\t\t})\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\towned = false\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.translateError(path, error)\n\t\t} finally {\n\t\t\tif (owned) await this.remove(temporary)\n\t\t}\n\t}\n\n\t/** Removes a checked file, accepting absence. @param path - File @param options - Cancellation options */\n\tasync remove(path: string, options?: BrowserStoreOptions): Promise<void> {\n\t\tif (!(await this.check(path, options))) return\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tawait unlink(path)\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tif (!(error instanceof Error && 'code' in error && error.code === 'ENOENT'))\n\t\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t}\n\n\t/**\n\t * Holds a directory lock through a mutation and releases only its named entry.\n\t * @remarks Reclaims dead or empty locks within a bounded attempt count; a live or unknown holder refuses.\n\t * @param path - Lock directory\n\t * @param action - Mutation inside the lock\n\t * @param options - Cancellation options\n\t * @returns The mutation result\n\t */\n\tasync lock<T>(path: string, action: () => Promise<T>, options?: BrowserStoreOptions): Promise<T> {\n\t\tawait this.createDirectory(dirname(path), options)\n\t\tconst name = formatBrowserLockEntry(process.pid, randomUUID())\n\t\tconst entry = this.resolvePath(path, name)\n\t\tfor (let attempt = 0; attempt < BROWSER_JOURNEY_LOCK_ATTEMPTS; attempt += 1) {\n\t\t\tawait this.check(path, options)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tawait mkdir(path)\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof Error && 'code' in error && error.code === 'EEXIST'))\n\t\t\t\t\tthrow this.translateError(path, error)\n\t\t\t\tconst entries = await this.#readLock(path, options)\n\t\t\t\tif (entries === undefined) continue\n\t\t\t\tif (entries.length > 1) break\n\t\t\t\tconst holder = entries[0]\n\t\t\t\tif (holder !== undefined) {\n\t\t\t\t\tconst pid = parseBrowserLockEntry(holder)\n\t\t\t\t\tif (pid === undefined) break\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocess.kill(pid, 0)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t} catch (cause) {\n\t\t\t\t\t\tif (!(cause instanceof Error && 'code' in cause && cause.code === 'ESRCH')) break\n\t\t\t\t\t}\n\t\t\t\t\tif (!(await this.#unlinkLock(this.resolvePath(path, holder)))) continue\n\t\t\t\t}\n\t\t\t\tawait this.#removeLock(path)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlet owned = false\n\t\t\ttry {\n\t\t\t\tawait this.check(entry, options)\n\t\t\t\ttry {\n\t\t\t\t\tconst file = await open(entry, 'wx')\n\t\t\t\t\towned = true\n\t\t\t\t\tawait file.close()\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error && 'code' in error && error.code === 'ENOENT') continue\n\t\t\t\t\tthrow this.translateError(entry, error)\n\t\t\t\t}\n\t\t\t\t// An empty directory can be replaced between mkdir and entry creation.\n\t\t\t\tconst entries = await this.#readLock(path, options)\n\t\t\t\tif (entries?.length !== 1 || entries[0] !== name) break\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\treturn await action()\n\t\t\t} finally {\n\t\t\t\tif (owned) await this.#unlinkLock(entry)\n\t\t\t\tawait this.#removeLock(path)\n\t\t\t}\n\t\t}\n\t\tthrow new BrowserError(`Journey is locked: ${path}`, 'BROWSER_JOURNEY_LOCKED')\n\t}\n\n\t/**\n\t * Lists readable entries in sorted order with a bounded page and one extra readable probe.\n\t * @param path - Parent directory\n\t * @param reader - Entry reader\n\t * @param options - Paging and cancellation\n\t * @returns Page and observed entry faults\n\t */\n\tasync list<T>(\n\t\tpath: string,\n\t\treader: (name: string) => Promise<T | undefined>,\n\t\toptions?: BrowserStoreOptions & { readonly offset?: number; readonly limit?: number },\n\t): Promise<BrowserStorePage<T>> {\n\t\tconst offset = options?.offset ?? 0\n\t\tconst requested = options?.limit ?? this.#limit\n\t\tvalidateBrowserStorePage(offset, requested)\n\t\tconst limit = Math.min(requested, this.#limit)\n\t\tconst entries: T[] = []\n\t\tconst faults: BrowserStoreFault[] = []\n\t\tif (!(await this.check(path, options))) return { entries, faults, truncated: false }\n\t\tlet names: string[]\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tnames = (await readdir(path)).sort()\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t\tlet count = 0\n\t\tfor (const name of names) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\ttry {\n\t\t\t\tconst entry = await reader(name)\n\t\t\t\tif (entry === undefined) continue\n\t\t\t\tif (count++ < offset) continue\n\t\t\t\tif (entries.length === limit) return { entries, faults, truncated: true }\n\t\t\t\tentries.push(entry)\n\t\t\t} catch (error) {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tconst reason = error instanceof BrowserError ? error.context?.['reason'] : undefined\n\t\t\t\tfaults.push({\n\t\t\t\t\tname,\n\t\t\t\t\treason:\n\t\t\t\t\t\ttypeof reason === 'string'\n\t\t\t\t\t\t\t? reason\n\t\t\t\t\t\t\t: error instanceof BrowserError && error.code === 'BROWSER_JOURNEY_PATH'\n\t\t\t\t\t\t\t\t? 'The entry path is refused'\n\t\t\t\t\t\t\t\t: error instanceof BrowserError && error.code === 'BROWSER_JOURNEY_ACCESS'\n\t\t\t\t\t\t\t\t\t? 'Permission denied'\n\t\t\t\t\t\t\t\t\t: error instanceof BrowserError && error.code === 'BROWSER_JOURNEY_FORMAT'\n\t\t\t\t\t\t\t\t\t\t? 'Unknown file format'\n\t\t\t\t\t\t\t\t\t\t: 'The stored entry is malformed or unreadable',\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\treturn { entries, faults, truncated: false }\n\t}\n\n\t/**\n\t * Allocates a run directory exclusively, retrying colliding producer candidates.\n\t * @param parent - Checked parent directory\n\t * @param candidate - Producer id source\n\t * @param options - Cancellation options\n\t * @returns Allocated id and absolute directory\n\t */\n\tasync allocate(\n\t\tparent: string,\n\t\tcandidate: () => string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<{ readonly id: string; readonly path: string }> {\n\t\tawait this.createDirectory(parent, options)\n\t\tfor (;;) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst id = candidate()\n\t\t\tthis.validateId(id)\n\t\t\tconst path = this.resolvePath(parent, id)\n\t\t\tawait this.check(path, options)\n\t\t\ttry {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tawait mkdir(path)\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\treturn { id, path }\n\t\t\t} catch (error) {\n\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\tif (error instanceof Error && 'code' in error && error.code === 'EEXIST') continue\n\t\t\t\tthrow this.translateError(path, error)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Translates filesystem and validation failures with their path. @param path - Failed path @param error - Cause @returns Coded error */\n\ttranslateError(path: string, error: unknown): BrowserError {\n\t\tconst code = error instanceof Error && 'code' in error ? error.code : undefined\n\t\treturn new BrowserError(\n\t\t\t`${path}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\tcode === 'EACCES' || code === 'EPERM'\n\t\t\t\t? 'BROWSER_JOURNEY_ACCESS'\n\t\t\t\t: error instanceof BrowserError && code !== 'BROWSER_JOURNEY_INVALID'\n\t\t\t\t\t? error.code\n\t\t\t\t\t: 'BROWSER_JOURNEY_FILE',\n\t\t\t{ path },\n\t\t)\n\t}\n\tasync #readLock(\n\t\tpath: string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<readonly string[] | undefined> {\n\t\tawait this.check(path, options)\n\t\ttry {\n\t\t\tconst entries = await readdir(path, { withFileTypes: true })\n\t\t\tfor (const entry of entries) {\n\t\t\t\tawait this.check(this.resolvePath(path, entry.name), options)\n\t\t\t\tif (!entry.isFile())\n\t\t\t\t\tthrow new BrowserError(`Journey is locked: ${path}`, 'BROWSER_JOURNEY_LOCKED')\n\t\t\t}\n\t\t\treturn entries.map((entry) => entry.name)\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && 'code' in error) {\n\t\t\t\tif (error.code === 'ENOENT') return undefined\n\t\t\t\tif (error.code === 'ENOTDIR')\n\t\t\t\t\tthrow new BrowserError(`Journey is locked: ${path}`, 'BROWSER_JOURNEY_LOCKED')\n\t\t\t}\n\t\t\tthrow this.translateError(path, error)\n\t\t}\n\t}\n\n\tasync #unlinkLock(path: string): Promise<boolean> {\n\t\tawait this.check(path)\n\t\ttry {\n\t\t\tawait unlink(path)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tif (\n\t\t\t\terror instanceof Error &&\n\t\t\t\t'code' in error &&\n\t\t\t\t(error.code === 'ENOENT' || error.code === 'ENOTEMPTY')\n\t\t\t)\n\t\t\t\treturn false\n\t\t\tthrow new BrowserError(`Cannot remove lock entry: ${path}`, 'BROWSER_JOURNEY_ACCESS', {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t}\n\n\tasync #removeLock(path: string): Promise<void> {\n\t\tawait this.check(path)\n\t\ttry {\n\t\t\tawait rmdir(path)\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && 'code' in error) {\n\t\t\t\tif (error.code === 'ENOTEMPTY') return\n\t\t\t\tif (error.code === 'ENOENT' || error.code === 'EPERM') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif ((await lstat(path)).isDirectory()) return\n\t\t\t\t\t} catch (cause) {\n\t\t\t\t\t\tif (cause instanceof Error && 'code' in cause && cause.code === 'ENOENT') return\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new BrowserError(`Cannot remove lock directory: ${path}`, 'BROWSER_JOURNEY_ACCESS', {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t}\n}\n","import type {\n\tBrowserJourney,\n\tBrowserJourneyRevision,\n\tBrowserJourneyStoreInterface,\n\tBrowserStoreOptions,\n\tBrowserStorePage,\n} from '@src/core'\nimport type { FileBrowserStoreOptions } from '../types.js'\nimport { isRecord, parseJSON } from '@orkestrel/contract'\nimport {\n\tBROWSER_JOURNEY_NAME_PATTERN,\n\tBrowserError,\n\tvalidateBrowserJourney,\n\tnormalizeBrowserJourneyReason,\n} from '@src/core'\nimport {\n\tBROWSER_JOURNEY_SNAPSHOT_FILE,\n\tBROWSER_JOURNEY_REVISION_FILE,\n\tBROWSER_JOURNEY_LOCK_DIRECTORY,\n} from '../constants.js'\nimport { FileBrowserStore } from './FileBrowserStore.js'\n\n/**\n * Persists journeys with exclusive writes and revision counters retained across deletion.\n * @remarks Requires an existing root. A live holder refuses immediately; dead or empty locks are reclaimed within a bounded attempt count.\n * @example\n * const store = new FileBrowserJourneyStore({ root: directory })\n * await store.set(journey)\n */\nexport class FileBrowserJourneyStore implements BrowserJourneyStoreInterface {\n\treadonly #files: FileBrowserStore\n\n\tconstructor(options: FileBrowserStoreOptions) {\n\t\tthis.#files = new FileBrowserStore(options)\n\t}\n\n\tasync get(\n\t\tname: string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<BrowserJourneyRevision | undefined> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tconst path = this.#files.resolvePath(name, BROWSER_JOURNEY_SNAPSHOT_FILE)\n\t\tconst source = await this.#files.read(path, options)\n\t\tif (source === undefined) return undefined\n\t\ttry {\n\t\t\tconst value = parseJSON(source)\n\t\t\tif (\n\t\t\t\t!isRecord(value) ||\n\t\t\t\ttypeof value['revision'] !== 'number' ||\n\t\t\t\t!Number.isSafeInteger(value['revision']) ||\n\t\t\t\tvalue['revision'] < 1\n\t\t\t)\n\t\t\t\tthrow new BrowserError('Malformed journey revision', 'BROWSER_JOURNEY_FILE')\n\t\t\tif (!isRecord(value['journey']) || !('format' in value['journey']))\n\t\t\t\tthrow new BrowserError('Missing journey format', 'BROWSER_JOURNEY_FILE')\n\t\t\tvalidateBrowserJourney(value['journey'])\n\t\t\tif (value['journey'].name !== name)\n\t\t\t\tthrow new BrowserError('Journey name differs from its directory', 'BROWSER_JOURNEY_FILE')\n\t\t\treturn { journey: value['journey'], revision: value['revision'] }\n\t\t} catch (error) {\n\t\t\tconst translated = this.#files.translateError(path, error)\n\t\t\tthrow new BrowserError(translated.message, translated.code, {\n\t\t\t\t...translated.context,\n\t\t\t\treason: normalizeBrowserJourneyReason(error),\n\t\t\t})\n\t\t}\n\t}\n\n\tasync set(\n\t\tjourney: BrowserJourney,\n\t\texpected?: number,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<BrowserJourneyRevision> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(journey.name)\n\t\tvalidateBrowserJourney(journey)\n\t\tconst owned = structuredClone(journey)\n\t\tconst path = this.#files.resolvePath(owned.name, BROWSER_JOURNEY_SNAPSHOT_FILE)\n\t\tconst counter = this.#files.resolvePath(owned.name, BROWSER_JOURNEY_REVISION_FILE)\n\t\treturn this.#files.lock(\n\t\t\tthis.#files.resolvePath(owned.name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\tconst current = await this.get(owned.name, options)\n\t\t\t\tif (expected !== undefined && expected !== (current?.revision ?? 0))\n\t\t\t\t\tthrow new BrowserError(\n\t\t\t\t\t\t`Journey ${owned.name} changed since you read it`,\n\t\t\t\t\t\t'BROWSER_JOURNEY_STALE',\n\t\t\t\t\t)\n\t\t\t\tconst source = await this.#files.read(counter, options)\n\t\t\t\tconst previous = source === undefined ? 0 : Number(source)\n\t\t\t\tif (!Number.isSafeInteger(previous) || previous < 0 || source?.trim() === '')\n\t\t\t\t\tthrow new BrowserError(`Malformed revision: ${counter}`, 'BROWSER_JOURNEY_FILE')\n\t\t\t\tconst revision = Math.max(previous, current?.revision ?? 0) + 1\n\t\t\t\tif (!Number.isSafeInteger(revision))\n\t\t\t\t\tthrow new BrowserError(`Exhausted revision: ${counter}`, 'BROWSER_JOURNEY_FILE')\n\t\t\t\tconst saved = { journey: owned, revision }\n\t\t\t\tawait this.#files.write(path, JSON.stringify(saved), options)\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#files.write(counter, String(revision), options)\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Rollback and lock cleanup must finish even when the caller aborts.\n\t\t\t\t\tif (current === undefined) await this.#files.remove(path)\n\t\t\t\t\telse await this.#files.write(path, JSON.stringify(current))\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\treturn saved\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync delete(name: string, options?: BrowserStoreOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tawait this.#files.lock(\n\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\tconst current = await this.get(name, options)\n\t\t\t\tif (current === undefined) return\n\t\t\t\tconst counter = this.#files.resolvePath(name, BROWSER_JOURNEY_REVISION_FILE)\n\t\t\t\tconst source = await this.#files.read(counter, options)\n\t\t\t\tconst previous = source === undefined ? 0 : Number(source)\n\t\t\t\tif (!Number.isSafeInteger(previous) || previous < 0 || source?.trim() === '')\n\t\t\t\t\tthrow new BrowserError(`Malformed revision: ${counter}`, 'BROWSER_JOURNEY_FILE')\n\t\t\t\t// Preserve the committed revision even if a process exited before updating its counter.\n\t\t\t\tawait this.#files.write(counter, String(Math.max(previous, current.revision ?? 0)), options)\n\t\t\t\tawait this.#files.remove(\n\t\t\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_SNAPSHOT_FILE),\n\t\t\t\t\toptions,\n\t\t\t\t)\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync list(\n\t\toptions?: BrowserStoreOptions & { readonly offset?: number; readonly limit?: number },\n\t): Promise<BrowserStorePage<BrowserJourneyRevision>> {\n\t\toptions?.signal?.throwIfAborted()\n\t\treturn this.#files.list(\n\t\t\tthis.#files.resolvePath(),\n\t\t\tasync (name) => {\n\t\t\t\tif (!BROWSER_JOURNEY_NAME_PATTERN.test(name)) return undefined\n\t\t\t\treturn this.get(name, options)\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n}\n","import type {\n\tBrowserRun,\n\tBrowserRunSlot,\n\tBrowserRunStoreInterface,\n\tBrowserStoreOptions,\n\tBrowserStorePage,\n} from '@src/core'\nimport type { FileBrowserStoreOptions } from '../types.js'\nimport { lstat, readdir, rm } from 'node:fs/promises'\nimport { isRecord, parseJSON } from '@orkestrel/contract'\nimport {\n\tBROWSER_JOURNEY_FORMAT_VERSION,\n\tBrowserError,\n\tgenerateBrowserRunId,\n\tvalidateBrowserRun,\n} from '@src/core'\nimport {\n\tBROWSER_RUN_FILE,\n\tBROWSER_RUN_DIRECTORY,\n\tBROWSER_JOURNEY_LOCK_DIRECTORY,\n} from '../constants.js'\nimport { FileBrowserStore } from './FileBrowserStore.js'\n\n/**\n * Persists runs and captures only in directories allocated by this instance.\n * @remarks Requires an existing root. Reopened stores can read and delete saved runs.\n * @example\n * const store = new FileBrowserRunStore({ root: directory })\n * const slot = await store.open('check-ready')\n */\nexport class FileBrowserRunStore implements BrowserRunStoreInterface {\n\treadonly #files: FileBrowserStore\n\treadonly #slots = new WeakMap<BrowserRunSlot, string>()\n\treadonly #directories = new Set<string>()\n\n\tconstructor(options: FileBrowserStoreOptions) {\n\t\tthis.#files = new FileBrowserStore(options)\n\t}\n\n\tasync open(name: string, options?: BrowserStoreOptions): Promise<BrowserRunSlot> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\treturn this.#files.lock(\n\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\tconst directory = await this.#files.allocate(\n\t\t\t\t\tthis.#files.resolvePath(name, BROWSER_RUN_DIRECTORY),\n\t\t\t\t\tgenerateBrowserRunId,\n\t\t\t\t\toptions,\n\t\t\t\t)\n\t\t\t\tconst slot = Object.freeze({ id: directory.id, directory: directory.path })\n\t\t\t\tthis.#directories.add(directory.path)\n\t\t\t\tthis.#slots.set(slot, directory.path)\n\t\t\t\treturn slot\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync get(\n\t\tname: string,\n\t\tid: string,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<BrowserRun | undefined> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tthis.#files.validateId(id)\n\t\tconst path = this.#files.resolvePath(name, BROWSER_RUN_DIRECTORY, id, BROWSER_RUN_FILE)\n\t\tconst source = await this.#files.read(path, options)\n\t\tif (source === undefined) return undefined\n\t\ttry {\n\t\t\tconst value = parseJSON(source)\n\t\t\tif (!isRecord(value) || !('format' in value))\n\t\t\t\tthrow new BrowserError('Missing run format', 'BROWSER_JOURNEY_FILE')\n\t\t\tif (\n\t\t\t\tvalue['format'] === BROWSER_JOURNEY_FORMAT_VERSION &&\n\t\t\t\t(!isRecord(value['journey']) || !('format' in value['journey']))\n\t\t\t)\n\t\t\t\tthrow new BrowserError('Missing run journey format', 'BROWSER_JOURNEY_FILE')\n\t\t\tvalidateBrowserRun(value)\n\t\t\tif (value.id !== id || value.journey.name !== name)\n\t\t\t\tthrow new BrowserError('Run identity differs from its directory', 'BROWSER_JOURNEY_FILE')\n\t\t\treturn value\n\t\t} catch (error) {\n\t\t\tthrow this.#files.translateError(path, error)\n\t\t}\n\t}\n\n\tasync set(run: BrowserRun, options?: BrowserStoreOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(run.journey.name)\n\t\tthis.#files.validateId(run.id)\n\t\tvalidateBrowserRun(run)\n\t\tconst source = JSON.stringify(run)\n\t\tconst directory = this.#files.resolvePath(run.journey.name, BROWSER_RUN_DIRECTORY, run.id)\n\t\tawait this.#requireDirectory(directory, options)\n\t\tawait this.#files.write(this.#files.resolvePath(directory, BROWSER_RUN_FILE), source, options)\n\t}\n\n\tasync capture(\n\t\tslot: BrowserRunSlot,\n\t\tname: string,\n\t\tbytes: Uint8Array,\n\t\toptions?: BrowserStoreOptions,\n\t): Promise<string> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tconst directory = this.#slots.get(slot)\n\t\tif (directory === undefined || !/^s[1-9]\\d*\\.png$/.test(name))\n\t\t\tthrow new BrowserError(\n\t\t\t\t'Capture requires an opened slot and an sN.png name',\n\t\t\t\t'BROWSER_JOURNEY_PATH',\n\t\t\t)\n\t\tconst owned = new Uint8Array(bytes)\n\t\tawait this.#requireDirectory(directory, options)\n\t\tawait this.#files.write(this.#files.resolvePath(directory, name), owned, options)\n\t\treturn name\n\t}\n\n\tasync delete(name: string, id: string, options?: BrowserStoreOptions): Promise<void> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tthis.#files.validateId(id)\n\t\tconst directory = this.#files.resolvePath(name, BROWSER_RUN_DIRECTORY, id)\n\t\tawait this.#files.check(this.#files.resolvePath(directory, BROWSER_RUN_FILE), options)\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tawait rm(directory, { recursive: true, force: true, maxRetries: 3 })\n\t\t\tthis.#directories.delete(directory)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.#files.translateError(directory, error)\n\t\t}\n\t}\n\n\tasync clear(name: string, options?: BrowserStoreOptions): Promise<number> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\tconst parent = this.#files.resolvePath(name, BROWSER_RUN_DIRECTORY)\n\t\tif (!(await this.#files.check(parent, options))) return 0\n\t\treturn this.#files.lock(\n\t\t\tthis.#files.resolvePath(name, BROWSER_JOURNEY_LOCK_DIRECTORY),\n\t\t\tasync () => {\n\t\t\t\ttry {\n\t\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\t\tconst ids = await readdir(parent)\n\t\t\t\t\t// Check the whole removal before deleting any run, including unsaved slots.\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tthis.#files.validateId(id)\n\t\t\t\t\t\tawait this.#files.check(this.#files.resolvePath(parent, id, BROWSER_RUN_FILE), options)\n\t\t\t\t\t}\n\t\t\t\t\tfor (const id of ids) await this.delete(name, id, options)\n\t\t\t\t\treturn ids.length\n\t\t\t\t} catch (error) {\n\t\t\t\t\toptions?.signal?.throwIfAborted()\n\t\t\t\t\tthrow this.#files.translateError(parent, error)\n\t\t\t\t}\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync list(\n\t\tname: string,\n\t\toptions?: BrowserStoreOptions & { readonly offset?: number; readonly limit?: number },\n\t): Promise<BrowserStorePage<BrowserRun>> {\n\t\toptions?.signal?.throwIfAborted()\n\t\tthis.#files.validateName(name)\n\t\treturn this.#files.list(\n\t\t\tthis.#files.resolvePath(name, BROWSER_RUN_DIRECTORY),\n\t\t\t(id) => this.get(name, id, options),\n\t\t\toptions,\n\t\t)\n\t}\n\n\tasync #requireDirectory(directory: string, options?: BrowserStoreOptions): Promise<void> {\n\t\tif (!this.#directories.has(directory) || !(await this.#files.check(directory, options)))\n\t\t\tthrow new BrowserError(\n\t\t\t\t`Run directory was not opened or is missing: ${directory}`,\n\t\t\t\t'BROWSER_JOURNEY_PATH',\n\t\t\t)\n\t\ttry {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tconst status = await lstat(directory)\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tif (!status.isDirectory())\n\t\t\t\tthrow new BrowserError(\n\t\t\t\t\t`Run directory is not a directory: ${directory}`,\n\t\t\t\t\t'BROWSER_JOURNEY_PATH',\n\t\t\t\t)\n\t\t} catch (error) {\n\t\t\toptions?.signal?.throwIfAborted()\n\t\t\tthrow this.#files.translateError(directory, error)\n\t\t}\n\t}\n}\n","import type {\n\tBrowserJourneyStoreInterface,\n\tBrowserRunStoreInterface,\n\tCDPTransportInterface,\n\tBrowserWriterInterface,\n} from '@src/core'\nimport type {\n\tFileBrowserStoreOptions,\n\tBrowserInterface,\n\tBrowserMCPServerInterface,\n\tBrowserMCPServerOptions,\n\tBrowserOptions,\n\tWebSocketCDPTransportOptions,\n} from './types.js'\nimport { BrowserMCPServer } from './BrowserMCPServer.js'\nimport { FileBrowserJourneyStore } from './stores/FileBrowserJourneyStore.js'\nimport { FileBrowserRunStore } from './stores/FileBrowserRunStore.js'\nimport { Browser } from './Browser.js'\nimport { WebSocketCDPTransport } from './transports/WebSocketCDPTransport.js'\nimport { FileBrowserWriter } from './writers/FileBrowserWriter.js'\n\n/**\n * Creates a raw-CDP `BrowserInterface` façade with discovery, connection, and lifecycle\n * management.\n *\n * @param options - Connection, launch, and viewport configuration\n * @returns A {@link BrowserInterface}\n *\n * @example Connect to a browser and drive a page\n * ```ts\n * import { createBrowser } from '@orkestrel/browser/server'\n *\n * const browser = createBrowser({ headless: true })\n * await browser.connect() // CDP endpoint discovery → connect, else launch\n * const page = await browser.create({ url: 'https://example.com' })\n * await (await page.elements.find({ css: '#accept' }))[0]?.click()\n * const shot = await page.screenshot({ path: './out.png' })\n * await browser.destroy()\n * ```\n */\nexport function createBrowser(options?: BrowserOptions): BrowserInterface {\n\treturn new Browser(options)\n}\n\n/**\n * Creates a Node `WebSocket`-backed `CDPTransportInterface` for the given CDP debugger URL.\n *\n * @param options - The CDP WebSocket debugger URL (and optional timeout)\n * @returns A {@link CDPTransportInterface}\n */\nexport function createCDPTransport(options: WebSocketCDPTransportOptions): CDPTransportInterface {\n\treturn new WebSocketCDPTransport(options)\n}\n\n/**\n * Creates a filesystem-backed `BrowserWriterInterface` that persists bytes through\n * `node:fs/promises`.\n *\n * @returns A {@link BrowserWriterInterface} that persists bytes through `node:fs/promises`\n */\nexport function createBrowserWriter(): BrowserWriterInterface {\n\treturn new FileBrowserWriter()\n}\n\n/**\n * Creates a journey store over an existing filesystem root.\n * @param options - Root and listing cap\n * @returns A durable journey store\n * @example\n * const store = createFileBrowserJourneyStore({ root: directory })\n */\nexport function createFileBrowserJourneyStore(\n\toptions: FileBrowserStoreOptions,\n): BrowserJourneyStoreInterface {\n\treturn new FileBrowserJourneyStore(options)\n}\n\n/**\n * Creates a run store over an existing filesystem root.\n * @param options - Root and listing cap\n * @returns A durable run and capture store\n * @example\n * const store = createFileBrowserRunStore({ root: directory })\n */\nexport function createFileBrowserRunStore(\n\toptions: FileBrowserStoreOptions,\n): BrowserRunStoreInterface {\n\treturn new FileBrowserRunStore(options)\n}\n\n/**\n * Creates the browse server, which serves the browser vocabulary and the journey tools over the\n * Model Context Protocol on stdio and launches Chromium on the first tool call.\n *\n * @param options - The root, the launch, the journeys' read-only switch, and the streams\n * @returns A {@link BrowserMCPServerInterface} that reads nothing until `start()`\n *\n * @example\n * ```ts\n * import { createBrowserMCPServer } from '@orkestrel/browser/server'\n *\n * const server = createBrowserMCPServer({ root: 'tmp/browsers', headless: true })\n * await server.start() // answers tools/list before Chromium starts\n * await server.destroy()\n * ```\n */\nexport function createBrowserMCPServer(\n\toptions?: BrowserMCPServerOptions,\n): BrowserMCPServerInterface {\n\treturn new BrowserMCPServer(options)\n}\n","import type { ChildProcess } from 'node:child_process'\nimport type {\n\tBrowserConnection,\n\tBrowserDiscoveryResult,\n\tBrowserEngine,\n\tBrowserEventMap,\n\tBrowserInterface,\n\tBrowserOptions,\n\tBrowserProfileResult,\n\tBrowserStatus,\n} from './types.js'\nimport type {\n\tBrowserContextInterface,\n\tBrowserContextOptions,\n\tBrowserPageInterface,\n\tBrowserPageOptions,\n\tCDPTarget,\n\tCDPTransportInterface,\n} from '@src/core'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport { addAbortListener, once } from 'node:events'\nimport { isArray, isError, isInteger, isRecord, isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport {\n\tBrowserConnectionError,\n\tBrowserContext,\n\tBrowserTransition,\n\tBROWSER_DEFAULT_TIMEOUT_MS,\n\tCDPClient,\n\tisBrowserConnectionError,\n\tvalidateBrowserContextOptions,\n} from '@src/core'\nimport { BrowserDestroyedError, BrowserNotConnectedError } from './errors.js'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_DEFAULT_CDP_PORT,\n\tBROWSER_DEFAULT_HOST,\n\tBROWSER_DRAIN_INTERVAL_MS,\n\tBROWSER_KILL_GRACE_MS,\n\tBROWSER_PORT_PROBE_TIMEOUT_MS,\n\tBROWSER_PROCESS_EXIT_CAUSE,\n\tBROWSER_TRANSPORT_LOSS_CAUSE,\n\tBROWSER_TRANSPORT_LOSS_DEFER_MS,\n} from './constants.js'\nimport {\n\tbrowserToEngine,\n\tcreateBrowserProfile,\n\tfindSystemBrowser,\n\tlaunchBrowserProcess,\n\tparseBrowserEngine,\n\treadBrowserEndpoint,\n\tremoveBrowserProfile,\n} from './helpers.js'\nimport { createCDPTransport, createBrowserWriter } from './factories.js'\n\n// === Browser\n\n/**\n * Discovers, launches, connects to, and owns Chromium-family browser sessions.\n *\n * @example\n * ```ts\n * import { Browser } from '@orkestrel/browser/server'\n *\n * const browser = new Browser({ headless: true })\n * await browser.connect()\n * const page = await browser.create({ url: 'https://example.com' })\n * await browser.destroy()\n * ```\n */\nexport class Browser implements BrowserInterface {\n\treadonly #emitter: Emitter<BrowserEventMap>\n\treadonly #options: BrowserOptions\n\treadonly #abort = new AbortController()\n\treadonly #cdpPort: number\n\treadonly #cdpHost: string\n\t#engine: BrowserEngine\n\t#status: BrowserStatus = 'idle'\n\t#connection: BrowserConnection | undefined\n\t#owned: boolean | undefined\n\t#endpoint: string | undefined\n\t#client: CDPClient | undefined\n\t#process: ChildProcess | undefined\n\t// Identifier the launcher handed the endpoint to when it re-executed the\n\t// browser and exited before CDP became ready. Undefined whenever the\n\t// spawned child is itself the process serving the endpoint.\n\t#servingPid: number | undefined\n\t#profile: BrowserProfileResult | undefined\n\t#contexts: BrowserContext[] = []\n\t#destroyed = false\n\treadonly #connecting: BrowserTransition = new BrowserTransition()\n\treadonly #disconnecting: BrowserTransition = new BrowserTransition()\n\t#exitCleanup: Promise<void> | undefined\n\t#shutdown: Promise<void> | undefined\n\t#transport: CDPTransportInterface | undefined\n\treadonly #transportCloseHandler = this.#handleTransportLoss.bind(this)\n\treadonly #transportErrorHandler = this.#handleTransportLoss.bind(this)\n\treadonly #processExitHandler = this.#handleProcessExit.bind(this)\n\n\tconstructor(options?: BrowserOptions) {\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#options = options ?? {}\n\t\tthis.#engine =\n\t\t\tthis.#options.engine ??\n\t\t\t(this.#options.executable !== undefined\n\t\t\t\t? (parseBrowserEngine(this.#options.executable) ?? 'chromium')\n\t\t\t\t: 'chromium')\n\t\tthis.#cdpPort = this.#options.cdp?.port ?? BROWSER_DEFAULT_CDP_PORT\n\t\tthis.#cdpHost = this.#options.cdp?.host ?? BROWSER_DEFAULT_HOST\n\n\t\tqueueMicrotask(() => this.#emitter.emit('idle'))\n\t}\n\n\tget emitter(): EmitterInterface<BrowserEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget engine(): BrowserEngine {\n\t\treturn this.#engine\n\t}\n\n\tget status(): BrowserStatus {\n\t\treturn this.#status\n\t}\n\n\tget connection(): BrowserConnection | undefined {\n\t\treturn this.#connection\n\t}\n\n\tget owned(): boolean | undefined {\n\t\treturn this.#owned\n\t}\n\n\tget pid(): number | undefined {\n\t\treturn this.#servingPid ?? this.#process?.pid\n\t}\n\n\tasync discover(): Promise<BrowserDiscoveryResult> {\n\t\tconst result = await this.#discoverCDP()\n\t\tthis.#emitter.emit('discover', result)\n\t\treturn result\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\n\t\tconst active = this.#connecting.pending\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\t\tif (this.#status === 'connected') return\n\n\t\tawait this.#connecting.execute(() => this.#establish())\n\t}\n\n\tadopt(): void {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tif (\n\t\t\tthis.#status !== 'connected' ||\n\t\t\tthis.#client === undefined ||\n\t\t\tthis.#endpoint === undefined\n\t\t) {\n\t\t\tthrow new BrowserNotConnectedError()\n\t\t}\n\t\tthis.#owned = true\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.#destroyed) return\n\n\t\tconst disconnecting = this.#disconnecting.pending\n\t\tconst connecting = this.#connecting.pending\n\t\tif (disconnecting !== undefined) await disconnecting\n\t\tif (connecting !== undefined) await connecting.catch(() => undefined)\n\t\tif (this.#destroyed) return\n\t\tif (this.#status !== 'connected' || this.#client === undefined) return\n\n\t\tawait this.#disconnecting.execute(() => this.#detach())\n\t}\n\n\tcontext(index?: number): BrowserContextInterface | undefined {\n\t\tconst i = index ?? 0\n\t\tif (i < 0 || i >= this.#contexts.length) return undefined\n\t\treturn this.#contexts[i]\n\t}\n\n\tcontexts(): readonly BrowserContextInterface[] {\n\t\treturn [...this.#contexts]\n\t}\n\n\tasync isolate(options?: BrowserContextOptions): Promise<BrowserContextInterface> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tconst client = this.#client\n\t\tif (this.#status !== 'connected' || client === undefined) {\n\t\t\tthrow new BrowserNotConnectedError()\n\t\t}\n\t\tvalidateBrowserContextOptions(options)\n\t\tconst params: Record<string, unknown> = { disposeOnDetach: false }\n\t\tif (options?.proxy !== undefined) {\n\t\t\tparams['proxyServer'] = options.proxy.server\n\t\t\tif (options.proxy.bypass !== undefined) {\n\t\t\t\tparams['proxyBypassList'] = options.proxy.bypass.join(',')\n\t\t\t}\n\t\t}\n\t\tif (options?.origins !== undefined) {\n\t\t\tparams['originsWithUniversalNetworkAccess'] = [...options.origins]\n\t\t}\n\t\tconst result = await client.send('Target.createBrowserContext', params)\n\t\tif (!isRecord(result) || !isString(result['browserContextId'])) {\n\t\t\tthrow new BrowserConnectionError('Failed to create isolated browser context')\n\t\t}\n\t\tconst id = result['browserContextId']\n\t\tconst context = new BrowserContext(\n\t\t\tclient,\n\t\t\tid,\n\t\t\toptions?.emulation?.viewport ?? this.#options.viewport,\n\t\t\tcreateBrowserWriter(),\n\t\t\toptions?.emulation,\n\t\t\toptions?.downloads,\n\t\t\toptions,\n\t\t)\n\n\t\ttry {\n\t\t\tif (options?.downloads !== undefined) {\n\t\t\t\tawait client.send('Browser.setDownloadBehavior', {\n\t\t\t\t\tbehavior: options.downloads.named === true ? 'allowAndName' : 'allow',\n\t\t\t\t\tbrowserContextId: id,\n\t\t\t\t\tdownloadPath: options.downloads.path,\n\t\t\t\t\teventsEnabled: true,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait context.close().catch(() => undefined)\n\t\t\tthrow error\n\t\t}\n\n\t\tthis.#registerContext(context)\n\t\treturn context\n\t}\n\n\tasync create(options?: BrowserPageOptions): Promise<BrowserPageInterface> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tconst client = this.#client\n\t\tif (this.#status !== 'connected' || client === undefined) {\n\t\t\tthrow new BrowserNotConnectedError()\n\t\t}\n\n\t\tlet context = this.#contexts[0]\n\t\tif (context === undefined) {\n\t\t\tcontext = new BrowserContext(client, undefined, this.#options.viewport, createBrowserWriter())\n\t\t\tthis.#registerContext(context)\n\t\t}\n\n\t\tconst page = await context.create(options)\n\t\tthis.#emitter.emit('page', page)\n\t\treturn page\n\t}\n\n\tdestroy(): Promise<void> {\n\t\tconst active = this.#shutdown\n\t\tif (active !== undefined) return active\n\t\tif (this.#destroyed) return Promise.resolve()\n\n\t\tthis.#destroyed = true\n\t\tthis.#abort.abort()\n\t\tconst shutdown = this.#destroyResources()\n\t\tthis.#shutdown = shutdown\n\t\treturn shutdown\n\t}\n\n\tclose(): Promise<void> {\n\t\tconst active = this.#shutdown\n\t\tif (active !== undefined) return active\n\t\tif (this.#destroyed) return Promise.resolve()\n\n\t\tthis.#destroyed = true\n\t\tthis.#abort.abort()\n\t\tconst shutdown = this.#closeResources()\n\t\tthis.#shutdown = shutdown\n\t\treturn shutdown\n\t}\n\n\t// === Private helpers\n\n\tasync #establish(): Promise<void> {\n\t\tconst disconnecting = this.#disconnecting.pending\n\t\tif (disconnecting !== undefined) await disconnecting\n\t\tawait this.#settleExit()\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tif (this.#status === 'connected') return\n\n\t\tthis.#assertNotAborted()\n\t\tthis.#status = 'connecting'\n\n\t\ttry {\n\t\t\tif (this.#owned === true && this.#endpoint !== undefined) {\n\t\t\t\tawait this.#connectCDP(this.#endpoint)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst endpoint = this.#options.cdp?.endpoint\n\t\t\tif (endpoint !== undefined) {\n\t\t\t\tawait this.#connectCDP(endpoint)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst discover = this.#options.cdp?.discover ?? true\n\t\t\tif (discover) {\n\t\t\t\tconst discovery = await this.#raceAbort(this.#discoverCDP(this.#signal()))\n\t\t\t\tif (discovery.endpoint !== undefined) {\n\t\t\t\t\tthis.#engine = browserToEngine(discovery.browser)\n\t\t\t\t\tawait this.#connectCDP(discovery.endpoint)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait this.#raceAbort(this.#assertPortFree())\n\t\t\t}\n\n\t\t\tthis.#assertNotAborted()\n\t\t\tawait this.#launch()\n\t\t} catch (error) {\n\t\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\n\t\t\tthis.#status = 'error'\n\t\t\tthis.#emitter.emit('error', error)\n\t\t\tif (isBrowserConnectionError(error)) throw error\n\n\t\t\tconst message = isError(error) ? error.message : String(error)\n\t\t\tthrow new BrowserConnectionError(message, { executable: this.#options.executable })\n\t\t}\n\t}\n\n\tasync #detach(): Promise<void> {\n\t\tthis.#status = 'disconnected'\n\t\tthis.#connection = undefined\n\t\tthis.#unbindTransport()\n\n\t\tconst client = this.#client\n\t\tthis.#client = undefined\n\t\tawait this.#destroyContexts()\n\t\tthis.#contexts = []\n\n\t\tif (this.#owned !== true) {\n\t\t\tthis.#owned = undefined\n\t\t\tthis.#endpoint = undefined\n\t\t}\n\n\t\tawait this.#closeClient(client)\n\t\tif (this.#destroyed) return\n\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t#assertNotAborted(): void {\n\t\tif (this.#signal().aborted) throw new BrowserConnectionError('Connection aborted')\n\t}\n\n\t#signal(): AbortSignal {\n\t\tconst external = this.#options.signal\n\t\treturn external === undefined\n\t\t\t? this.#abort.signal\n\t\t\t: AbortSignal.any([this.#abort.signal, external])\n\t}\n\n\tasync #raceAbort<T>(promise: Promise<T>): Promise<T> {\n\t\tconst signal = this.#signal()\n\t\tif (signal.aborted) throw new BrowserConnectionError('Connection aborted')\n\n\t\tconst aborted = Promise.withResolvers<never>()\n\t\tconst listener = addAbortListener(signal, () => {\n\t\t\taborted.reject(new BrowserConnectionError('Connection aborted'))\n\t\t})\n\n\t\ttry {\n\t\t\treturn await Promise.race([promise, aborted.promise])\n\t\t} finally {\n\t\t\tlistener[Symbol.dispose]()\n\t\t\tvoid promise.catch(() => undefined)\n\t\t}\n\t}\n\n\t#handleProcessExit(): void {\n\t\tif (this.#destroyed) return\n\n\t\tconst connected = this.#status === 'connected'\n\t\tconst client = this.#client\n\t\tconst contexts = this.#contexts\n\t\tconst process = this.#process\n\t\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\t\tthis.#process = undefined\n\t\tthis.#servingPid = undefined\n\t\tconst cleanup = this.#cleanupExitedProcess(process, contexts, client)\n\t\tthis.#exitCleanup = cleanup\n\t\tvoid cleanup.catch((error: unknown) => this.#emitter.emit('error', error))\n\t\tthis.#client = undefined\n\t\tthis.#contexts = []\n\t\tthis.#connection = undefined\n\t\tthis.#owned = undefined\n\t\tthis.#endpoint = undefined\n\t\tif (connected) this.#status = 'disconnected'\n\n\t\tthis.#emitter.emit(\n\t\t\t'error',\n\t\t\tnew BrowserConnectionError('The browser process exited unexpectedly', {\n\t\t\t\tcause: BROWSER_PROCESS_EXIT_CAUSE,\n\t\t\t}),\n\t\t)\n\n\t\tif (connected) {\n\t\t\tthis.#emitter.emit('disconnect')\n\t\t\tthis.#emitter.emit('idle')\n\t\t}\n\t}\n\n\t#handleTransportLoss(): void {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\tif (this.#process === undefined) {\n\t\t\tthis.#confirmTransportLoss()\n\t\t\treturn\n\t\t}\n\n\t\tif (!this.#alive()) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\t// A spawned child that is already dead is diagnosed by its own `exit`\n\t\t// event, never by a probe here: Node sets `exitCode` in the same callback\n\t\t// that emits `exit`, and reports ESRCH from `ChildProcess.kill(0)` as a\n\t\t// `false` return rather than a throw, so no reading of the handle can see\n\t\t// the death before the event does. The defer only has to outlast the loop\n\t\t// turn that delivers it.\n\t\tsetTimeout(() => this.#confirmTransportLoss(), BROWSER_TRANSPORT_LOSS_DEFER_MS)\n\t}\n\n\t#confirmTransportLoss(): void {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\tif (this.#process !== undefined && !this.#alive()) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tconst client = this.#client\n\t\tconst owned = this.#owned === true\n\t\tconst contexts = this.#contexts\n\t\tthis.#unbindTransport()\n\t\tthis.#client = undefined\n\t\tthis.#contexts = []\n\t\tthis.#connection = undefined\n\t\tthis.#status = 'disconnected'\n\n\t\tif (!owned) {\n\t\t\tthis.#owned = undefined\n\t\t\tthis.#endpoint = undefined\n\t\t}\n\n\t\tvoid this.#destroyContextList(contexts)\n\t\tvoid this.#closeClient(client)\n\t\tthis.#emitter.emit(\n\t\t\t'error',\n\t\t\tnew BrowserConnectionError('The CDP transport connection was lost', {\n\t\t\t\tcause: BROWSER_TRANSPORT_LOSS_CAUSE,\n\t\t\t}),\n\t\t)\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t#bindTransport(transport: CDPTransportInterface): void {\n\t\tthis.#unbindTransport()\n\t\tthis.#transport = transport\n\t\ttransport.emitter.on('close', this.#transportCloseHandler)\n\t\ttransport.emitter.on('error', this.#transportErrorHandler)\n\t}\n\n\t#unbindTransport(): void {\n\t\tconst transport = this.#transport\n\t\tif (transport === undefined) return\n\t\ttransport.emitter.off('close', this.#transportCloseHandler)\n\t\ttransport.emitter.off('error', this.#transportErrorHandler)\n\t\tthis.#transport = undefined\n\t}\n\n\t#bindProcess(process: ChildProcess): void {\n\t\tthis.#unbindProcess()\n\t\t// A launcher that handed the endpoint on has already exited, and its exit\n\t\t// says nothing about the browser now serving CDP. That browser has no\n\t\t// child handle, so the transport reports its death.\n\t\tif (this.#servingPid !== undefined) return\n\t\tprocess.once('exit', this.#processExitHandler)\n\t\tif (process.exitCode !== null || process.signalCode !== null) {\n\t\t\tqueueMicrotask(this.#processExitHandler)\n\t\t}\n\t}\n\n\t#unbindProcess(): void {\n\t\tthis.#process?.off('exit', this.#processExitHandler)\n\t}\n\n\t#timeout(): number {\n\t\treturn this.#options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS\n\t}\n\n\tasync #discoverCDP(signal?: AbortSignal): Promise<BrowserDiscoveryResult> {\n\t\tconst url = `${BROWSER_CDP_PROTOCOL}://${this.#cdpHost}:${this.#cdpPort}${BROWSER_CDP_VERSION_PATH}`\n\t\tconst requestSignal =\n\t\t\tsignal === undefined\n\t\t\t\t? AbortSignal.timeout(this.#timeout())\n\t\t\t\t: AbortSignal.any([signal, AbortSignal.timeout(this.#timeout())])\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: requestSignal })\n\t\t\tif (!response.ok) return this.#notFound()\n\n\t\t\tconst info: unknown = await response.json()\n\t\t\tif (!isRecord(info)) return this.#notFound()\n\n\t\t\tconst endpoint = isString(info['webSocketDebuggerUrl'])\n\t\t\t\t? info['webSocketDebuggerUrl']\n\t\t\t\t: undefined\n\t\t\tconst browser = isString(info['Browser']) ? info['Browser'] : undefined\n\n\t\t\treturn { endpoint, browser }\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted === true) throw error\n\t\t\treturn this.#notFound()\n\t\t}\n\t}\n\n\t#notFound(): BrowserDiscoveryResult {\n\t\treturn { endpoint: undefined, browser: undefined }\n\t}\n\n\tasync #assertPortFree(): Promise<void> {\n\t\tif (await this.#probePort()) {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t`Port ${this.#cdpPort} on ${this.#cdpHost} is already occupied by another CDP endpoint`,\n\t\t\t\t{ port: this.#cdpPort, host: this.#cdpHost },\n\t\t\t)\n\t\t}\n\t}\n\n\tasync #probePort(): Promise<boolean> {\n\t\tconst url = `${BROWSER_CDP_PROTOCOL}://${this.#cdpHost}:${this.#cdpPort}${BROWSER_CDP_VERSION_PATH}`\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tsignal: AbortSignal.timeout(BROWSER_PORT_PROBE_TIMEOUT_MS),\n\t\t\t})\n\t\t\treturn response.ok\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tasync #connectCDP(endpoint: string): Promise<void> {\n\t\tconst transport = createCDPTransport({ url: endpoint, timeout: this.#timeout() })\n\t\tconst client = new CDPClient({ transport, timeout: this.#timeout() })\n\t\tconst retained = this.#owned === true && this.#endpoint === endpoint\n\n\t\ttry {\n\t\t\tawait this.#raceAbort(client.connect())\n\n\t\t\tthis.#client = client\n\t\t\tthis.#endpoint = endpoint\n\t\t\tthis.#connection = retained ? this.#retainedConnection() : 'cdp'\n\t\t\tthis.#owned = retained\n\t\t\tthis.#status = 'connected'\n\t\t\tthis.#bindTransport(transport)\n\n\t\t\tawait this.#syncContexts()\n\t\t\tthis.#emitter.emit('connect', this.#connection)\n\t\t} catch (error) {\n\t\t\tthis.#unbindTransport()\n\t\t\tif (this.#client === client) this.#client = undefined\n\t\t\tthis.#contexts = []\n\t\t\tthis.#connection = undefined\n\t\t\tif (!retained) {\n\t\t\t\tthis.#owned = undefined\n\t\t\t\tthis.#endpoint = undefined\n\t\t\t}\n\t\t\tawait this.#closeClient(client)\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tasync #launch(): Promise<void> {\n\t\tif (this.#process !== undefined) {\n\t\t\tthrow new BrowserConnectionError('A browser process is already active on this instance')\n\t\t}\n\n\t\tconst requestedEngine = this.#options.engine ?? this.#options.browsers?.engine\n\t\tlet executable = this.#options.executable\n\t\tlet resolvedEngine: BrowserEngine | undefined\n\n\t\tif (executable !== undefined) {\n\t\t\tresolvedEngine = parseBrowserEngine(executable) ?? 'chromium'\n\t\t} else {\n\t\t\tconst found = findSystemBrowser({\n\t\t\t\t...this.#options.browsers,\n\t\t\t\t...(requestedEngine !== undefined ? { engine: requestedEngine } : {}),\n\t\t\t})\n\t\t\texecutable = found?.executable\n\t\t\tresolvedEngine = found?.engine\n\t\t}\n\n\t\tif (executable === undefined) {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t'No Chromium browser found. Install Chrome, Edge, or Chromium.',\n\t\t\t\trequestedEngine === undefined ? undefined : { engine: requestedEngine },\n\t\t\t)\n\t\t}\n\n\t\tthis.#engine = resolvedEngine ?? 'chromium'\n\t\tawait this.#releaseProfile()\n\t\tconst profile = await createBrowserProfile(this.#options.profile)\n\t\tthis.#profile = profile\n\t\tlet process: ChildProcess\n\t\ttry {\n\t\t\tprocess = launchBrowserProcess(\n\t\t\t\texecutable,\n\t\t\t\tthis.#options.cdp?.port,\n\t\t\t\tthis.#options.headless ?? true,\n\t\t\t\tprofile.path,\n\t\t\t\tthis.#options.args,\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tawait this.#releaseProfile()\n\t\t\tthrow error\n\t\t}\n\t\tthis.#process = process\n\n\t\tlet client: CDPClient | undefined\n\n\t\ttry {\n\t\t\tconst endpoint = await this.#waitForLaunch(process, executable, this.#options.args)\n\t\t\tconst transport = createCDPTransport({ url: endpoint, timeout: this.#timeout() })\n\t\t\tclient = new CDPClient({ transport, timeout: this.#timeout() })\n\t\t\tawait this.#raceAbort(client.connect())\n\t\t\tawait this.#takeEndpointOwner(process, client)\n\n\t\t\tconst connection = this.#options.profile === undefined ? 'launch' : 'persistent'\n\t\t\tthis.#client = client\n\t\t\tthis.#endpoint = endpoint\n\t\t\tthis.#connection = connection\n\t\t\tthis.#owned = true\n\t\t\tthis.#status = 'connected'\n\t\t\tthis.#bindTransport(transport)\n\t\t\tthis.#bindProcess(process)\n\n\t\t\tawait this.#syncContexts()\n\t\t\tthis.#emitter.emit('launch', this.#engine)\n\t\t\tthis.#emitter.emit('connect', connection)\n\t\t} catch (error) {\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\t\t\tawait this.#closeClient(client)\n\t\t\tawait this.#terminate(process)\n\t\t\tawait this.#releaseProfile()\n\t\t\tthis.#process = undefined\n\t\t\tthis.#servingPid = undefined\n\t\t\tthis.#client = undefined\n\t\t\tthis.#endpoint = undefined\n\t\t\tthis.#owned = undefined\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Takes over the process serving the CDP endpoint when the spawned child is\n\t * no longer it.\n\t *\n\t * @remarks\n\t * A Windows launcher — Microsoft Edge — re-executes the browser with the\n\t * same `--remote-debugging-port` and exits 0 before the endpoint answers, so\n\t * the child this instance spawned parents the real tree without being part\n\t * of it. Chromium names the process behind the endpoint as the `browser`\n\t * entry of `SystemInfo.getProcessInfo`, which identifies it without a\n\t * platform branch. An endpoint that names no such process cannot be owned,\n\t * so the launch closes it and fails rather than leaking it.\n\t */\n\tasync #takeEndpointOwner(process: ChildProcess, client: CDPClient): Promise<void> {\n\t\tif (process.exitCode === null && process.signalCode === null) return\n\n\t\tlet result: unknown\n\t\ttry {\n\t\t\tresult = await client.send('SystemInfo.getProcessInfo')\n\t\t} catch {\n\t\t\tresult = undefined\n\t\t}\n\n\t\tlet pid: number | undefined\n\t\tif (isRecord(result) && isArray(result['processInfo'])) {\n\t\t\tfor (const entry of result['processInfo']) {\n\t\t\t\tif (!isRecord(entry) || entry['type'] !== 'browser' || !isInteger(entry['id'])) continue\n\t\t\t\tpid = entry['id']\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (pid === undefined) {\n\t\t\tawait this.#closeRemote(client)\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t'The browser launcher exited without naming the process serving its CDP endpoint',\n\t\t\t\t{ executable: this.#options.executable, pid: process.pid },\n\t\t\t)\n\t\t}\n\n\t\tthis.#servingPid = pid\n\t}\n\n\tasync #waitForLaunch(\n\t\tprocess: ChildProcess,\n\t\texecutable: string,\n\t\targs?: readonly string[],\n\t): Promise<string> {\n\t\tconst context = { executable, args }\n\t\tconst timeout = this.#timeout()\n\t\tconst controller = new AbortController()\n\t\tconst deadline = AbortSignal.timeout(timeout)\n\t\tconst signal = AbortSignal.any([controller.signal, this.#signal(), deadline])\n\t\tconst stderr = process.stderr\n\t\tif (stderr === null) {\n\t\t\tthrow new BrowserConnectionError('The browser process has no standard error to read', context)\n\t\t}\n\t\tconst exit = once(process, 'exit', { signal })\n\t\tvoid exit.catch(() => undefined)\n\t\tconst ready = readBrowserEndpoint(stderr, signal).catch(async (error: unknown) => {\n\t\t\t// A stream that closes without the line ends the launch, and the exit\n\t\t\t// that closed it names the cause: a nonzero exit is the launch-exit\n\t\t\t// fault, while a clean exit leaves the readiness failure standing.\n\t\t\tif (signal.aborted) throw error\n\t\t\tconst values = await exit\n\t\t\tif (values[0] === 0 && values[1] === null) throw error\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\tthis.#formatLaunchExit(\n\t\t\t\t\tisInteger(values[0]) ? values[0] : null,\n\t\t\t\t\tisString(values[1]) ? values[1] : null,\n\t\t\t\t),\n\t\t\t\tcontext,\n\t\t\t)\n\t\t})\n\t\tconst exited = exit.then((values) => {\n\t\t\tconst code = isInteger(values[0]) ? values[0] : null\n\t\t\tconst exitSignal = isString(values[1]) ? values[1] : null\n\t\t\t// A launcher that re-executes the browser exits cleanly and hands the\n\t\t\t// inherited standard error to the process it spawned, so a clean exit\n\t\t\t// ends the child rather than the launch. Keep reading the same pipe on\n\t\t\t// the same readiness budget, which still fails when the line never\n\t\t\t// arrives.\n\t\t\tif (code === 0 && exitSignal === null) return ready\n\t\t\tthrow new BrowserConnectionError(this.#formatLaunchExit(code, exitSignal), context)\n\t\t})\n\n\t\ttry {\n\t\t\treturn await Promise.race([ready, exited])\n\t\t} catch (error) {\n\t\t\tif (isBrowserConnectionError(error)) throw error\n\t\t\tif (this.#signal().aborted) throw new BrowserConnectionError('Connection aborted', context)\n\t\t\tif (deadline.aborted) {\n\t\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t\t`Browser did not report a CDP endpoint within ${timeout}ms`,\n\t\t\t\t\t{ ...context, timeout },\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst message = isError(error) ? error.message : String(error)\n\t\t\tthrow new BrowserConnectionError(message, context)\n\t\t} finally {\n\t\t\tcontroller.abort()\n\t\t\tvoid ready.catch(() => undefined)\n\t\t\tvoid exited.catch(() => undefined)\n\t\t}\n\t}\n\n\t#formatLaunchExit(code: number | null, signal: string | null): string {\n\t\tif (signal !== null) {\n\t\t\treturn `Browser process exited before CDP became ready (signal: ${signal})`\n\t\t}\n\t\tif (code !== null) return `Browser process exited before CDP became ready (code: ${code})`\n\t\treturn 'Browser process exited before CDP became ready'\n\t}\n\n\t#retainedConnection(): BrowserConnection {\n\t\tif (this.#process === undefined) return 'cdp'\n\t\treturn this.#options.profile === undefined ? 'launch' : 'persistent'\n\t}\n\n\tasync #syncContexts(): Promise<void> {\n\t\tconst client = this.#client\n\t\tif (client === undefined) return\n\n\t\tlet result: unknown\n\t\ttry {\n\t\t\tresult = await client.send('Target.getTargets')\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t\tif (!isRecord(result) || !isArray(result['targetInfos'])) return\n\n\t\tconst pages: CDPTarget[] = []\n\t\tfor (const target of result['targetInfos']) {\n\t\t\tif (\n\t\t\t\t!isRecord(target) ||\n\t\t\t\t!isString(target['targetId']) ||\n\t\t\t\ttarget['type'] !== 'page' ||\n\t\t\t\t!isString(target['title']) ||\n\t\t\t\t!isString(target['url'])\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpages.push({\n\t\t\t\tid: target['targetId'],\n\t\t\t\tcategory: target['type'],\n\t\t\t\ttitle: target['title'],\n\t\t\t\turl: target['url'],\n\t\t\t})\n\t\t}\n\t\tif (pages.length === 0 || this.#contexts.length > 0) return\n\n\t\tconst context = new BrowserContext(\n\t\t\tclient,\n\t\t\tundefined,\n\t\t\tthis.#options.viewport,\n\t\t\tcreateBrowserWriter(),\n\t\t)\n\t\tawait context.sync(pages)\n\t\tthis.#registerContext(context)\n\t}\n\n\tasync #destroyResources(): Promise<void> {\n\t\tlet terminated = false\n\t\ttry {\n\t\t\tawait this.#settle()\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\n\t\t\tconst client = this.#client\n\t\t\tif (this.#owned === true) {\n\t\t\t\tawait this.#closeContexts()\n\t\t\t\tif (this.#process === undefined) await this.#closeRemote(client)\n\t\t\t} else {\n\t\t\t\tawait this.#destroyContexts()\n\t\t\t}\n\t\t\tthis.#contexts = []\n\n\t\t\tawait this.#terminate(this.#process)\n\t\t\tthis.#process = undefined\n\t\t\tthis.#servingPid = undefined\n\t\t\tterminated = true\n\t\t} finally {\n\t\t\tconst contexts = this.#contexts\n\t\t\tthis.#contexts = []\n\t\t\tconst client = this.#client\n\t\t\tthis.#client = undefined\n\t\t\ttry {\n\t\t\t\tawait this.#cleanupLocal(contexts, client)\n\t\t\t\tif (terminated) await this.#releaseProfile()\n\t\t\t} finally {\n\t\t\t\tthis.#finish()\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #closeResources(): Promise<void> {\n\t\tlet terminated = false\n\t\ttry {\n\t\t\tawait this.#settle()\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\n\t\t\tconst client = this.#client\n\t\t\tawait this.#closeContexts()\n\t\t\tthis.#contexts = []\n\t\t\tawait this.#closeRemote(client)\n\n\t\t\tconst process = this.#process\n\t\t\tif (process !== undefined) {\n\t\t\t\tconst exited = await this.#waitForTerminationWithin(process, BROWSER_KILL_GRACE_MS)\n\t\t\t\tif (!exited) await this.#terminate(process)\n\t\t\t\tawait this.#closeProcessPipe(process)\n\t\t\t}\n\t\t\tthis.#process = undefined\n\t\t\tthis.#servingPid = undefined\n\t\t\tterminated = true\n\t\t} finally {\n\t\t\tconst contexts = this.#contexts\n\t\t\tthis.#contexts = []\n\t\t\tconst client = this.#client\n\t\t\tthis.#client = undefined\n\t\t\ttry {\n\t\t\t\tawait this.#cleanupLocal(contexts, client)\n\t\t\t\tif (terminated) await this.#releaseProfile()\n\t\t\t} finally {\n\t\t\t\tthis.#finish()\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #settle(): Promise<void> {\n\t\tawait this.#connecting.pending?.catch(() => undefined)\n\t\tawait this.#disconnecting.pending?.catch(() => undefined)\n\t\tawait this.#settleExit()\n\t}\n\n\tasync #settleExit(): Promise<void> {\n\t\tconst cleanup = this.#exitCleanup\n\t\tif (cleanup === undefined) return\n\t\tawait cleanup\n\t\tif (this.#exitCleanup === cleanup) this.#exitCleanup = undefined\n\t}\n\n\tasync #closeRemote(client: CDPClient | undefined): Promise<void> {\n\t\tlet remote = client\n\t\tlet temporary = false\n\n\t\tif (remote === undefined && this.#owned === true && this.#endpoint !== undefined) {\n\t\t\tconst transport = createCDPTransport({\n\t\t\t\turl: this.#endpoint,\n\t\t\t\ttimeout: this.#timeout(),\n\t\t\t})\n\t\t\tremote = new CDPClient({ transport, timeout: this.#timeout() })\n\t\t\ttry {\n\t\t\t\tawait remote.connect()\n\t\t\t\ttemporary = true\n\t\t\t} catch {\n\t\t\t\tawait this.#closeClient(remote)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif (remote !== undefined) {\n\t\t\ttry {\n\t\t\t\tawait remote.send('Browser.close')\n\t\t\t} catch {\n\t\t\t\t// The remote may already be gone or close before acknowledging.\n\t\t\t}\n\t\t}\n\n\t\tif (temporary) await this.#closeClient(remote)\n\t}\n\n\tasync #closeContexts(): Promise<void> {\n\t\tfor (const context of [...this.#contexts]) {\n\t\t\ttry {\n\t\t\t\tawait context.close()\n\t\t\t} catch {\n\t\t\t\t// Teardown is best-effort after the browser begins shutting down.\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #destroyContexts(): Promise<void> {\n\t\tawait this.#destroyContextList([...this.#contexts])\n\t}\n\n\t#registerContext(context: BrowserContext): void {\n\t\tthis.#contexts.push(context)\n\t\tcontext.emitter.on('close', () => {\n\t\t\tconst index = this.#contexts.indexOf(context)\n\t\t\tif (index >= 0) this.#contexts.splice(index, 1)\n\t\t})\n\t\tthis.#emitter.emit('context', context)\n\t}\n\n\tasync #destroyContextList(contexts: readonly BrowserContext[]): Promise<void> {\n\t\tfor (const context of contexts) {\n\t\t\ttry {\n\t\t\t\tawait context.destroy()\n\t\t\t} catch {\n\t\t\t\t// The transport may already be unavailable.\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #closeClient(client: CDPClient | undefined): Promise<void> {\n\t\tif (client === undefined) return\n\t\ttry {\n\t\t\tawait client.close()\n\t\t} catch {\n\t\t\t// Teardown is best-effort after a connection fault.\n\t\t}\n\t}\n\n\tasync #releaseProfile(): Promise<void> {\n\t\tconst profile = this.#profile\n\t\tthis.#profile = undefined\n\t\tif (profile !== undefined) await removeBrowserProfile(profile)\n\t}\n\n\tasync #cleanupExitedProcess(\n\t\tprocess: ChildProcess | undefined,\n\t\tcontexts: readonly BrowserContext[],\n\t\tclient: CDPClient | undefined,\n\t): Promise<void> {\n\t\tlet terminated = false\n\t\ttry {\n\t\t\tawait this.#terminate(process)\n\t\t\tterminated = true\n\t\t} finally {\n\t\t\tawait this.#cleanupLocal(contexts, client)\n\t\t}\n\t\tif (terminated) await this.#releaseProfile()\n\t}\n\n\tasync #cleanupLocal(\n\t\tcontexts: readonly BrowserContext[],\n\t\tclient: CDPClient | undefined,\n\t): Promise<void> {\n\t\tawait this.#destroyContextList(contexts)\n\t\tawait this.#closeClient(client)\n\t}\n\n\tasync #waitForProcessWithin(process: ChildProcess, timeout: number): Promise<boolean> {\n\t\tif (process.exitCode !== null || process.signalCode !== null) return true\n\n\t\tconst signal = AbortSignal.timeout(timeout)\n\t\ttry {\n\t\t\tawait once(process, 'exit', { signal })\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tif (signal.aborted) {\n\t\t\t\treturn process.exitCode !== null || process.signalCode !== null\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t#hasProcessGroup(process: ChildProcess): boolean {\n\t\tconst pid = process.pid\n\t\treturn globalThis.process.platform !== 'win32' && pid !== undefined && pid > 0\n\t}\n\n\t// Whether the process serving the CDP endpoint is still running. The spawned\n\t// child reports through its own handle; a process the launcher handed the\n\t// endpoint to has none, so it is probed by identifier.\n\t#alive(): boolean {\n\t\tconst process = this.#process\n\t\tif (process === undefined) return false\n\t\tif (this.#servingPid !== undefined) return this.#signalProcess(process, 0) !== false\n\t\treturn process.exitCode === null && process.signalCode === null\n\t}\n\n\t// Whether the launch retains a process the reaped child does not account\n\t// for: the POSIX process group, or the process the launcher handed the\n\t// endpoint to.\n\t#inspectRemainder(process: ChildProcess): boolean | undefined {\n\t\tif (!this.#hasProcessGroup(process) && this.#servingPid === undefined) return false\n\t\treturn this.#signalProcess(process, 0)\n\t}\n\n\t#signalProcess(process: ChildProcess, signal: NodeJS.Signals | 0): boolean | undefined {\n\t\tconst pid = process.pid\n\t\tconst serving = this.#servingPid\n\t\ttry {\n\t\t\tif (this.#hasProcessGroup(process) && pid !== undefined) {\n\t\t\t\treturn globalThis.process.kill(-pid, signal)\n\t\t\t}\n\t\t\t// Terminating the Chromium browser process takes its whole tree with\n\t\t\t// it, so Windows needs no separate tree walk to reach the renderers,\n\t\t\t// GPU, and utility children the serving process parents.\n\t\t\tif (serving !== undefined) return globalThis.process.kill(serving, signal)\n\t\t\treturn process.kill(signal)\n\t\t} catch (error) {\n\t\t\tconst code =\n\t\t\t\tisError(error) && 'code' in error && isString(error.code) ? error.code : undefined\n\t\t\tif (code === 'ESRCH') return false\n\t\t\tif (signal === 0) return code === 'EPERM' ? true : undefined\n\t\t\tthrow new BrowserConnectionError('Failed to signal the browser process', {\n\t\t\t\tpid: serving ?? pid,\n\t\t\t\tsignal,\n\t\t\t\tcause: error,\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Waits within a bound for the rest of a terminated process group, or the process a\n\t * launcher handed the endpoint to, to disappear.\n\t *\n\t * @remarks\n\t * This is the one interval loop in the server. Node raises an exit event for the direct\n\t * child only, so no event source reports the remainder of a POSIX process group or a\n\t * handed-off process, and the drain probes on `BROWSER_DRAIN_INTERVAL_MS` until the\n\t * remainder is gone or `timeout` elapses.\n\t */\n\tasync #waitForRemainderWithin(\n\t\tprocess: ChildProcess,\n\t\ttimeout: number,\n\t): Promise<boolean | undefined> {\n\t\tconst deadline = performance.now() + timeout\n\t\tlet confirmed = false\n\t\twhile (true) {\n\t\t\tconst alive = this.#inspectRemainder(process)\n\t\t\tif (alive === false) return true\n\t\t\tif (alive === true) confirmed = true\n\t\t\tconst remaining = deadline - performance.now()\n\t\t\tif (remaining <= 0) return confirmed ? false : undefined\n\t\t\tawait new Promise<void>((resolve) =>\n\t\t\t\tsetTimeout(resolve, Math.min(BROWSER_DRAIN_INTERVAL_MS, remaining)),\n\t\t\t)\n\t\t}\n\t}\n\n\tasync #waitForTerminationWithin(\n\t\tprocess: ChildProcess,\n\t\ttimeout: number,\n\t\tfinal = false,\n\t): Promise<boolean> {\n\t\tconst exited = this.#waitForProcessWithin(process, timeout)\n\t\tconst drained = this.#waitForRemainderWithin(process, timeout)\n\t\tconst results = await Promise.all([exited, drained])\n\t\treturn results[0] && (results[1] === true || (final && results[1] === undefined))\n\t}\n\n\tasync #terminate(process: ChildProcess | undefined): Promise<void> {\n\t\ttry {\n\t\t\tif (\n\t\t\t\tprocess === undefined ||\n\t\t\t\t((process.exitCode !== null || process.signalCode !== null) &&\n\t\t\t\t\tthis.#inspectRemainder(process) === false)\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (this.#signalProcess(process, 'SIGTERM') === false) return\n\t\t\tif (await this.#waitForTerminationWithin(process, BROWSER_KILL_GRACE_MS)) return\n\n\t\t\tif (this.#signalProcess(process, 'SIGKILL') === false) return\n\t\t\tif (await this.#waitForTerminationWithin(process, BROWSER_KILL_GRACE_MS, true)) return\n\n\t\t\tthrow new BrowserConnectionError('Browser process did not exit after SIGKILL', {\n\t\t\t\tpid: this.#servingPid ?? process.pid,\n\t\t\t})\n\t\t} finally {\n\t\t\tawait this.#closeProcessPipe(process)\n\t\t}\n\t}\n\n\tasync #closeProcessPipe(process: ChildProcess | undefined): Promise<void> {\n\t\tconst stream = process?.stderr\n\t\tif (stream === undefined || stream === null || stream.closed) return\n\t\t// A descendant can inherit the writer after the browser exits, especially on Windows.\n\t\t// Release our read end explicitly and await its close before teardown settles.\n\t\tconst closed = once(stream, 'close')\n\t\tstream.destroy()\n\t\tawait closed\n\t}\n\n\t#finish(): void {\n\t\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\t\tthis.#status = 'disconnected'\n\t\tthis.#connection = undefined\n\t\tthis.#owned = undefined\n\t\tthis.#endpoint = undefined\n\t\tthis.#client = undefined\n\t\tthis.#process = undefined\n\t\tthis.#servingPid = undefined\n\t\tthis.#exitCleanup = undefined\n\t\tthis.#contexts = []\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#emitter.destroy()\n\t}\n}\n"],"mappings":"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"}
|