@orkestrel/browser 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.cjs +422 -162
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +11 -2
- package/dist/src/core/index.d.ts +11 -2
- package/dist/src/core/index.js +422 -162
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +588 -411
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +52 -53
- package/dist/src/server/index.d.ts +52 -53
- package/dist/src/server/index.js +586 -410
- package/dist/src/server/index.js.map +1 -1
- package/package.json +11 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#emitter","#url","#timeout","#connecting","#socket","#bind","#emitter","#options","#engine","#cdpPort","#cdpHost","#status","#connection","#process","#lastPid","#discoverCdp","#destroyed","#assertNotAborted","#connectCdp","#raceAbort","#assertPortFree","#launch","#unbindTransport","#unbindProcess","#client","#reset","#contexts","#terminate","#handleProcessExit","#handleTransportLoss","#transportUnbind","#processUnbind","#timeout","#notFoundResult","#probePort","#bindTransport","#syncContexts","#waitForLaunch","#bindProcess","#formatLaunchExit"],"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 { BrowserDiscoveryResult, 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/** Sentinel result returned by discovery when no browser is reachable. */\nexport const BROWSER_NOT_FOUND_RESULT: BrowserDiscoveryResult = Object.freeze({\n\tfound: false,\n\tendpoint: undefined,\n\tbrowser: undefined,\n\tconnection: undefined,\n})\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/** 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/** 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'\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 value instanceof 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 value instanceof 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 value instanceof BrowserDestroyedError\n}\n","import type { ChildProcess } from 'node:child_process'\nimport type { CDPTarget } from '@src/core'\nimport type { SystemBrowserOptions, SystemBrowser, BrowserEngine } from './types.js'\nimport { existsSync, globSync } from 'node:fs'\nimport { win32 as pathWin32, posix as pathPosix } from 'node:path'\nimport { spawn, spawnSync } from 'node:child_process'\nimport { 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} 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/')) return 'edge'\n\tif (browser.includes('Chrome/')) return 'chrome'\n\treturn 'chromium'\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) => (a < b ? 1 : a > b ? -1 : 0))\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): 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\tconst remaining = Math.max(0, deadline - Date.now())\n\t\tconst controller = new AbortController()\n\t\tconst timer = setTimeout(() => controller.abort(), remaining)\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: controller.signal })\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 {\n\t\t\t// Not ready yet — keep polling\n\t\t} finally {\n\t\t\tclearTimeout(timer)\n\t\t}\n\n\t\tawait new Promise((resolve) => setTimeout(resolve, BROWSER_WAIT_POLL_INTERVAL_MS))\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 (!Array.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 (!isString(entry['id']) || !isString(entry['type'])) continue\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: isString(entry['title']) ? entry['title'] : '',\n\t\t\t\turl: isString(entry['url']) ? 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 { IncomingMessage } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport { randomBytes } from 'node:crypto'\nimport { request as httpRequest } from 'node:http'\nimport { isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport {\n\tcomputeWebSocketAccept,\n\tcreateNodeWebSocket,\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 {@link CDPTransportInterface} — the dumb text\n * pipe a {@link import('@src/core').CDPClientInterface} sends and receives\n * JSON-RPC frames over.\n *\n * @remarks\n * `start()` hand-rolls the RFC 6455 client handshake: it opens a `node:http`\n * `GET` carrying `Connection: Upgrade` / `Upgrade: websocket` / a random\n * `Sec-WebSocket-Key` / `Sec-WebSocket-Version`, awaits the client `'upgrade'`\n * event, and validates `Sec-WebSocket-Accept === computeWebSocketAccept(key)`\n * — a mismatch (or a connection/request error, or a timeout) rejects `start()`\n * with a coded {@link BrowserConnectionError} and cleans up the socket. On\n * success it wraps the raw upgraded socket in `createNodeWebSocket({ socket,\n * head })` (CLIENT mode — no `key` — so outgoing frames are masked per RFC\n * 6455 §5.3) and bridges its `message`/`close`/`error` events onto this\n * transport's emitter. `start()` opens a fresh socket each call (safe to call\n * again after `close()` — a new request/socket/NodeWebSocket triple is\n * created every time, which is what `CDPClient.reconnect()` depends on). CDP\n * frames are text-only, so `message` always carries a `string`.\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#connecting:\n\t\t| {\n\t\t\t\treadonly abort: () => void\n\t\t\t\treadonly timer: ReturnType<typeof setTimeout>\n\t\t\t\treadonly reject: (error: unknown) => void\n\t\t }\n\t\t| undefined\n\n\tconstructor(options: WebSocketCDPTransportOptions) {\n\t\tthis.#emitter = new Emitter()\n\t\tthis.#url = options.url\n\t\tthis.#timeout = options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS\n\t}\n\n\tget emitter(): EmitterInterface<CDPTransportEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tasync start(): Promise<void> {\n\t\tconst url = new URL(this.#url)\n\t\tconst key = randomBytes(16).toString('base64')\n\n\t\tconst ws = await new Promise<NodeWebSocketInterface>((resolve, reject) => {\n\t\t\tconst settle = (fn: () => void): void => {\n\t\t\t\tthis.#connecting = undefined\n\t\t\t\tfn()\n\t\t\t}\n\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\trequest.destroy()\n\t\t\t\tsettle(() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t\t\t`WebSocket CDP connection to ${this.#url} timed out after ${this.#timeout}ms`,\n\t\t\t\t\t\t\t{ url: this.#url, timeout: this.#timeout },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}, this.#timeout)\n\n\t\t\tconst request = httpRequest({\n\t\t\t\thostname: url.hostname,\n\t\t\t\tport: url.port.length > 0 ? Number(url.port) : 80,\n\t\t\t\tpath: `${url.pathname}${url.search}`,\n\t\t\t\theaders: {\n\t\t\t\t\tConnection: 'Upgrade',\n\t\t\t\t\tUpgrade: 'websocket',\n\t\t\t\t\t'Sec-WebSocket-Key': key,\n\t\t\t\t\t'Sec-WebSocket-Version': WEBSOCKET_VERSION,\n\t\t\t\t},\n\t\t\t})\n\n\t\t\trequest.on('upgrade', (response: IncomingMessage, socket: Duplex, head: Buffer) => {\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tconst accept = response.headers['sec-websocket-accept']\n\t\t\t\tif (!isString(accept) || accept !== computeWebSocketAccept(key)) {\n\t\t\t\t\tsocket.destroy()\n\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: Sec-WebSocket-Accept mismatch`,\n\t\t\t\t\t\t\t\t{ url: this.#url },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tsettle(() => resolve(createNodeWebSocket({ socket, head })))\n\t\t\t})\n\n\t\t\trequest.on('response', (response) => {\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tresponse.resume()\n\t\t\t\tsettle(() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: upgrade declined with status ${response.statusCode ?? 0}`,\n\t\t\t\t\t\t\t{ url: this.#url },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\n\t\t\trequest.on('error', (error) => {\n\t\t\t\tclearTimeout(timer)\n\t\t\t\tsettle(() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew BrowserConnectionError(\n\t\t\t\t\t\t\t`WebSocket CDP connection to ${this.#url} failed: ${error.message}`,\n\t\t\t\t\t\t\t{ url: this.#url },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t})\n\n\t\t\tthis.#connecting = {\n\t\t\t\tabort: () => request.destroy(),\n\t\t\t\ttimer,\n\t\t\t\treject: (error) => settle(() => reject(error)),\n\t\t\t}\n\n\t\t\trequest.end()\n\t\t})\n\n\t\tthis.#socket = ws\n\t\tthis.#bind(ws)\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 connecting = this.#connecting\n\t\tif (connecting !== undefined) {\n\t\t\tclearTimeout(connecting.timer)\n\t\t\tthis.#connecting = undefined\n\t\t\tconnecting.abort()\n\t\t\tconnecting.reject(\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\treturn\n\t\t}\n\n\t\tconst socket = this.#socket\n\t\tif (socket === undefined) return\n\t\tthis.#socket = undefined\n\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tsocket.emitter.on('close', () => resolve())\n\t\t\tsocket.close()\n\t\t})\n\t}\n\n\t// === Private helpers\n\n\t#bind(ws: NodeWebSocketInterface): void {\n\t\tws.emitter.on('message', (data) => {\n\t\t\tthis.#emitter.emit('message', data)\n\t\t})\n\n\t\tws.emitter.on('close', () => {\n\t\t\tthis.#emitter.emit('close')\n\t\t})\n\n\t\tws.emitter.on('error', (error) => {\n\t\t\tthis.#emitter.emit('error', error)\n\t\t})\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\tBrowserEventMap,\n\tBrowserOptions,\n\tBrowserEngine,\n\tBrowserStatus,\n\tBrowserConnection,\n\tBrowserInterface,\n\tBrowserDiscoveryResult,\n} from './types.js'\nimport type {\n\tBrowserContextInterface,\n\tBrowserPageInterface,\n\tBrowserPageOptions,\n\tCDPTransportInterface,\n} from '@src/core'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport { isRecord, isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { CDPClient, BrowserContext, BROWSER_DEFAULT_TIMEOUT_MS } from '@src/core'\nimport {\n\tBrowserConnectionError,\n\tBrowserNotConnectedError,\n\tBrowserDestroyedError,\n} from './errors.js'\nimport {\n\tBROWSER_DEFAULT_CDP_PORT,\n\tBROWSER_DEFAULT_HOST,\n\tBROWSER_CDP_VERSION_PATH,\n\tBROWSER_CDP_PROTOCOL,\n\tBROWSER_KILL_GRACE_MS,\n\tBROWSER_PORT_PROBE_TIMEOUT_MS,\n\tBROWSER_TRANSPORT_LOSS_DEFER_MS,\n} from './constants.js'\nimport {\n\tfindSystemBrowser,\n\tparseBrowserEngine,\n\tbrowserToEngine,\n\tlaunchBrowserProcess,\n\twaitForCdpReady,\n\tfetchCdpTargets,\n} from './helpers.js'\nimport { createCDPTransport, createScreenshotWriter } from './factories.js'\n\n// === Browser\n\nexport class Browser implements BrowserInterface {\n\treadonly #emitter: Emitter<BrowserEventMap>\n\t#options: BrowserOptions\n\t#engine: BrowserEngine\n\t#status: BrowserStatus = 'idle'\n\t#connection: BrowserConnection | undefined\n\t#client: CDPClient | undefined\n\t#process: ChildProcess | undefined\n\t#cdpPort: number\n\t#cdpHost: string\n\t#contexts: BrowserContext[] = []\n\t#destroyed = false\n\t#transportUnbind: (() => void) | undefined\n\t#processUnbind: (() => void) | undefined\n\t#lastPid: number | undefined\n\n\tconstructor(options?: BrowserOptions) {\n\t\tthis.#emitter = new Emitter({ on: options?.on })\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\t// Emit idle after construction to signal browser is ready for connection\n\t\tqueueMicrotask(() => this.#emitter.emit('idle'))\n\t}\n\n\tget emitter(): EmitterInterface<BrowserEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t// === Property accessors\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 connected(): boolean {\n\t\treturn this.#status === 'connected'\n\t}\n\n\tget pid(): number | undefined {\n\t\treturn this.#process?.pid ?? this.#lastPid\n\t}\n\n\t// === Discovery\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\t// === Connection\n\n\tasync connect(): Promise<void> {\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\t// Step 1: explicit CDP endpoint (highest priority — user explicitly specified)\n\t\t\tconst cdpEndpoint = this.#options.cdp?.endpoint\n\t\t\tif (cdpEndpoint !== undefined) {\n\t\t\t\tawait this.#connectCdp(cdpEndpoint)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Step 2: passive CDP discovery (connect to existing browser if available)\n\t\t\tconst discover = this.#options.cdp?.discover ?? true\n\t\t\tif (discover) {\n\t\t\t\tthis.#assertNotAborted()\n\t\t\t\tconst discovery = await this.#raceAbort(this.#discoverCdp())\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\t// Discovery explicitly disabled — the caller demanded a fresh\n\t\t\t\t// launch with a specific profile/engine, so a stray listener on\n\t\t\t\t// the port must reject loudly rather than being silently attached to.\n\t\t\t\tthis.#assertNotAborted()\n\t\t\t\tawait this.#raceAbort(this.#assertPortFree())\n\t\t\t}\n\n\t\t\t// Step 3: launch system browser with CDP\n\t\t\tthis.#assertNotAborted()\n\t\t\tawait this.#launch()\n\t\t} catch (thrown) {\n\t\t\tthis.#status = 'error'\n\t\t\tthis.#emitter.emit('error', thrown)\n\t\t\tif (thrown instanceof BrowserConnectionError) throw thrown\n\t\t\tconst message = thrown instanceof Error ? thrown.message : String(thrown)\n\t\t\tthrow new BrowserConnectionError(message, { executable: this.#options.executable })\n\t\t}\n\t}\n\n\t// === Disconnection\n\n\tasync disconnect(): Promise<void> {\n\t\tif (this.#destroyed || this.#status !== 'connected') return\n\n\t\t// An ephemeral 'launch' (no persistent profile) has no way to be\n\t\t// reattached to later — detaching here would strand its process with\n\t\t// no path back to it. Callers must use destroy() instead. A\n\t\t// 'persistent' (profile-backed) launch IS reattachable (via CDP\n\t\t// discovery on the same port), so it falls through to the same\n\t\t// release-without-killing path as a 'cdp' connection.\n\t\tif (this.#connection === 'launch') {\n\t\t\tthrow new BrowserConnectionError(\n\t\t\t\t'Cannot disconnect() an ephemeral launch — no persistent profile to reattach to; ephemeral launches must use destroy() to release it',\n\t\t\t\t{ connection: this.#connection },\n\t\t\t)\n\t\t}\n\n\t\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\n\t\tconst client = this.#client\n\t\tif (client !== undefined) {\n\t\t\ttry {\n\t\t\t\tawait client.close()\n\t\t\t} catch {\n\t\t\t\t// Swallow — best-effort close on detach\n\t\t\t}\n\t\t}\n\n\t\t// Release ownership of a launched process WITHOUT killing it, so a\n\t\t// 'persistent' session's browser stays alive for later reattachment.\n\t\t// The pid stays readable on this instance until destroy() or an\n\t\t// observed process exit clears it.\n\t\tif (this.#process?.pid !== undefined) this.#lastPid = this.#process.pid\n\t\tthis.#process = undefined\n\n\t\tthis.#reset()\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t// === Context management\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\t// === Page creation shortcut\n\n\tasync create(options?: BrowserPageOptions): Promise<BrowserPageInterface> {\n\t\tif (this.#destroyed) throw new BrowserDestroyedError()\n\t\tif (this.#status !== 'connected' || this.#client === undefined)\n\t\t\tthrow new BrowserNotConnectedError()\n\n\t\t// Get or create the default context\n\t\tlet ctx = this.#contexts[0]\n\t\tif (ctx === undefined) {\n\t\t\tctx = new BrowserContext(\n\t\t\t\tthis.#client,\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.#contexts.push(ctx)\n\t\t}\n\t\tconst page = await ctx.create(options)\n\t\tthis.#emitter.emit('page', page)\n\t\treturn page\n\t}\n\n\t// === Lifecycle\n\n\tasync destroy(): Promise<void> {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\n\t\ttry {\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\n\t\t\t// Owned (launch/persistent) browsers close their pages/contexts\n\t\t\t// normally. A CDP-attached browser is a LOCAL DETACH ONLY — other\n\t\t\t// clients may share those targets, so no remote close is sent.\n\t\t\tconst owned = this.#process !== undefined\n\t\t\tif (owned) {\n\t\t\t\tfor (const ctx of this.#contexts) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ctx.close()\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Swallow errors during teardown\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.#contexts = []\n\n\t\t\t// Kill launched browser process, then close CDP client (§13 order)\n\t\t\tawait this.#terminate(this.#process)\n\t\t\tthis.#process = undefined\n\n\t\t\tif (this.#client !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#client.close()\n\t\t\t\t} catch {\n\t\t\t\t\t// Swallow\n\t\t\t\t}\n\t\t\t\tthis.#client = undefined\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#status = 'disconnected'\n\t\t\tthis.#connection = undefined\n\t\t\tthis.#lastPid = undefined\n\t\t\tthis.#emitter.emit('destroy')\n\t\t\tthis.#emitter.destroy()\n\t\t}\n\t}\n\n\t/**\n\t * Gracefully shut down the remote browser, whether this instance owns its\n\t * process or merely attached to it via CDP.\n\t *\n\t * @remarks\n\t * Sends CDP `Browser.close` best-effort; on an owned browser also awaits\n\t * the process's exit (bounded by the kill-escalation grace period,\n\t * escalating to a kill only if it does not exit in time). Ends in the\n\t * same local-cleanup state as `destroy()`.\n\t */\n\tasync close(): Promise<void> {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\n\t\ttry {\n\t\t\tthis.#unbindTransport()\n\t\t\tthis.#unbindProcess()\n\n\t\t\tconst client = this.#client\n\t\t\tif (client !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tawait client.send('Browser.close')\n\t\t\t\t} catch {\n\t\t\t\t\t// Best-effort — the remote may not support it or may already be gone\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst process = this.#process\n\t\t\tif (process !== undefined) {\n\t\t\t\tconst exited = new Promise<void>((resolve) => {\n\t\t\t\t\tprocess.once('exit', () => resolve())\n\t\t\t\t})\n\n\t\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\t\t\tconst timedOut = await Promise.race([\n\t\t\t\t\texited.then(() => false),\n\t\t\t\t\tnew Promise<boolean>((resolve) => {\n\t\t\t\t\t\ttimer = setTimeout(() => resolve(true), BROWSER_KILL_GRACE_MS)\n\t\t\t\t\t}),\n\t\t\t\t])\n\t\t\t\tif (timer !== undefined) clearTimeout(timer)\n\n\t\t\t\t// Browser.close already asked nicely — escalate only if the\n\t\t\t\t// process failed to exit within the bound.\n\t\t\t\tif (timedOut) await this.#terminate(process)\n\t\t\t\tthis.#process = undefined\n\t\t\t}\n\n\t\t\tfor (const ctx of this.#contexts) {\n\t\t\t\ttry {\n\t\t\t\t\tawait ctx.close()\n\t\t\t\t} catch {\n\t\t\t\t\t// Swallow errors during teardown\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.#contexts = []\n\n\t\t\tif (client !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tawait client.close()\n\t\t\t\t} catch {\n\t\t\t\t\t// Swallow\n\t\t\t\t}\n\t\t\t\tthis.#client = undefined\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#status = 'disconnected'\n\t\t\tthis.#connection = undefined\n\t\t\tthis.#lastPid = undefined\n\t\t\tthis.#emitter.emit('destroy')\n\t\t\tthis.#emitter.destroy()\n\t\t}\n\t}\n\n\t// === Private helpers\n\n\t#assertNotAborted(): void {\n\t\tif (this.#options.signal?.aborted) {\n\t\t\tthrow new BrowserConnectionError('Connection aborted')\n\t\t}\n\t}\n\n\t/**\n\t * Race a promise against the connection's external AbortSignal (if any),\n\t * rejecting promptly with a coded BrowserConnectionError when it fires.\n\t */\n\tasync #raceAbort<T>(promise: Promise<T>): Promise<T> {\n\t\tconst signal = this.#options.signal\n\t\tif (signal === undefined) return promise\n\t\tif (signal.aborted) throw new BrowserConnectionError('Connection aborted')\n\n\t\tlet abortWon = false\n\n\t\treturn await new Promise<T>((resolve, reject) => {\n\t\t\tconst onAbort = (): void => {\n\t\t\t\tabortWon = true\n\t\t\t\tcleanup()\n\t\t\t\treject(new BrowserConnectionError('Connection aborted'))\n\t\t\t}\n\t\t\tconst cleanup = (): void => signal.removeEventListener('abort', onAbort)\n\t\t\tsignal.addEventListener('abort', onAbort, { once: true })\n\t\t\tpromise.then(\n\t\t\t\t(value) => {\n\t\t\t\t\tcleanup()\n\t\t\t\t\tresolve(value)\n\t\t\t\t},\n\t\t\t\t(error: unknown) => {\n\t\t\t\t\tcleanup()\n\t\t\t\t\treject(error)\n\t\t\t\t},\n\t\t\t)\n\t\t}).catch((error: unknown) => {\n\t\t\t// When the abort signal wins the race, `promise` is still in\n\t\t\t// flight — attach an observer so its eventual rejection doesn't\n\t\t\t// surface as an unhandled rejection once nobody is listening.\n\t\t\tif (abortWon) promise.catch(() => undefined)\n\t\t\tthrow error\n\t\t})\n\t}\n\n\t#reset(): void {\n\t\tthis.#contexts = []\n\t\tthis.#status = 'disconnected'\n\t\tthis.#connection = undefined\n\t\tthis.#client = undefined\n\t}\n\n\t/**\n\t * Handle the owned process exiting on its own (not via destroy()/close()).\n\t * The process is already gone — no kill is attempted. Cleans up orphaned\n\t * state so the next connect() call can start fresh, and emits a coded\n\t * `error` (cause: process exit) before `disconnect`.\n\t */\n\t#handleProcessExit(): void {\n\t\tif (this.#destroyed) return\n\t\tif (this.#status !== 'connected') return\n\n\t\tthis.#unbindTransport()\n\t\tthis.#unbindProcess()\n\n\t\tconst client = this.#client\n\t\tthis.#process = undefined\n\t\tthis.#lastPid = undefined\n\t\tthis.#reset()\n\n\t\tif (client !== undefined) client.close().catch(() => undefined)\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: 'process-exit',\n\t\t\t}),\n\t\t)\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t/**\n\t * Handle a transport close/error while the owned process (if any) is\n\t * still alive, or the connection is CDP-attached. Never kills the\n\t * process — only the local client is reset, so the SAME instance can\n\t * reconnect (e.g. rediscover on the port and reattach). Emits a coded\n\t * `error` (cause: connection loss) before `disconnect`.\n\t */\n\t#handleTransportLoss(deferred = false): void {\n\t\tif (this.#destroyed) return\n\t\tif (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\t// The owned process is already dead — this IS a process exit, not\n\t\t\t// merely a lost connection.\n\t\t\tthis.#handleProcessExit()\n\t\t\treturn\n\t\t}\n\n\t\tif (process !== undefined && !deferred) {\n\t\t\t// A killed owned process's sockets can close before its 'exit'\n\t\t\t// event is reaped by libuv — defer briefly so an already-pending\n\t\t\t// 'exit' (handled by #handleProcessExit via the bound listener)\n\t\t\t// gets first say over what really happened; if it wins, this call\n\t\t\t// becomes a no-op via the #status guard above. Only ever defers once.\n\t\t\tsetTimeout(() => this.#handleTransportLoss(true), BROWSER_TRANSPORT_LOSS_DEFER_MS)\n\t\t\treturn\n\t\t}\n\n\t\tif (process !== undefined && process.pid !== undefined) {\n\t\t\t// The 'exit' event may still not have reached us even after the\n\t\t\t// defer (a slow-to-reap libuv tick) — re-verify liveness directly\n\t\t\t// via signal 0 so a genuinely dead process routes through the\n\t\t\t// process-exit cleanup path (clearing #process) instead of being\n\t\t\t// left stranded as a resumable owned process.\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\tthis.#unbindTransport()\n\n\t\tconst client = this.#client\n\t\tthis.#reset()\n\n\t\tif (client !== undefined) client.close().catch(() => undefined)\n\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: 'connection-loss',\n\t\t\t}),\n\t\t)\n\t\tthis.#emitter.emit('disconnect')\n\t\tthis.#emitter.emit('idle')\n\t}\n\n\t/** Subscribe to the CDP transport's close/error events for deterministic transport-loss detection. */\n\t#bindTransport(transport: CDPTransportInterface): void {\n\t\tconst onClose = (): void => this.#handleTransportLoss()\n\t\tconst onError = (): void => this.#handleTransportLoss()\n\t\ttransport.emitter.on('close', onClose)\n\t\ttransport.emitter.on('error', onError)\n\t\tthis.#transportUnbind = () => {\n\t\t\ttransport.emitter.off('close', onClose)\n\t\t\ttransport.emitter.off('error', onError)\n\t\t}\n\t}\n\n\t#unbindTransport(): void {\n\t\tthis.#transportUnbind?.()\n\t\tthis.#transportUnbind = undefined\n\t}\n\n\t/** Subscribe to a launched process's exit event for deterministic process-exit detection. */\n\t#bindProcess(process: ChildProcess): void {\n\t\tconst onExit = (): void => this.#handleProcessExit()\n\t\tprocess.once('exit', onExit)\n\t\tthis.#processUnbind = () => process.off('exit', onExit)\n\t}\n\n\t#unbindProcess(): void {\n\t\tthis.#processUnbind?.()\n\t\tthis.#processUnbind = undefined\n\t}\n\n\t#timeout(): number {\n\t\treturn this.#options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS\n\t}\n\n\tasync #discoverCdp(): Promise<BrowserDiscoveryResult> {\n\t\tconst port = this.#cdpPort\n\t\tconst url = `${BROWSER_CDP_PROTOCOL}://${this.#cdpHost}:${port}${BROWSER_CDP_VERSION_PATH}`\n\t\tconst controller = new AbortController()\n\t\tconst timer = setTimeout(() => controller.abort(), this.#timeout())\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: controller.signal })\n\n\t\t\tif (!response.ok) return this.#notFoundResult()\n\n\t\t\tconst info: unknown = await response.json()\n\t\t\tif (!isRecord(info)) return this.#notFoundResult()\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 browserName = 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: browserName,\n\t\t\t\tconnection: endpoint !== undefined ? 'cdp' : undefined,\n\t\t\t}\n\t\t} catch {\n\t\t\treturn this.#notFoundResult()\n\t\t} finally {\n\t\t\tclearTimeout(timer)\n\t\t}\n\t}\n\n\t#notFoundResult(): BrowserDiscoveryResult {\n\t\treturn { found: false, endpoint: undefined, browser: undefined, connection: undefined }\n\t}\n\n\t/**\n\t * Reject when something is already listening on the configured CDP port —\n\t * used ahead of a `discover: false` launch, so a caller demanding a fresh\n\t * browser never silently attaches to a stranger already on that port.\n\t */\n\tasync #assertPortFree(): Promise<void> {\n\t\tconst occupied = await this.#probePort()\n\t\tif (occupied) {\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\t/** Very short probe of the CDP version endpoint — just enough to detect an occupied port, not full discovery. */\n\tasync #probePort(): Promise<boolean> {\n\t\tconst url = `${BROWSER_CDP_PROTOCOL}://${this.#cdpHost}:${this.#cdpPort}${BROWSER_CDP_VERSION_PATH}`\n\t\tconst controller = new AbortController()\n\t\tconst timer = setTimeout(() => controller.abort(), BROWSER_PORT_PROBE_TIMEOUT_MS)\n\n\t\ttry {\n\t\t\tconst response = await fetch(url, { signal: controller.signal })\n\t\t\treturn response.ok\n\t\t} catch {\n\t\t\treturn false\n\t\t} finally {\n\t\t\tclearTimeout(timer)\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\n\t\ttry {\n\t\t\tawait this.#raceAbort(client.connect())\n\n\t\t\tthis.#client = client\n\t\t\tthis.#connection = 'cdp'\n\t\t\tthis.#status = 'connected'\n\t\t\tthis.#bindTransport(transport)\n\n\t\t\t// Sync existing targets as contexts\n\t\t\tawait this.#syncContexts()\n\n\t\t\tthis.#emitter.emit('connect', 'cdp')\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait client.close()\n\t\t\t} catch {\n\t\t\t\t// Swallow — best-effort cleanup of the failed attempt\n\t\t\t}\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 ? { engine: requestedEngine } : undefined,\n\t\t\t)\n\t\t}\n\n\t\tthis.#engine = resolvedEngine ?? 'chromium'\n\n\t\tconst headless = this.#options.headless ?? true\n\t\tconst profile = this.#options.profile\n\t\tconst extra = this.#options.args\n\n\t\tconst process = launchBrowserProcess(executable, this.#cdpPort, headless, profile, extra)\n\t\tthis.#process = process\n\n\t\tlet transport: CDPTransportInterface | undefined\n\t\tlet client: CDPClient | undefined\n\n\t\ttry {\n\t\t\t// Wait for the CDP endpoint to be available\n\t\t\tconst wsUrl = await this.#raceAbort(this.#waitForLaunch(process, executable, extra))\n\n\t\t\t// Connect to the browser via CDP\n\t\t\ttransport = createCDPTransport({ url: wsUrl, 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\tthis.#client = client\n\t\t\tthis.#connection = profile !== undefined ? 'persistent' : 'launch'\n\t\t\tthis.#status = 'connected'\n\t\t\tthis.#bindTransport(transport)\n\t\t\tthis.#bindProcess(process)\n\n\t\t\t// Sync existing targets\n\t\t\tawait this.#syncContexts()\n\n\t\t\tthis.#emitter.emit('launch', this.#engine)\n\t\t\tthis.#emitter.emit('connect', this.#connection)\n\t\t} catch (error) {\n\t\t\tif (client !== undefined) {\n\t\t\t\ttry {\n\t\t\t\t\tawait client.close()\n\t\t\t\t} catch {\n\t\t\t\t\t// Swallow — best-effort cleanup of the failed attempt\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait this.#terminate(process)\n\t\t\tthis.#process = 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\n\t\treturn await new Promise((resolve, reject) => {\n\t\t\tlet settled = false\n\n\t\t\tconst finish = (callback: () => void): void => {\n\t\t\t\tif (settled) return\n\t\t\t\tsettled = true\n\t\t\t\tprocess.off('error', onError)\n\t\t\t\tprocess.off('exit', onExit)\n\t\t\t\tcallback()\n\t\t\t}\n\n\t\t\tconst onError = (error: Error): void => {\n\t\t\t\tfinish(() => reject(new BrowserConnectionError(error.message, context)))\n\t\t\t}\n\n\t\t\tconst onExit = (code: number | null, signal: NodeJS.Signals | null): void => {\n\t\t\t\tfinish(() =>\n\t\t\t\t\treject(new BrowserConnectionError(this.#formatLaunchExit(code, signal), context)),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tprocess.once('error', onError)\n\t\t\tprocess.once('exit', onExit)\n\n\t\t\tvoid waitForCdpReady(this.#cdpPort, this.#timeout(), this.#cdpHost).then(\n\t\t\t\t(wsUrl) => {\n\t\t\t\t\tfinish(() => resolve(wsUrl))\n\t\t\t\t},\n\t\t\t\t(error: unknown) => {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error)\n\t\t\t\t\tfinish(() => reject(new BrowserConnectionError(message, context)))\n\t\t\t\t},\n\t\t\t)\n\t\t})\n\t}\n\n\t#formatLaunchExit(code: number | null, signal: NodeJS.Signals | null): string {\n\t\tif (signal !== null) {\n\t\t\treturn `Browser process exited before CDP became ready (signal: ${signal})`\n\t\t}\n\n\t\tif (code !== null) {\n\t\t\treturn `Browser process exited before CDP became ready (code: ${code})`\n\t\t}\n\n\t\treturn 'Browser process exited before CDP became ready'\n\t}\n\n\tasync #syncContexts(): Promise<void> {\n\t\tif (this.#client === undefined) return\n\n\t\tconst targets = await fetchCdpTargets(this.#cdpPort, this.#timeout(), this.#cdpHost)\n\t\tconst pageTargets = targets.filter((t) => t.type === 'page')\n\n\t\tif (pageTargets.length > 0 && this.#contexts.length === 0) {\n\t\t\tconst ctx = new BrowserContext(\n\t\t\t\tthis.#client,\n\t\t\t\tundefined,\n\t\t\t\tthis.#options.viewport,\n\t\t\t\tcreateScreenshotWriter(),\n\t\t\t)\n\t\t\tawait ctx.sync(pageTargets)\n\t\t\tthis.#contexts.push(ctx)\n\t\t}\n\t}\n\n\t/**\n\t * Terminate a browser process, escalating from SIGTERM to SIGKILL if it\n\t * does not exit within the grace period. Tolerates a process that has\n\t * already exited (ESRCH).\n\t */\n\tasync #terminate(process: ChildProcess | undefined): Promise<void> {\n\t\tif (process === undefined) return\n\t\tif (process.exitCode !== null || process.signalCode !== null) return\n\n\t\tconst exited = new Promise<void>((resolve) => {\n\t\t\tprocess.once('exit', () => resolve())\n\t\t})\n\n\t\ttry {\n\t\t\tprocess.kill('SIGTERM')\n\t\t} catch {\n\t\t\t// Already dead — tolerate ESRCH\n\t\t\treturn\n\t\t}\n\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined\n\t\tconst timedOut = await Promise.race([\n\t\t\texited.then(() => false),\n\t\t\tnew Promise<boolean>((resolve) => {\n\t\t\t\ttimer = setTimeout(() => resolve(true), BROWSER_KILL_GRACE_MS)\n\t\t\t}),\n\t\t])\n\t\tif (timer !== undefined) clearTimeout(timer)\n\n\t\tif (timedOut) {\n\t\t\ttry {\n\t\t\t\tprocess.kill('SIGKILL')\n\t\t\t} catch {\n\t\t\t\t// Already dead — tolerate ESRCH\n\t\t\t}\n\t\t\tawait exited\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
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","#shutdown","#destroyResources","#closeResources","#assertNotAborted","#connectCDP","#raceAbort","#signal","#assertPortFree","#launch","#unbindTransport","#destroyContexts","#closeClient","#unbindProcess","#destroyContextList","#confirmTransportLoss","#transport","#onTransportClose","#onTransportError","#onProcessExit","#timeout","#notFound","#probePort","#retainedConnection","#bindTransport","#syncContexts","#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/** 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'\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 value instanceof 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 value instanceof 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 value instanceof BrowserDestroyedError\n}\n","import type { ChildProcess } from 'node:child_process'\nimport type { CDPTarget } from '@src/core'\nimport type { SystemBrowserOptions, SystemBrowser, BrowserEngine } from './types.js'\nimport { existsSync, globSync } from 'node:fs'\nimport { 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 { 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} 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/** 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 (!Array.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 { 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 attempt = this.#open()\n\t\tthis.#starting = attempt\n\n\t\ttry {\n\t\t\tawait attempt\n\t\t} finally {\n\t\t\tif (this.#starting === attempt) 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 attempt = this.#stop()\n\t\tthis.#closing = attempt\n\t\ttry {\n\t\t\tawait attempt\n\t\t} finally {\n\t\t\tif (this.#closing === attempt) this.#closing = undefined\n\t\t}\n\t}\n\n\t// === Private helpers\n\n\tasync #open(): Promise<void> {\n\t\tconst url = new URL(this.#url)\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\tBrowserStatus,\n} from './types.js'\nimport type {\n\tBrowserContextInterface,\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 { isRecord, isString } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { BrowserContext, BROWSER_DEFAULT_TIMEOUT_MS, CDPClient } from '@src/core'\nimport {\n\tBrowserConnectionError,\n\tBrowserDestroyedError,\n\tBrowserNotConnectedError,\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\tfindSystemBrowser,\n\tlaunchBrowserProcess,\n\tparseBrowserEngine,\n\twaitForCDPReady,\n} from './helpers.js'\nimport { createCDPTransport, createScreenshotWriter } from './factories.js'\n\n// === Browser\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#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 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.#contexts.push(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 (error instanceof BrowserConnectionError) throw error\n\n\t\t\tconst message = error instanceof 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\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\tconst profile = this.#options.profile\n\t\tconst process = launchBrowserProcess(\n\t\t\texecutable,\n\t\t\tthis.#cdpPort,\n\t\t\tthis.#options.headless ?? true,\n\t\t\tprofile,\n\t\t\tthis.#options.args,\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 = 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\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 = typeof values[0] === 'number' ? values[0] : null\n\t\t\tconst exitSignal = typeof values[1] === 'string' ? 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 (error instanceof BrowserConnectionError) throw error\n\t\t\tif (this.#signal().aborted) throw new BrowserConnectionError('Connection aborted', context)\n\n\t\t\tconst message = error instanceof 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) || !Array.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.#contexts.push(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\tthis.#finish()\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\tthis.#finish()\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\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 #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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkestrel/browser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Chrome DevTools Protocol browser automation with an environment-agnostic core. Part of the @orkestrel line.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"clean": "node -e \"try{require('node:fs').rmSync('dist',{recursive:true,force:true})}catch{}\"",
|
|
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
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
|
+
"scaffold": "scaffold",
|
|
61
62
|
"lint": "oxlint --config .oxlintrc.json --fix .",
|
|
62
63
|
"check": "tsc --noEmit --project tsconfig.json && npm run check:src",
|
|
63
64
|
"check:src": "npm run check:src:core && npm run check:src:server",
|
|
@@ -78,16 +79,18 @@
|
|
|
78
79
|
"prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test"
|
|
79
80
|
},
|
|
80
81
|
"dependencies": {
|
|
81
|
-
"@orkestrel/contract": "^0.0.
|
|
82
|
-
"@orkestrel/emitter": "^0.0.
|
|
83
|
-
"@orkestrel/websocket": "^0.0.
|
|
82
|
+
"@orkestrel/contract": "^0.0.7",
|
|
83
|
+
"@orkestrel/emitter": "^0.0.3",
|
|
84
|
+
"@orkestrel/websocket": "^0.0.5"
|
|
84
85
|
},
|
|
85
86
|
"devDependencies": {
|
|
86
|
-
"@microsoft/api-extractor": "^7.58.
|
|
87
|
-
"@orkestrel/guide": "^0.0.
|
|
87
|
+
"@microsoft/api-extractor": "^7.58.12",
|
|
88
|
+
"@orkestrel/guide": "^0.0.5",
|
|
89
|
+
"@orkestrel/scaffold": "^0.0.2",
|
|
88
90
|
"@types/node": "^26.1.1",
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
+
"@vitest/browser-playwright": "^4.1.10",
|
|
92
|
+
"oxfmt": "^0.60.0",
|
|
93
|
+
"oxlint": "^1.75.0",
|
|
91
94
|
"typescript": "^6.0.3",
|
|
92
95
|
"vite": "^8.1.5",
|
|
93
96
|
"vite-plugin-dts": "^5.0.3",
|