@orkestrel/browser 0.0.6 → 0.0.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#emitter","#url","#timeout","#closeResolve","#closing","#socket","#starting","#open","#stop","#request","#resolve","#reject","#timer","#expire","#upgrade","#decline","#fail","#bind","#rejectRequest","#onSocketClose","#resolveRequest","#clearRequest","#emitter","#options","#abort","#cdpPort","#cdpHost","#handleTransportLoss","#handleProcessExit","#engine","#status","#connection","#owned","#process","#discoverCDP","#destroyed","#disconnecting","#connecting","#establish","#client","#endpoint","#detach","#contexts","#registerContext","#shutdown","#destroyResources","#closeResources","#assertNotAborted","#connectCDP","#raceAbort","#signal","#assertPortFree","#launch","#unbindTransport","#destroyContexts","#closeClient","#unbindProcess","#releaseProfile","#destroyContextList","#confirmTransportLoss","#transport","#onTransportClose","#onTransportError","#onProcessExit","#timeout","#notFound","#probePort","#retainedConnection","#bindTransport","#syncContexts","#profile","#waitForLaunch","#bindProcess","#terminate","#formatLaunchExit","#settle","#closeContexts","#closeRemote","#finish","#waitForProcessWithin","#waitForProcess"],"sources":["../../../src/server/constants.ts","../../../src/server/errors.ts","../../../src/server/helpers.ts","../../../src/server/transports/WebSocketCDPTransport.ts","../../../src/server/factories.ts","../../../src/server/Browser.ts"],"sourcesContent":["import type { BrowserEngine } from './types.js'\n\n// === CDP discovery\n\n/** Default CDP port probed for an existing browser and used for launches. */\nexport const BROWSER_DEFAULT_CDP_PORT = 9222\n\n/** Default host probed for an existing browser and used for launches (avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`). */\nexport const BROWSER_DEFAULT_HOST = '127.0.0.1'\n\n/** Protocol prefix for CDP discovery requests. */\nexport const BROWSER_CDP_PROTOCOL = 'http'\n\n/** Path appended to the CDP host to fetch version metadata (endpoint discovery). */\nexport const BROWSER_CDP_VERSION_PATH = '/json/version'\n\n/** Path appended to the CDP host to list open targets (pages, workers, etc). */\nexport const BROWSER_CDP_LIST_PATH = '/json/list'\n\n// === Browser launch\n\n/** 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/** Flag enabling headless mode on a launched browser process. */\nexport const BROWSER_HEADLESS_ARG = '--headless=new'\n\n/** Prefix for isolated browser profiles created beneath the operating-system temp directory. */\nexport const BROWSER_PROFILE_PREFIX = 'orkestrel-browser-'\n\n/** Grace period after SIGTERM before a launched process is escalated to SIGKILL during teardown. */\nexport const BROWSER_KILL_GRACE_MS = 3_000\n\n/** Bound for the `discover: false` port-occupancy probe before launching — short, since it only needs to detect an already-listening CDP endpoint, not perform full discovery. */\nexport const BROWSER_PORT_PROBE_TIMEOUT_MS = 200\n\n/** Brief defer applied once when a transport loss is observed on an owned process, giving a near-simultaneous process-exit event (which libuv may reap slightly later than the socket close) first say over the diagnosis. */\nexport const BROWSER_TRANSPORT_LOSS_DEFER_MS = 50\n\n/** Machine-readable error-context cause for an owned browser process exiting. */\nexport const BROWSER_PROCESS_EXIT_CAUSE = 'process-exit'\n\n/** Machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */\nexport const BROWSER_TRANSPORT_LOSS_CAUSE = 'transport-loss'\n\n/** Environment variables checked (in order) for an explicit browser executable path override. */\nexport const BROWSER_ENV_PATH_KEYS: readonly string[] = Object.freeze([\n\t'PLAYWRIGHT_EXECUTABLE_PATH',\n\t'CHROME_PATH',\n])\n\n/** Well-known Chrome/Chromium/Edge executable paths with no platform-specific root, keyed by `process.platform`. */\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/** 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/** Fallback Windows install roots used when the corresponding environment variable is absent. */\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/** 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/** Environment variable naming an additional Playwright browser store base directory. */\nexport const BROWSER_STORE_ENV_KEY = 'PLAYWRIGHT_BROWSERS_PATH'\n\n/** Well-known Playwright browser store base directories checked in addition to `PLAYWRIGHT_BROWSERS_PATH`. */\nexport const BROWSER_STORE_DEFAULT_DIRS: readonly string[] = Object.freeze(['/opt/pw-browsers'])\n\n/** 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/** Name of the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */\nexport const BROWSER_STORE_LINK_NAME = 'chromium'\n\n/**\n * 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/** 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","import { BrowserError } from '@src/core'\nimport { isInstance } from '@orkestrel/contract'\n\n// === Server browser errors\n\n/**\n * A CDP connection, discovery, or launch attempt failed.\n */\nexport class BrowserConnectionError extends BrowserError {\n\tconstructor(message: string, context?: Readonly<Record<string, unknown>>) {\n\t\tsuper(message, 'BROWSER_CONNECTION_ERROR', context)\n\t\tthis.name = 'BrowserConnectionError'\n\t}\n}\n\n/**\n * An operation requiring an active connection was attempted while disconnected.\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 * An operation was attempted after the Browser was destroyed.\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 * Narrow an unknown value to BrowserConnectionError.\n *\n * @param value - Value to check\n * @returns True when value is a BrowserConnectionError instance\n */\nexport function isBrowserConnectionError(value: unknown): value is BrowserConnectionError {\n\treturn isInstance(value, BrowserConnectionError)\n}\n\n/**\n * Narrow an unknown value to BrowserNotConnectedError.\n *\n * @param value - Value to check\n * @returns True when value is a BrowserNotConnectedError instance\n */\nexport function isBrowserNotConnectedError(value: unknown): value is BrowserNotConnectedError {\n\treturn isInstance(value, BrowserNotConnectedError)\n}\n\n/**\n * Narrow an unknown value to BrowserDestroyedError.\n *\n * @param value - Value to check\n * @returns True when value is a BrowserDestroyedError instance\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 { CDPTarget } from '@src/core'\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 { setTimeout as waitForTimeout } from 'node:timers/promises'\nimport { isArray, isRecord, isString } from '@orkestrel/contract'\nimport { BROWSER_WAIT_POLL_INTERVAL_MS } from '@src/core'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_CDP_LIST_PATH,\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// === Discovery helpers\n\n/**\n * Enumerate 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} via\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(...findAllEnvOverrides(env))\n\n\tconst paths = options?.paths ?? defaultInstallPaths(platform, env)\n\tcandidates.push(...findAllInstallPaths(paths))\n\n\tconst names = options?.names ?? BROWSER_EXECUTABLE_NAMES\n\tcandidates.push(...probeAllPathNames(names, platform))\n\n\tconst stores = options?.stores ?? defaultStoreBases(env, platform)\n\tfor (const store of stores) {\n\t\tcandidates.push(...findAllInStore(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 * Locate 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 * Classify 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/** Normalize 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/** Classify 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 * Resolve a persistent caller profile or create 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 * Remove 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 Error('Refusing to remove an unsafe browser profile path')\n\t}\n\tawait rm(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })\n}\n\n/** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order for an existing file. */\nexport function findEnvOverride(\n\tenv: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n\treturn findAllEnvOverrides(env)[0]\n}\n\n/** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order, returning every one that exists. */\nexport function findAllEnvOverrides(\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/** Build the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */\nexport function defaultInstallPaths(\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 = windowsRoots(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/** Derive Windows install roots from env vars, falling back to well-known literals when absent. */\nexport function windowsRoots(env: Readonly<Record<string, string | undefined>>): 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/** Return the first candidate path that exists on disk. */\nexport function findInstallPath(paths: readonly string[]): string | undefined {\n\treturn findAllInstallPaths(paths)[0]\n}\n\n/** Return every candidate path that exists on disk, in the given order. */\nexport function findAllInstallPaths(paths: readonly string[]): readonly string[] {\n\treturn paths.filter((path) => existsSync(path))\n}\n\n/** Probe PATH (`which`/`where`) for the first resolvable command name. */\nexport function probePathNames(names: readonly string[], platform: string): string | undefined {\n\treturn probeAllPathNames(names, platform)[0]\n}\n\n/** Probe PATH (`which`/`where`) for every resolvable command name, in the given order. */\nexport function probeAllPathNames(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 output = result.stdout.toString('utf-8').trim().split('\\n')[0]\n\t\t\tif (output !== undefined && output.length > 0) found.push(output)\n\t\t}\n\t}\n\treturn found\n}\n\n/** Build the default Playwright browser store base directories to search for a managed Chromium. */\nexport function defaultStoreBases(\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/** Search one store base for the top-level `chromium` link, else the highest-revision `chromium-*` install. */\nexport function findInStore(base: string, platform: string): string | undefined {\n\treturn findAllInStore(base, platform)[0]\n}\n\n/** Search one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */\nexport function findAllInStore(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 * Launch a browser process with raw-CDP debugging flags.\n *\n * @param executable - Absolute path to the browser executable\n * @param port - Port the browser exposes its CDP endpoint on\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\n */\nexport function launchBrowserProcess(\n\texecutable: string,\n\tport: number,\n\theadless: boolean,\n\tprofile?: string,\n\textra?: readonly string[],\n): ChildProcess {\n\t// Caller-supplied args come FIRST so a script path (e.g. `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 below —\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}`, ...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, { stdio: 'ignore' })\n}\n\n/**\n * Poll a browser's CDP version endpoint until it responds or the timeout elapses.\n *\n * @param port - Port the browser exposes its CDP endpoint on\n * @param timeout - Maximum time to wait in milliseconds\n * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)\n * @returns The browser's WebSocket debugger URL\n *\n * @throws When the endpoint does not become ready before the timeout\n */\nexport async function waitForCDPReady(\n\tport: number,\n\ttimeout: number,\n\thost: string = BROWSER_DEFAULT_HOST,\n\tsignal?: AbortSignal,\n): Promise<string> {\n\tconst url = `${BROWSER_CDP_PROTOCOL}://${host}:${port}${BROWSER_CDP_VERSION_PATH}`\n\tconst deadline = Date.now() + timeout\n\n\twhile (Date.now() < deadline) {\n\t\tsignal?.throwIfAborted()\n\t\tconst remaining = Math.max(0, deadline - Date.now())\n\t\tconst requestSignal =\n\t\t\tsignal === undefined\n\t\t\t\t? AbortSignal.timeout(remaining)\n\t\t\t\t: AbortSignal.any([signal, AbortSignal.timeout(remaining)])\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: requestSignal })\n\t\t\tif (response.ok) {\n\t\t\t\tconst info: unknown = await response.json()\n\t\t\t\tif (isRecord(info) && isString(info['webSocketDebuggerUrl'])) {\n\t\t\t\t\treturn info['webSocketDebuggerUrl']\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted === true) throw error\n\t\t\t// Not ready yet — keep polling\n\t\t}\n\n\t\tconst delay = Math.min(BROWSER_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()))\n\t\tif (delay > 0) await waitForTimeout(delay, undefined, { signal })\n\t}\n\n\tthrow new Error(`CDP endpoint on port ${port} did not become ready within ${timeout}ms`)\n}\n\n/**\n * Fetch the current CDP target list from a browser's `/json/list` endpoint.\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 Normalized CDP targets\n */\nexport async function fetchCDPTargets(\n\tport: number,\n\ttimeout: number,\n\thost: string = BROWSER_DEFAULT_HOST,\n): Promise<readonly CDPTarget[]> {\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) return []\n\n\t\tconst list: unknown = await response.json()\n\t\tif (!isArray(list)) return []\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\ttype: 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 targets\n\t} catch {\n\t\treturn []\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 } from '@src/core'\nimport { BrowserConnectionError } from '../errors.js'\n\n// === WebSocketCDPTransport\n\n/**\n * `@orkestrel/websocket`-backed raw CDP text transport.\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 */\nexport class WebSocketCDPTransport implements CDPTransportInterface {\n\treadonly #emitter: Emitter<CDPTransportEventMap>\n\treadonly #url: string\n\treadonly #timeout: number\n\t#socket: NodeWebSocketInterface | undefined\n\t#starting: Promise<void> | undefined\n\t#closing: Promise<void> | undefined\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\t#onSocketClose = (): void => this.#closeResolve?.()\n\n\tconstructor(options: WebSocketCDPTransportOptions) {\n\t\tthis.#emitter = new Emitter({ on: options.on, error: options.error })\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\tif (this.#closing !== undefined) await this.#closing\n\t\tif (this.#socket?.readyState === WEBSOCKET_READY_OPEN) return\n\n\t\tconst active = this.#starting\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\tconst transition = this.#open()\n\t\tthis.#starting = transition\n\n\t\ttry {\n\t\t\tawait transition\n\t\t} finally {\n\t\t\tif (this.#starting === transition) this.#starting = undefined\n\t\t}\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 Error('WebSocket CDP transport is not open')\n\t\t}\n\t\tsocket.send(data)\n\t}\n\n\tasync close(): Promise<void> {\n\t\tconst active = this.#closing\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\n\t\tconst transition = this.#stop()\n\t\tthis.#closing = transition\n\t\ttry {\n\t\t\tawait transition\n\t\t} finally {\n\t\t\tif (this.#closing === transition) this.#closing = undefined\n\t\t}\n\t}\n\n\t// === Private helpers\n\n\tasync #open(): 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 #stop(): 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?.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.#onSocketClose)\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.#onSocketClose)\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","import type { CDPTransportInterface, ScreenshotWriterInterface } from '@src/core'\nimport type { BrowserInterface, BrowserOptions, WebSocketCDPTransportOptions } from './types.js'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { Browser } from './Browser.js'\nimport { WebSocketCDPTransport } from './transports/WebSocketCDPTransport.js'\n\n/**\n * Create a raw-CDP Browser façade.\n *\n * @param options - Connection, launch, and viewport configuration\n * @returns A {@link BrowserInterface}\n *\n * @example\n * ```ts\n * import { createBrowser } from '@src/server'\n *\n * const browser = createBrowser()\n * await browser.connect()\n * ```\n */\nexport function createBrowser(options?: BrowserOptions): BrowserInterface {\n\treturn new Browser(options)\n}\n\n/**\n * Create a Node `WebSocket`-backed CDP transport.\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 * Create a filesystem-backed screenshot writer.\n *\n * @returns A {@link ScreenshotWriterInterface} that persists bytes via `node:fs/promises`\n */\nexport function createScreenshotWriter(): ScreenshotWriterInterface {\n\treturn {\n\t\tasync write(path: string, data: Uint8Array): Promise<void> {\n\t\t\tawait mkdir(dirname(path), { recursive: true })\n\t\t\tawait writeFile(path, data)\n\t\t},\n\t}\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\tBrowserContext,\n\tBROWSER_DEFAULT_TIMEOUT_MS,\n\tCDPClient,\n\tvalidateBrowserContextOptions,\n} from '@src/core'\nimport {\n\tBrowserConnectionError,\n\tBrowserDestroyedError,\n\tBrowserNotConnectedError,\n\tisBrowserConnectionError,\n} from './errors.js'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_DEFAULT_CDP_PORT,\n\tBROWSER_DEFAULT_HOST,\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\tremoveBrowserProfile,\n\twaitForCDPReady,\n} from './helpers.js'\nimport { createCDPTransport, createScreenshotWriter } from './factories.js'\n\n// === Browser\n\n/**\n * Discovers, launches, connects to, and owns Chromium-family browser sessions.\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#profile: BrowserProfileResult | undefined\n\t#contexts: BrowserContext[] = []\n\t#destroyed = false\n\t#connecting: Promise<void> | undefined\n\t#disconnecting: Promise<void> | undefined\n\t#shutdown: Promise<void> | undefined\n\t#transport: CDPTransportInterface | undefined\n\t#onTransportClose = (): void => this.#handleTransportLoss()\n\t#onTransportError = (): void => this.#handleTransportLoss()\n\t#onProcessExit = (): void => this.#handleProcessExit()\n\n\tconstructor(options?: BrowserOptions) {\n\t\tthis.#emitter = new Emitter({ on: options?.on, error: options?.error })\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 connected(): boolean {\n\t\treturn this.#status === 'connected'\n\t}\n\n\tget pid(): number | undefined {\n\t\treturn 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\t\tif (this.#disconnecting !== undefined) await this.#disconnecting\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tif (this.#status === 'connected') return\n\n\t\tconst active = this.#connecting\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\n\t\tconst attempt = this.#establish()\n\t\tthis.#connecting = attempt\n\n\t\ttry {\n\t\t\tawait attempt\n\t\t} finally {\n\t\t\tif (this.#connecting === attempt) this.#connecting = undefined\n\t\t}\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 active = this.#disconnecting\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\t\tif (this.#connecting !== undefined) {\n\t\t\tawait this.#connecting.catch(() => undefined)\n\t\t\tif (this.#destroyed) return\n\t\t}\n\t\tif (this.#status !== 'connected' || this.#client === undefined) return\n\n\t\tconst attempt = this.#detach()\n\t\tthis.#disconnecting = attempt\n\n\t\ttry {\n\t\t\tawait attempt\n\t\t} finally {\n\t\t\tif (this.#disconnecting === attempt) this.#disconnecting = undefined\n\t\t}\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\tcreateScreenshotWriter(),\n\t\t\toptions?.emulation,\n\t\t\toptions?.downloads,\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(\n\t\t\t\tclient,\n\t\t\t\tundefined,\n\t\t\t\tthis.#options.viewport,\n\t\t\t\tcreateScreenshotWriter(),\n\t\t\t)\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\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.found && 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\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\t\tthis.#process = undefined\n\t\tvoid this.#releaseProfile().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\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 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\tconst process = this.#process\n\t\tif (process !== undefined && (process.exitCode !== null || process.signalCode !== null)) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tif (process !== undefined) {\n\t\t\tsetTimeout(() => this.#confirmTransportLoss(), BROWSER_TRANSPORT_LOSS_DEFER_MS)\n\t\t\treturn\n\t\t}\n\n\t\tthis.#confirmTransportLoss()\n\t}\n\n\t#confirmTransportLoss(): void {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\tconst process = this.#process\n\t\tif (process !== undefined && (process.exitCode !== null || process.signalCode !== null)) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tif (process?.pid !== undefined) {\n\t\t\ttry {\n\t\t\t\tprocess.kill(0)\n\t\t\t} catch {\n\t\t\t\tthis.#handleProcessExit()\n\t\t\t\treturn\n\t\t\t}\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.#onTransportClose)\n\t\ttransport.emitter.on('error', this.#onTransportError)\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.#onTransportClose)\n\t\ttransport.emitter.off('error', this.#onTransportError)\n\t\tthis.#transport = undefined\n\t}\n\n\t#bindProcess(process: ChildProcess): void {\n\t\tthis.#unbindProcess()\n\t\tprocess.once('exit', this.#onProcessExit)\n\t\tif (process.exitCode !== null || process.signalCode !== null) {\n\t\t\tqueueMicrotask(this.#onProcessExit)\n\t\t}\n\t}\n\n\t#unbindProcess(): void {\n\t\tthis.#process?.off('exit', this.#onProcessExit)\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 {\n\t\t\t\tfound: endpoint !== undefined,\n\t\t\t\tendpoint,\n\t\t\t\tbrowser,\n\t\t\t\tconnection: endpoint !== undefined ? 'cdp' : undefined,\n\t\t\t}\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 { found: false, endpoint: undefined, browser: undefined, connection: 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({ ...this.#options.browsers, engine: requestedEngine })\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.#cdpPort,\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\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.#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\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 controller = new AbortController()\n\t\tconst signal = AbortSignal.any([controller.signal, this.#signal()])\n\t\tconst ready = waitForCDPReady(this.#cdpPort, this.#timeout(), this.#cdpHost, signal)\n\t\tconst exited = once(process, 'exit', { signal }).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\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\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\ttype: 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\tcreateScreenshotWriter(),\n\t\t)\n\t\tawait context.sync(pages)\n\t\tthis.#registerContext(context)\n\t}\n\n\tasync #destroyResources(): Promise<void> {\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\tawait this.#closeClient(client)\n\t\t\tthis.#client = undefined\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait 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\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.#waitForProcessWithin(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\n\t\t\tawait this.#closeClient(client)\n\t\t\tthis.#client = undefined\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait 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?.catch(() => undefined)\n\t\tawait this.#disconnecting?.catch(() => 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 #waitForProcess(process: ChildProcess): Promise<void> {\n\t\tif (process.exitCode !== null || process.signalCode !== null) return\n\t\tawait once(process, 'exit')\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\tasync #terminate(process: ChildProcess | undefined): Promise<void> {\n\t\tif (process === undefined || process.exitCode !== null || process.signalCode !== null) return\n\n\t\ttry {\n\t\t\tprocess.kill('SIGTERM')\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\n\t\tif (await this.#waitForProcessWithin(process, BROWSER_KILL_GRACE_MS)) return\n\n\t\ttry {\n\t\t\tprocess.kill('SIGKILL')\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t\tawait this.#waitForProcess(process)\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.#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.js","names":["#emitter","#url","#timeout","#onSocketClose","#handleSocketClose","#closing","#socket","#starting","#open","#stop","#request","#resolve","#reject","#timer","#expire","#upgrade","#decline","#fail","#bind","#rejectRequest","#closeResolve","#resolveRequest","#clearRequest","#emitter","#options","#abort","#cdpPort","#cdpHost","#onTransportClose","#handleTransportLoss","#onTransportError","#onProcessExit","#handleProcessExit","#engine","#status","#connection","#owned","#process","#discoverCDP","#destroyed","#connecting","#establish","#client","#endpoint","#disconnecting","#detach","#contexts","#registerContext","#shutdown","#destroyResources","#closeResources","#settleExit","#assertNotAborted","#connectCDP","#raceAbort","#signal","#assertPortFree","#launch","#unbindTransport","#destroyContexts","#closeClient","#unbindProcess","#cleanupExitedProcess","#exitCleanup","#confirmTransportLoss","#destroyContextList","#transport","#timeout","#notFound","#probePort","#retainedConnection","#bindTransport","#syncContexts","#releaseProfile","#profile","#waitForLaunch","#bindProcess","#terminate","#formatLaunchExit","#settle","#closeContexts","#closeRemote","#cleanupLocal","#finish","#waitForTerminationWithin","#waitForProcessWithin","#hasProcessGroup","#signalProcess","#waitForProcessGroupWithin","#inspectProcessGroup"],"sources":["../../../src/server/constants.ts","../../../src/server/errors.ts","../../../src/server/helpers.ts","../../../src/server/transports/WebSocketCDPTransport.ts","../../../src/server/factories.ts","../../../src/server/Browser.ts"],"sourcesContent":["import type { BrowserEngine } from './types.js'\n\n// === CDP discovery\n\n/** Default CDP port probed for an existing browser and used for launches. */\nexport const BROWSER_DEFAULT_CDP_PORT = 9222\n\n/** Default host probed for an existing browser and used for launches (avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`). */\nexport const BROWSER_DEFAULT_HOST = '127.0.0.1'\n\n/** Protocol prefix for CDP discovery requests. */\nexport const BROWSER_CDP_PROTOCOL = 'http'\n\n/** Path appended to the CDP host to fetch version metadata (endpoint discovery). */\nexport const BROWSER_CDP_VERSION_PATH = '/json/version'\n\n/** Path appended to the CDP host to list open targets (pages, workers, etc). */\nexport const BROWSER_CDP_LIST_PATH = '/json/list'\n\n// === Browser launch\n\n/** 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/** Flag enabling headless mode on a launched browser process. */\nexport const BROWSER_HEADLESS_ARG = '--headless=new'\n\n/** Prefix for isolated browser profiles created beneath the operating-system temp directory. */\nexport const BROWSER_PROFILE_PREFIX = 'orkestrel-browser-'\n\n/** Bound for each launched-process exit window during TERM-to-KILL teardown. */\nexport const BROWSER_KILL_GRACE_MS = 3_000\n\n/** Bound for the `discover: false` port-occupancy probe before launching — short, since it only needs to detect an already-listening CDP endpoint, not perform full discovery. */\nexport const BROWSER_PORT_PROBE_TIMEOUT_MS = 200\n\n/** Brief defer applied once when a transport loss is observed on an owned process, giving a near-simultaneous process-exit event (which libuv may reap slightly later than the socket close) first say over the diagnosis. */\nexport const BROWSER_TRANSPORT_LOSS_DEFER_MS = 50\n\n/** Machine-readable error-context cause for an owned browser process exiting. */\nexport const BROWSER_PROCESS_EXIT_CAUSE = 'process-exit'\n\n/** Machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */\nexport const BROWSER_TRANSPORT_LOSS_CAUSE = 'transport-loss'\n\n/** Environment variables checked (in order) for an explicit browser executable path override. */\nexport const BROWSER_ENV_PATH_KEYS: readonly string[] = Object.freeze([\n\t'PLAYWRIGHT_EXECUTABLE_PATH',\n\t'CHROME_PATH',\n])\n\n/** Well-known Chrome/Chromium/Edge executable paths with no platform-specific root, keyed by `process.platform`. */\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/** 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/** Fallback Windows install roots used when the corresponding environment variable is absent. */\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/** 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/** Environment variable naming an additional Playwright browser store base directory. */\nexport const BROWSER_STORE_ENV_KEY = 'PLAYWRIGHT_BROWSERS_PATH'\n\n/** Well-known Playwright browser store base directories checked in addition to `PLAYWRIGHT_BROWSERS_PATH`. */\nexport const BROWSER_STORE_DEFAULT_DIRS: readonly string[] = Object.freeze(['/opt/pw-browsers'])\n\n/** 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/** Name of the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */\nexport const BROWSER_STORE_LINK_NAME = 'chromium'\n\n/**\n * 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/** 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","import { BrowserError } from '@src/core'\nimport { isInstance } from '@orkestrel/contract'\n\n// === Server browser errors\n\n/**\n * A CDP connection, discovery, or launch attempt failed.\n */\nexport class BrowserConnectionError extends BrowserError {\n\tconstructor(message: string, context?: Readonly<Record<string, unknown>>) {\n\t\tsuper(message, 'BROWSER_CONNECTION_ERROR', context)\n\t\tthis.name = 'BrowserConnectionError'\n\t}\n}\n\n/**\n * An operation requiring an active connection was attempted while disconnected.\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 * An operation was attempted after the Browser was destroyed.\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 * Narrow an unknown value to BrowserConnectionError.\n *\n * @param value - Value to check\n * @returns True when value is a BrowserConnectionError instance\n */\nexport function isBrowserConnectionError(value: unknown): value is BrowserConnectionError {\n\treturn isInstance(value, BrowserConnectionError)\n}\n\n/**\n * Narrow an unknown value to BrowserNotConnectedError.\n *\n * @param value - Value to check\n * @returns True when value is a BrowserNotConnectedError instance\n */\nexport function isBrowserNotConnectedError(value: unknown): value is BrowserNotConnectedError {\n\treturn isInstance(value, BrowserNotConnectedError)\n}\n\n/**\n * Narrow an unknown value to BrowserDestroyedError.\n *\n * @param value - Value to check\n * @returns True when value is a BrowserDestroyedError instance\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 { CDPTarget } from '@src/core'\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 { setTimeout as waitForTimeout } from 'node:timers/promises'\nimport { isArray, isRecord, isString } from '@orkestrel/contract'\nimport { BROWSER_WAIT_POLL_INTERVAL_MS } from '@src/core'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_CDP_LIST_PATH,\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// === Discovery helpers\n\n/**\n * Enumerate 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} via\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(...findAllEnvOverrides(env))\n\n\tconst paths = options?.paths ?? defaultInstallPaths(platform, env)\n\tcandidates.push(...findAllInstallPaths(paths))\n\n\tconst names = options?.names ?? BROWSER_EXECUTABLE_NAMES\n\tcandidates.push(...probeAllPathNames(names, platform))\n\n\tconst stores = options?.stores ?? defaultStoreBases(env, platform)\n\tfor (const store of stores) {\n\t\tcandidates.push(...findAllInStore(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 * Locate 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 * Classify 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/** Normalize 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/** Classify 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 * Resolve a persistent caller profile or create 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 * Remove 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 Error('Refusing to remove an unsafe browser profile path')\n\t}\n\tawait rm(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })\n}\n\n/** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order for an existing file. */\nexport function findEnvOverride(\n\tenv: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n\treturn findAllEnvOverrides(env)[0]\n}\n\n/** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order, returning every one that exists. */\nexport function findAllEnvOverrides(\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/** Build the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */\nexport function defaultInstallPaths(\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 = windowsRoots(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/** Derive Windows install roots from env vars, falling back to well-known literals when absent. */\nexport function windowsRoots(env: Readonly<Record<string, string | undefined>>): 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/** Return the first candidate path that exists on disk. */\nexport function findInstallPath(paths: readonly string[]): string | undefined {\n\treturn findAllInstallPaths(paths)[0]\n}\n\n/** Return every candidate path that exists on disk, in the given order. */\nexport function findAllInstallPaths(paths: readonly string[]): readonly string[] {\n\treturn paths.filter((path) => existsSync(path))\n}\n\n/** Probe PATH (`which`/`where`) for the first resolvable command name. */\nexport function probePathNames(names: readonly string[], platform: string): string | undefined {\n\treturn probeAllPathNames(names, platform)[0]\n}\n\n/** Probe PATH (`which`/`where`) for every resolvable command name, in the given order. */\nexport function probeAllPathNames(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 output = result.stdout.toString('utf-8').trim().split('\\n')[0]\n\t\t\tif (output !== undefined && output.length > 0) found.push(output)\n\t\t}\n\t}\n\treturn found\n}\n\n/** Build the default Playwright browser store base directories to search for a managed Chromium. */\nexport function defaultStoreBases(\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/** Search one store base for the top-level `chromium` link, else the highest-revision `chromium-*` install. */\nexport function findInStore(base: string, platform: string): string | undefined {\n\treturn findAllInStore(base, platform)[0]\n}\n\n/** Search one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */\nexport function findAllInStore(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 * Launch 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 *\n * @param executable - Absolute path to the browser executable\n * @param port - Port the browser exposes its CDP endpoint on\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\n */\nexport function launchBrowserProcess(\n\texecutable: string,\n\tport: number,\n\theadless: boolean,\n\tprofile?: string,\n\textra?: readonly string[],\n): ChildProcess {\n\t// Caller-supplied args come FIRST so a script path (e.g. `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 below —\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}`, ...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',\n\t\tdetached: process.platform !== 'win32',\n\t})\n}\n\n/**\n * Poll a browser's CDP version endpoint until it responds or the timeout elapses.\n *\n * @param port - Port the browser exposes its CDP endpoint on\n * @param timeout - Maximum time to wait in milliseconds\n * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)\n * @returns The browser's WebSocket debugger URL\n *\n * @throws When the endpoint does not become ready before the timeout\n */\nexport async function waitForCDPReady(\n\tport: number,\n\ttimeout: number,\n\thost: string = BROWSER_DEFAULT_HOST,\n\tsignal?: AbortSignal,\n): Promise<string> {\n\tconst url = `${BROWSER_CDP_PROTOCOL}://${host}:${port}${BROWSER_CDP_VERSION_PATH}`\n\tconst deadline = Date.now() + timeout\n\n\twhile (Date.now() < deadline) {\n\t\tsignal?.throwIfAborted()\n\t\tconst remaining = Math.max(0, deadline - Date.now())\n\t\tconst requestSignal =\n\t\t\tsignal === undefined\n\t\t\t\t? AbortSignal.timeout(remaining)\n\t\t\t\t: AbortSignal.any([signal, AbortSignal.timeout(remaining)])\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: requestSignal })\n\t\t\tif (response.ok) {\n\t\t\t\tconst info: unknown = await response.json()\n\t\t\t\tif (isRecord(info) && isString(info['webSocketDebuggerUrl'])) {\n\t\t\t\t\treturn info['webSocketDebuggerUrl']\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted === true) throw error\n\t\t\t// Not ready yet — keep polling\n\t\t}\n\n\t\tconst delay = Math.min(BROWSER_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()))\n\t\tif (delay > 0) await waitForTimeout(delay, undefined, { signal })\n\t}\n\n\tthrow new Error(`CDP endpoint on port ${port} did not become ready within ${timeout}ms`)\n}\n\n/**\n * Fetch the current CDP target list from a browser's `/json/list` endpoint.\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 Normalized CDP targets\n */\nexport async function fetchCDPTargets(\n\tport: number,\n\ttimeout: number,\n\thost: string = BROWSER_DEFAULT_HOST,\n): Promise<readonly CDPTarget[]> {\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) return []\n\n\t\tconst list: unknown = await response.json()\n\t\tif (!isArray(list)) return []\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\ttype: 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 targets\n\t} catch {\n\t\treturn []\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 } from '@src/core'\nimport { BrowserConnectionError } from '../errors.js'\n\n// === WebSocketCDPTransport\n\n/**\n * `@orkestrel/websocket`-backed raw CDP text transport.\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 */\nexport class WebSocketCDPTransport implements CDPTransportInterface {\n\treadonly #emitter: Emitter<CDPTransportEventMap>\n\treadonly #url: string\n\treadonly #timeout: number\n\t#socket: NodeWebSocketInterface | undefined\n\t#starting: Promise<void> | undefined\n\t#closing: Promise<void> | undefined\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 #onSocketClose = 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\tif (this.#closing !== undefined) await this.#closing\n\t\tif (this.#socket?.readyState === WEBSOCKET_READY_OPEN) return\n\n\t\tconst active = this.#starting\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\tconst transition = this.#open()\n\t\tthis.#starting = transition\n\n\t\ttry {\n\t\t\tawait transition\n\t\t} finally {\n\t\t\tif (this.#starting === transition) this.#starting = undefined\n\t\t}\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 Error('WebSocket CDP transport is not open')\n\t\t}\n\t\tsocket.send(data)\n\t}\n\n\tasync close(): Promise<void> {\n\t\tconst active = this.#closing\n\t\tif (active !== undefined) {\n\t\t\tawait active\n\t\t\treturn\n\t\t}\n\n\t\tconst transition = this.#stop()\n\t\tthis.#closing = transition\n\t\ttry {\n\t\t\tawait transition\n\t\t} finally {\n\t\t\tif (this.#closing === transition) this.#closing = undefined\n\t\t}\n\t}\n\n\t// === Private helpers\n\n\tasync #open(): 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 #stop(): 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?.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.#onSocketClose)\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.#onSocketClose)\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 { CDPTransportInterface, ScreenshotWriterInterface } from '@src/core'\nimport type { BrowserInterface, BrowserOptions, WebSocketCDPTransportOptions } from './types.js'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { Browser } from './Browser.js'\nimport { WebSocketCDPTransport } from './transports/WebSocketCDPTransport.js'\n\n/**\n * Create a raw-CDP Browser façade.\n *\n * @param options - Connection, launch, and viewport configuration\n * @returns A {@link BrowserInterface}\n *\n * @example\n * ```ts\n * import { createBrowser } from '@src/server'\n *\n * const browser = createBrowser()\n * await browser.connect()\n * ```\n */\nexport function createBrowser(options?: BrowserOptions): BrowserInterface {\n\treturn new Browser(options)\n}\n\n/**\n * Create a Node `WebSocket`-backed CDP transport.\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 * Create a filesystem-backed screenshot writer.\n *\n * @returns A {@link ScreenshotWriterInterface} that persists bytes via `node:fs/promises`\n */\nexport function createScreenshotWriter(): ScreenshotWriterInterface {\n\treturn {\n\t\tasync write(path: string, data: Uint8Array): Promise<void> {\n\t\t\tawait mkdir(dirname(path), { recursive: true })\n\t\t\tawait writeFile(path, data)\n\t\t},\n\t}\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\tBrowserContext,\n\tBROWSER_DEFAULT_TIMEOUT_MS,\n\tBROWSER_WAIT_POLL_INTERVAL_MS,\n\tCDPClient,\n\tvalidateBrowserContextOptions,\n} from '@src/core'\nimport {\n\tBrowserConnectionError,\n\tBrowserDestroyedError,\n\tBrowserNotConnectedError,\n\tisBrowserConnectionError,\n} from './errors.js'\nimport {\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_DEFAULT_CDP_PORT,\n\tBROWSER_DEFAULT_HOST,\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\tremoveBrowserProfile,\n\twaitForCDPReady,\n} from './helpers.js'\nimport { createCDPTransport, createScreenshotWriter } from './factories.js'\n\n// === Browser\n\n/**\n * Discovers, launches, connects to, and owns Chromium-family browser sessions.\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#profile: BrowserProfileResult | undefined\n\t#contexts: BrowserContext[] = []\n\t#destroyed = false\n\t#connecting: Promise<void> | undefined\n\t#disconnecting: Promise<void> | undefined\n\t#exitCleanup: Promise<void> | undefined\n\t#shutdown: Promise<void> | undefined\n\t#transport: CDPTransportInterface | undefined\n\treadonly #onTransportClose = this.#handleTransportLoss.bind(this)\n\treadonly #onTransportError = this.#handleTransportLoss.bind(this)\n\treadonly #onProcessExit = 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 connected(): boolean {\n\t\treturn this.#status === 'connected'\n\t}\n\n\tget pid(): number | undefined {\n\t\treturn 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\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\tconst attempt = this.#establish()\n\t\tthis.#connecting = attempt\n\n\t\ttry {\n\t\t\tawait attempt\n\t\t} finally {\n\t\t\tif (this.#connecting === attempt) this.#connecting = undefined\n\t\t}\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\n\t\tconst connecting = this.#connecting\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\tconst attempt = this.#detach()\n\t\tthis.#disconnecting = attempt\n\n\t\ttry {\n\t\t\tawait attempt\n\t\t} finally {\n\t\t\tif (this.#disconnecting === attempt) this.#disconnecting = undefined\n\t\t}\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\tcreateScreenshotWriter(),\n\t\t\toptions?.emulation,\n\t\t\toptions?.downloads,\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(\n\t\t\t\tclient,\n\t\t\t\tundefined,\n\t\t\t\tthis.#options.viewport,\n\t\t\t\tcreateScreenshotWriter(),\n\t\t\t)\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\tif (this.#disconnecting !== undefined) await this.#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.found && 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\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\tconst process = this.#process\n\t\tif (process !== undefined && (process.exitCode !== null || process.signalCode !== null)) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tif (process !== undefined) {\n\t\t\tsetTimeout(() => this.#confirmTransportLoss(), BROWSER_TRANSPORT_LOSS_DEFER_MS)\n\t\t\treturn\n\t\t}\n\n\t\tthis.#confirmTransportLoss()\n\t}\n\n\t#confirmTransportLoss(): void {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\tconst process = this.#process\n\t\tif (process !== undefined && (process.exitCode !== null || process.signalCode !== null)) {\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tif (process?.pid !== undefined) {\n\t\t\ttry {\n\t\t\t\tprocess.kill(0)\n\t\t\t} catch {\n\t\t\t\tthis.#handleProcessExit()\n\t\t\t\treturn\n\t\t\t}\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.#onTransportClose)\n\t\ttransport.emitter.on('error', this.#onTransportError)\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.#onTransportClose)\n\t\ttransport.emitter.off('error', this.#onTransportError)\n\t\tthis.#transport = undefined\n\t}\n\n\t#bindProcess(process: ChildProcess): void {\n\t\tthis.#unbindProcess()\n\t\tprocess.once('exit', this.#onProcessExit)\n\t\tif (process.exitCode !== null || process.signalCode !== null) {\n\t\t\tqueueMicrotask(this.#onProcessExit)\n\t\t}\n\t}\n\n\t#unbindProcess(): void {\n\t\tthis.#process?.off('exit', this.#onProcessExit)\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 {\n\t\t\t\tfound: endpoint !== undefined,\n\t\t\t\tendpoint,\n\t\t\t\tbrowser,\n\t\t\t\tconnection: endpoint !== undefined ? 'cdp' : undefined,\n\t\t\t}\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 { found: false, endpoint: undefined, browser: undefined, connection: 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.#cdpPort,\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\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.#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\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 controller = new AbortController()\n\t\tconst signal = AbortSignal.any([controller.signal, this.#signal()])\n\t\tconst ready = waitForCDPReady(this.#cdpPort, this.#timeout(), this.#cdpHost, signal)\n\t\tconst exited = once(process, 'exit', { signal }).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\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\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\ttype: 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\tcreateScreenshotWriter(),\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\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\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?.catch(() => undefined)\n\t\tawait this.#disconnecting?.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#inspectProcessGroup(process: ChildProcess): boolean | undefined {\n\t\tif (!this.#hasProcessGroup(process)) 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\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\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,\n\t\t\t\tsignal,\n\t\t\t\tcause: error,\n\t\t\t})\n\t\t}\n\t}\n\n\tasync #waitForProcessGroupWithin(\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\t// Node observes only the direct child; POSIX exposes no event for the\n\t\t// remaining members of its process group, so bound the drain probe.\n\t\twhile (true) {\n\t\t\tconst alive = this.#inspectProcessGroup(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_WAIT_POLL_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.#waitForProcessGroupWithin(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.#inspectProcessGroup(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: 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.#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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkestrel/browser",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Chrome DevTools Protocol browser automation with an environment-agnostic core. Part of the @orkestrel line.",
5
5
  "keywords": [
6
6
  "automation",
@@ -21,7 +21,7 @@
21
21
  "url": "git+https://github.com/orkestrel/browser.git"
22
22
  },
23
23
  "files": [
24
- "dist",
24
+ "dist/src",
25
25
  "README.md"
26
26
  ],
27
27
  "type": "module",
@@ -55,22 +55,22 @@
55
55
  "access": "public"
56
56
  },
57
57
  "scripts": {
58
- "clean": "node -e \"try{require('node:fs').rmSync('dist',{recursive:true,force:true})}catch{}\"",
58
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
59
59
  "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)\"",
60
- "tmp:txt": "node -e \"const fs=require('node:fs'),p=require('node:path');function walk(d){for(const e of fs.readdirSync(d,{withFileTypes:true})){const f=p.join(d,e.name);if(e.isDirectory()){walk(f)}else if(!e.name.endsWith('.md')&&!e.name.endsWith('.txt')){const t=f+'.txt';if(!fs.existsSync(t)){fs.renameSync(f,t)}else{console.warn('Skipping '+f+' — target exists: '+t)}}}}try{walk('tmp')}catch(e){if(e.code!=='ENOENT')throw e}\"",
61
60
  "scaffold": "scaffold",
62
- "lint": "oxlint --config .oxlintrc.json --fix .",
61
+ "lint": "oxlint --config .oxlintrc.json --fix --deny-warnings .",
63
62
  "check": "tsc --noEmit --project tsconfig.json && npm run check:src",
64
63
  "check:src": "npm run check:src:core && npm run check:src:server",
65
64
  "check:src:core": "tsc --noEmit -p configs/src/tsconfig.core.json",
66
65
  "check:src:server": "tsc --noEmit -p configs/src/tsconfig.server.json",
67
66
  "format": "oxfmt --config .oxfmtrc.json --write .",
68
67
  "format:check": "oxfmt --config .oxfmtrc.json --check .",
69
- "lint:check": "oxlint --config .oxlintrc.json .",
70
- "test": "npm run test:src && npm run test:guides",
68
+ "lint:check": "oxlint --config .oxlintrc.json --deny-warnings .",
69
+ "test": "npm run test:src && npm run test:policy && npm run test:guides",
71
70
  "test:src": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core --project src:server",
72
71
  "test:src:core": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
73
72
  "test:src:server": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:server",
73
+ "test:policy": "vitest run --config vite.config.ts --no-cache --reporter=dot --project policy",
74
74
  "test:guides": "vitest run --config vite.config.ts --reporter=dot --project guides",
75
75
  "build": "npm run clean && npm run build:src",
76
76
  "build:src": "npm run build:src:core && npm run build:src:server",
@@ -79,24 +79,24 @@
79
79
  "prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test"
80
80
  },
81
81
  "dependencies": {
82
- "@orkestrel/contract": "^0.0.7",
83
- "@orkestrel/emitter": "^0.0.3",
84
- "@orkestrel/websocket": "^0.0.5"
82
+ "@orkestrel/contract": "^0.0.8",
83
+ "@orkestrel/emitter": "^0.0.4",
84
+ "@orkestrel/websocket": "^0.0.6"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@microsoft/api-extractor": "^7.58.12",
88
- "@orkestrel/guide": "^0.0.5",
89
- "@orkestrel/scaffold": "^0.0.2",
90
- "@types/node": "^26.1.1",
88
+ "@orkestrel/guide": "^0.0.7",
89
+ "@orkestrel/scaffold": "^0.0.7",
90
+ "@types/node": "^26.1.2",
91
91
  "@vitest/browser-playwright": "^4.1.10",
92
- "oxfmt": "^0.60.0",
93
- "oxlint": "^1.75.0",
92
+ "oxfmt": "^0.61.0",
93
+ "oxlint": "^1.76.0",
94
94
  "typescript": "^6.0.3",
95
95
  "vite": "^8.1.5",
96
96
  "vite-plugin-dts": "^5.0.3",
97
97
  "vitest": "^4.1.10"
98
98
  },
99
99
  "engines": {
100
- "node": ">=22"
100
+ "node": ">=22.12.0"
101
101
  }
102
102
  }