@orkestrel/browser 0.0.14 → 0.0.15

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.
@@ -14,35 +14,35 @@ let _orkestrel_emitter = require("@orkestrel/emitter");
14
14
  let _orkestrel_websocket = require("@orkestrel/websocket");
15
15
  let node_events = require("node:events");
16
16
  //#region src/server/constants.ts
17
- /** Default CDP port probed for an existing browser and used for launches. */
17
+ /** Sets the default CDP port probed for an existing browser and used for launches. */
18
18
  var BROWSER_DEFAULT_CDP_PORT = 9222;
19
- /** Default host probed for an existing browser and used for launches (avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`). */
19
+ /** Sets the default host probed for an existing browser and used for launches (avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`). */
20
20
  var BROWSER_DEFAULT_HOST = "127.0.0.1";
21
- /** Protocol prefix for CDP discovery requests. */
21
+ /** Names the protocol prefix for CDP discovery requests. */
22
22
  var BROWSER_CDP_PROTOCOL = "http";
23
- /** Path appended to the CDP host to fetch version metadata (endpoint discovery). */
23
+ /** Names the path appended to the CDP host to fetch version metadata (endpoint discovery). */
24
24
  var BROWSER_CDP_VERSION_PATH = "/json/version";
25
- /** Path appended to the CDP host to list open targets (pages, workers, etc). */
25
+ /** Names the path appended to the CDP host to list open targets (pages, workers, etc). */
26
26
  var BROWSER_CDP_LIST_PATH = "/json/list";
27
- /** Flags always passed to a launched browser process, alongside the caller's own. */
27
+ /** Lists the flags always passed to a launched browser process, alongside the caller's own. */
28
28
  var BROWSER_LAUNCH_ARGS = Object.freeze(["--no-first-run", "--no-default-browser-check"]);
29
- /** Flag enabling headless mode on a launched browser process. */
29
+ /** Names the flag that enables headless mode on a launched browser process. */
30
30
  var BROWSER_HEADLESS_ARG = "--headless=new";
31
- /** Prefix for isolated browser profiles created beneath the operating-system temp directory. */
31
+ /** Names the prefix for isolated browser profiles created beneath the operating-system temp directory. */
32
32
  var BROWSER_PROFILE_PREFIX = "orkestrel-browser-";
33
- /** Bound for each launched-process exit window during TERM-to-KILL teardown. */
33
+ /** Bounds each launched-process exit window during TERM-to-KILL teardown. */
34
34
  var BROWSER_KILL_GRACE_MS = 3e3;
35
- /** 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. */
35
+ /** Bounds the `discover: false` port-occupancy probe before launching — short, because it only needs to detect an already-listening CDP endpoint, not perform full discovery. */
36
36
  var BROWSER_PORT_PROBE_TIMEOUT_MS = 200;
37
- /** 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. */
37
+ /** Defers once, briefly, 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. */
38
38
  var BROWSER_TRANSPORT_LOSS_DEFER_MS = 50;
39
- /** Machine-readable error-context cause for an owned browser process exiting. */
39
+ /** Names the machine-readable error-context cause for an owned browser process exiting. */
40
40
  var BROWSER_PROCESS_EXIT_CAUSE = "process-exit";
41
- /** Machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */
41
+ /** Names the machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */
42
42
  var BROWSER_TRANSPORT_LOSS_CAUSE = "transport-loss";
43
- /** Environment variables checked (in order) for an explicit browser executable path override. */
43
+ /** Lists the environment variables checked (in order) for an explicit browser executable path override. */
44
44
  var BROWSER_ENV_PATH_KEYS = Object.freeze(["PLAYWRIGHT_EXECUTABLE_PATH", "CHROME_PATH"]);
45
- /** Well-known Chrome/Chromium/Edge executable paths with no platform-specific root, keyed by `process.platform`. */
45
+ /** Lists the well-known Chrome/Chromium/Edge executable paths with no platform-specific root, keyed by `process.platform`. */
46
46
  var BROWSER_EXECUTABLE_PATHS = Object.freeze({
47
47
  linux: Object.freeze([
48
48
  "/usr/bin/google-chrome",
@@ -62,18 +62,18 @@ var BROWSER_EXECUTABLE_PATHS = Object.freeze({
62
62
  ]),
63
63
  win32: Object.freeze([])
64
64
  });
65
- /** Windows install-root-relative suffixes for Chrome/Edge/Chromium, joined against each candidate root (`PROGRAMFILES`, `PROGRAMFILES(X86)`, `LOCALAPPDATA`). */
65
+ /** Lists the Windows install-root-relative suffixes for Chrome/Edge/Chromium, joined against each candidate root (`PROGRAMFILES`, `PROGRAMFILES(X86)`, `LOCALAPPDATA`). */
66
66
  var BROWSER_WINDOWS_SUFFIXES = Object.freeze([
67
67
  "Google\\Chrome\\Application\\chrome.exe",
68
68
  "Microsoft\\Edge\\Application\\msedge.exe",
69
69
  "Chromium\\Application\\chrome.exe"
70
70
  ]);
71
- /** Fallback Windows install roots used when the corresponding environment variable is absent. */
71
+ /** Lists the fallback Windows install roots used when the corresponding environment variable is absent. */
72
72
  var BROWSER_WINDOWS_ROOT_FALLBACKS = Object.freeze({
73
73
  PROGRAMFILES: "C:\\Program Files",
74
74
  "PROGRAMFILES(X86)": "C:\\Program Files (x86)"
75
75
  });
76
- /** Command names probed on PATH when no well-known executable path exists. */
76
+ /** Lists the command names probed on PATH when no well-known executable path exists. */
77
77
  var BROWSER_EXECUTABLE_NAMES = Object.freeze([
78
78
  "google-chrome",
79
79
  "google-chrome-stable",
@@ -83,19 +83,19 @@ var BROWSER_EXECUTABLE_NAMES = Object.freeze([
83
83
  "chromium-browser",
84
84
  "chrome"
85
85
  ]);
86
- /** Environment variable naming an additional Playwright browser store base directory. */
86
+ /** Names the environment variable that carries an additional Playwright browser store base directory. */
87
87
  var BROWSER_STORE_ENV_KEY = "PLAYWRIGHT_BROWSERS_PATH";
88
- /** Well-known Playwright browser store base directories checked in addition to `PLAYWRIGHT_BROWSERS_PATH`. */
88
+ /** Lists the well-known Playwright browser store base directories checked in addition to `PLAYWRIGHT_BROWSERS_PATH`. */
89
89
  var BROWSER_STORE_DEFAULT_DIRS = Object.freeze(["/opt/pw-browsers"]);
90
- /** Per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */
90
+ /** Names the per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */
91
91
  var BROWSER_STORE_CACHE_DIRS = Object.freeze({
92
92
  linux: ".cache/ms-playwright",
93
93
  darwin: "Library/Caches/ms-playwright"
94
94
  });
95
- /** Name of the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */
95
+ /** Names the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */
96
96
  var BROWSER_STORE_LINK_NAME = "chromium";
97
97
  /**
98
- * Case-insensitive substrings identifying an executable path/name's browser
98
+ * Lists the case-insensitive substrings identifying an executable path/name's browser
99
99
  * engine, checked by `parseBrowserEngine` in the order `edge` → `chromium` → `chrome`.
100
100
  */
101
101
  var BROWSER_ENGINE_HINTS = Object.freeze({
@@ -119,7 +119,7 @@ var BROWSER_ENGINE_HINTS = Object.freeze({
119
119
  "chrome"
120
120
  ])
121
121
  });
122
- /** Glob pattern (relative to a store base) matching a versioned Chromium binary, keyed by `process.platform`. */
122
+ /** Names the glob pattern (relative to a store base) matching a versioned Chromium binary, keyed by `process.platform`. */
123
123
  var BROWSER_STORE_GLOBS = Object.freeze({
124
124
  linux: "chromium-*/chrome-linux*/chrome",
125
125
  darwin: "chromium-*/chrome-mac*/Chromium.app/Contents/MacOS/Chromium",
@@ -128,7 +128,7 @@ var BROWSER_STORE_GLOBS = Object.freeze({
128
128
  //#endregion
129
129
  //#region src/server/errors.ts
130
130
  /**
131
- * A CDP connection, discovery, or launch attempt failed.
131
+ * Reports that a CDP connection, discovery, or launch attempt failed.
132
132
  */
133
133
  var BrowserConnectionError = class extends _src_core.BrowserError {
134
134
  constructor(message, context) {
@@ -137,7 +137,7 @@ var BrowserConnectionError = class extends _src_core.BrowserError {
137
137
  }
138
138
  };
139
139
  /**
140
- * An operation requiring an active connection was attempted while disconnected.
140
+ * Reports that an operation requiring an active connection was attempted while disconnected.
141
141
  */
142
142
  var BrowserNotConnectedError = class extends _src_core.BrowserError {
143
143
  constructor(context) {
@@ -146,7 +146,7 @@ var BrowserNotConnectedError = class extends _src_core.BrowserError {
146
146
  }
147
147
  };
148
148
  /**
149
- * An operation was attempted after the Browser was destroyed.
149
+ * Reports that an operation was attempted after the Browser was destroyed.
150
150
  */
151
151
  var BrowserDestroyedError = class extends _src_core.BrowserError {
152
152
  constructor(context) {
@@ -155,28 +155,28 @@ var BrowserDestroyedError = class extends _src_core.BrowserError {
155
155
  }
156
156
  };
157
157
  /**
158
- * Narrow an unknown value to BrowserConnectionError.
158
+ * Narrows an unknown value to BrowserConnectionError.
159
159
  *
160
160
  * @param value - Value to check
161
- * @returns True when value is a BrowserConnectionError instance
161
+ * @returns True if value is a BrowserConnectionError instance; false otherwise
162
162
  */
163
163
  function isBrowserConnectionError(value) {
164
164
  return (0, _orkestrel_contract.isInstance)(value, BrowserConnectionError);
165
165
  }
166
166
  /**
167
- * Narrow an unknown value to BrowserNotConnectedError.
167
+ * Narrows an unknown value to BrowserNotConnectedError.
168
168
  *
169
169
  * @param value - Value to check
170
- * @returns True when value is a BrowserNotConnectedError instance
170
+ * @returns True if value is a BrowserNotConnectedError instance; false otherwise
171
171
  */
172
172
  function isBrowserNotConnectedError(value) {
173
173
  return (0, _orkestrel_contract.isInstance)(value, BrowserNotConnectedError);
174
174
  }
175
175
  /**
176
- * Narrow an unknown value to BrowserDestroyedError.
176
+ * Narrows an unknown value to BrowserDestroyedError.
177
177
  *
178
178
  * @param value - Value to check
179
- * @returns True when value is a BrowserDestroyedError instance
179
+ * @returns True if value is a BrowserDestroyedError instance; false otherwise
180
180
  */
181
181
  function isBrowserDestroyedError(value) {
182
182
  return (0, _orkestrel_contract.isInstance)(value, BrowserDestroyedError);
@@ -184,7 +184,7 @@ function isBrowserDestroyedError(value) {
184
184
  //#endregion
185
185
  //#region src/server/helpers.ts
186
186
  /**
187
- * Enumerate every Chrome/Chromium/Edge executable discoverable on this
187
+ * Enumerates every Chrome/Chromium/Edge executable discoverable on this
188
188
  * machine, deduplicated by normalized absolute path.
189
189
  *
190
190
  * @remarks
@@ -198,7 +198,7 @@ function isBrowserDestroyedError(value) {
198
198
  * and the per-OS Playwright cache directory) — the top-level `chromium`
199
199
  * link/binary, then the highest-revision `chromium-*` install found
200
200
  *
201
- * Each candidate is classified into a {@link BrowserEngine} via
201
+ * Each candidate is classified into a {@link BrowserEngine} through
202
202
  * `parseBrowserEngine` (unclassifiable candidates default to `'chromium'`),
203
203
  * and `options.engine` (when given) narrows the result to that engine.
204
204
  *
@@ -209,13 +209,13 @@ function findSystemBrowsers(options) {
209
209
  const platform = process.platform;
210
210
  const env = options?.env ?? process.env;
211
211
  const candidates = [];
212
- candidates.push(...findAllEnvOverrides(env));
213
- const paths = options?.paths ?? defaultInstallPaths(platform, env);
214
- candidates.push(...findAllInstallPaths(paths));
212
+ candidates.push(...findEnvOverrides(env));
213
+ const paths = options?.paths ?? buildInstallPaths(platform, env);
214
+ candidates.push(...findInstallPaths(paths));
215
215
  const names = options?.names ?? BROWSER_EXECUTABLE_NAMES;
216
- candidates.push(...probeAllPathNames(names, platform));
217
- const stores = options?.stores ?? defaultStoreBases(env, platform);
218
- for (const store of stores) candidates.push(...findAllInStore(store, platform));
216
+ candidates.push(...probePathNames(names, platform));
217
+ const stores = options?.stores ?? buildStoreBases(env, platform);
218
+ for (const store of stores) candidates.push(...findStorePaths(store, platform));
219
219
  const seen = /* @__PURE__ */ new Set();
220
220
  const browsers = [];
221
221
  for (const executable of candidates) {
@@ -232,7 +232,7 @@ function findSystemBrowsers(options) {
232
232
  return browsers;
233
233
  }
234
234
  /**
235
- * Locate a Chrome/Chromium/Edge executable on this machine — the first entry
235
+ * Locates a Chrome/Chromium/Edge executable on this machine — the first entry
236
236
  * of {@link findSystemBrowsers}.
237
237
  *
238
238
  * @param options - Overrides for the candidate sources; see {@link SystemBrowserOptions}
@@ -242,7 +242,7 @@ function findSystemBrowser(options) {
242
242
  return findSystemBrowsers(options)[0];
243
243
  }
244
244
  /**
245
- * Classify an executable path/name into a {@link BrowserEngine} by
245
+ * Classifies an executable path/name into a {@link BrowserEngine} by
246
246
  * case-insensitive hint, checked in the order edge → chromium → chrome.
247
247
  *
248
248
  * @param executable - Executable path or command name to classify
@@ -256,19 +256,19 @@ function parseBrowserEngine(executable) {
256
256
  "chrome"
257
257
  ]) if (BROWSER_ENGINE_HINTS[engine].some((hint) => lower.includes(hint))) return engine;
258
258
  }
259
- /** Normalize an executable path for cross-source deduplication (case-insensitive on Windows). */
259
+ /** Normalizes an executable path for cross-source deduplication (case-insensitive on Windows). */
260
260
  function normalizeExecutablePath(path, platform) {
261
261
  const normalized = platform === "win32" ? node_path.win32.normalize(path) : node_path.posix.normalize(path);
262
262
  return platform === "win32" ? normalized.toLowerCase() : normalized;
263
263
  }
264
- /** Classify a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */
264
+ /** Classifies a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */
265
265
  function browserToEngine(browser) {
266
266
  if (browser?.includes("Edg/") === true) return "edge";
267
267
  if (browser?.includes("Chrome/") === true) return "chrome";
268
268
  return "chromium";
269
269
  }
270
270
  /**
271
- * Resolve a persistent caller profile or create an isolated temporary one.
271
+ * Resolves a persistent caller profile or creates an isolated temporary one.
272
272
  *
273
273
  * @param path - Optional caller-owned persistent user-data directory
274
274
  * @returns The resolved profile and whether the library owns its lifecycle
@@ -284,7 +284,7 @@ async function createBrowserProfile(path) {
284
284
  };
285
285
  }
286
286
  /**
287
- * Remove a library-owned isolated browser profile.
287
+ * Removes a library-owned isolated browser profile.
288
288
  *
289
289
  * @remarks
290
290
  * The path must remain a direct child of the operating-system temp directory
@@ -297,7 +297,7 @@ async function removeBrowserProfile(profile) {
297
297
  if (!profile.temporary) return;
298
298
  const path = (0, node_path.resolve)(profile.path);
299
299
  const temporary = (0, node_path.resolve)((0, node_os.tmpdir)());
300
- if ((0, node_path.dirname)(path) !== temporary || !(0, node_path.basename)(path).startsWith("orkestrel-browser-")) throw new Error("Refusing to remove an unsafe browser profile path");
300
+ if ((0, node_path.dirname)(path) !== temporary || !(0, node_path.basename)(path).startsWith("orkestrel-browser-")) throw new _src_core.BrowserError("Refusing to remove an unsafe browser profile path", void 0, { path });
301
301
  await (0, node_fs_promises.rm)(path, {
302
302
  recursive: true,
303
303
  force: true,
@@ -305,12 +305,8 @@ async function removeBrowserProfile(profile) {
305
305
  retryDelay: 100
306
306
  });
307
307
  }
308
- /** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order for an existing file. */
309
- function findEnvOverride(env) {
310
- return findAllEnvOverrides(env)[0];
311
- }
312
- /** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order, returning every one that exists. */
313
- function findAllEnvOverrides(env) {
308
+ /** Checks the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order and returns every one that exists. */
309
+ function findEnvOverrides(env) {
314
310
  const found = [];
315
311
  for (const key of BROWSER_ENV_PATH_KEYS) {
316
312
  const value = env[key];
@@ -318,36 +314,28 @@ function findAllEnvOverrides(env) {
318
314
  }
319
315
  return found;
320
316
  }
321
- /** Build the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */
322
- function defaultInstallPaths(platform, env) {
317
+ /** Builds the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */
318
+ function buildInstallPaths(platform, env) {
323
319
  if (platform !== "win32") return BROWSER_EXECUTABLE_PATHS[platform] ?? [];
324
- const roots = windowsRoots(env);
320
+ const roots = buildWindowsRoots(env);
325
321
  const paths = [];
326
322
  for (const root of roots) for (const suffix of BROWSER_WINDOWS_SUFFIXES) paths.push(node_path.win32.join(root, suffix));
327
323
  return paths;
328
324
  }
329
- /** Derive Windows install roots from env vars, falling back to well-known literals when absent. */
330
- function windowsRoots(env) {
325
+ /** Derives Windows install roots from env vars, falling back to well-known literals when absent. */
326
+ function buildWindowsRoots(env) {
331
327
  return [
332
328
  env["PROGRAMFILES"] ?? BROWSER_WINDOWS_ROOT_FALLBACKS["PROGRAMFILES"],
333
329
  env["PROGRAMFILES(X86)"] ?? BROWSER_WINDOWS_ROOT_FALLBACKS["PROGRAMFILES(X86)"],
334
330
  env["LOCALAPPDATA"]
335
331
  ].filter((root) => root !== void 0);
336
332
  }
337
- /** Return the first candidate path that exists on disk. */
338
- function findInstallPath(paths) {
339
- return findAllInstallPaths(paths)[0];
340
- }
341
- /** Return every candidate path that exists on disk, in the given order. */
342
- function findAllInstallPaths(paths) {
333
+ /** Returns every candidate path that exists on disk, in the given order. */
334
+ function findInstallPaths(paths) {
343
335
  return paths.filter((path) => (0, node_fs.existsSync)(path));
344
336
  }
345
- /** Probe PATH (`which`/`where`) for the first resolvable command name. */
337
+ /** Probes PATH (`which`/`where`) for every resolvable command name, in the given order. */
346
338
  function probePathNames(names, platform) {
347
- return probeAllPathNames(names, platform)[0];
348
- }
349
- /** Probe PATH (`which`/`where`) for every resolvable command name, in the given order. */
350
- function probeAllPathNames(names, platform) {
351
339
  const finder = platform === "win32" ? "where" : "which";
352
340
  const found = [];
353
341
  for (const name of names) {
@@ -382,8 +370,8 @@ function readFirstLine(output) {
382
370
  if (text.length > 0) return text;
383
371
  }
384
372
  }
385
- /** Build the default Playwright browser store base directories to search for a managed Chromium. */
386
- function defaultStoreBases(env, platform) {
373
+ /** Builds the default Playwright browser store base directories to search for a managed Chromium. */
374
+ function buildStoreBases(env, platform) {
387
375
  const bases = [];
388
376
  const envBase = env[BROWSER_STORE_ENV_KEY];
389
377
  if (envBase !== void 0 && envBase.length > 0) bases.push(envBase);
@@ -398,12 +386,8 @@ function defaultStoreBases(env, platform) {
398
386
  }
399
387
  return bases;
400
388
  }
401
- /** Search one store base for the top-level `chromium` link, else the highest-revision `chromium-*` install. */
402
- function findInStore(base, platform) {
403
- return findAllInStore(base, platform)[0];
404
- }
405
- /** Search one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */
406
- function findAllInStore(base, platform) {
389
+ /** Searches one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */
390
+ function findStorePaths(base, platform) {
407
391
  const joiner = platform === "win32" ? node_path.win32.join : node_path.posix.join;
408
392
  const found = [];
409
393
  const linkPath = joiner(base, BROWSER_STORE_LINK_NAME);
@@ -417,7 +401,7 @@ function findAllInStore(base, platform) {
417
401
  return found;
418
402
  }
419
403
  /**
420
- * Launch a browser process with raw-CDP debugging flags.
404
+ * Launches a browser process with raw-CDP debugging flags.
421
405
  *
422
406
  * @remarks
423
407
  * POSIX launches own an isolated process group so lifecycle teardown can
@@ -447,11 +431,12 @@ function launchBrowserProcess(executable, port, headless, profile, extra) {
447
431
  });
448
432
  }
449
433
  /**
450
- * Poll a browser's CDP version endpoint until it responds or the timeout elapses.
434
+ * Polls a browser's CDP version endpoint until it responds or the timeout elapses.
451
435
  *
452
436
  * @param port - Port the browser exposes its CDP endpoint on
453
437
  * @param timeout - Maximum time to wait in milliseconds
454
438
  * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)
439
+ * @param signal - Optional external abort; an abort while waiting rethrows rather than resolving
455
440
  * @returns The browser's WebSocket debugger URL
456
441
  *
457
442
  * @throws When the endpoint does not become ready before the timeout
@@ -475,15 +460,33 @@ async function waitForCDPReady(port, timeout, host = BROWSER_DEFAULT_HOST, signa
475
460
  const delay = Math.min(_src_core.BROWSER_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()));
476
461
  if (delay > 0) await (0, node_timers_promises.setTimeout)(delay, void 0, { signal });
477
462
  }
478
- throw new Error(`CDP endpoint on port ${port} did not become ready within ${timeout}ms`);
463
+ throw new BrowserConnectionError(`CDP endpoint on port ${port} did not become ready within ${timeout}ms`, {
464
+ port,
465
+ timeout
466
+ });
479
467
  }
480
468
  /**
481
- * Fetch the current CDP target list from a browser's `/json/list` endpoint.
469
+ * Fetches the current CDP target list from a browser's `/json/list` endpoint.
470
+ *
471
+ * @remarks
472
+ * The endpoint is a network boundary, so an unreachable host, a non-2xx
473
+ * response, and a body that is not a JSON array each come back as a failed
474
+ * `Result` carrying a coded `BrowserConnectionError`. An entry missing a
475
+ * required string field is skipped rather than failing the whole list.
482
476
  *
483
477
  * @param port - Port the browser exposes its CDP endpoint on
484
478
  * @param timeout - Request timeout in milliseconds
485
479
  * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)
486
- * @returns Normalized CDP targets
480
+ * @returns The normalized CDP targets, or the fault that stopped the request
481
+ *
482
+ * @example
483
+ * ```ts
484
+ * import { fetchCDPTargets } from '@orkestrel/browser/server'
485
+ *
486
+ * const result = await fetchCDPTargets(9222, 2000)
487
+ * if (result.success) log(result.value.length)
488
+ * else log(result.error.code)
489
+ * ```
487
490
  */
488
491
  async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
489
492
  const url = `${BROWSER_CDP_PROTOCOL}://${host}:${port}${BROWSER_CDP_LIST_PATH}`;
@@ -491,23 +494,41 @@ async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
491
494
  const timer = setTimeout(() => controller.abort(), timeout);
492
495
  try {
493
496
  const response = await fetch(url, { signal: controller.signal });
494
- if (!response.ok) return [];
497
+ if (!response.ok) return {
498
+ success: false,
499
+ error: new BrowserConnectionError("CDP target list request was refused", {
500
+ url,
501
+ status: response.status
502
+ })
503
+ };
495
504
  const list = await response.json();
496
- if (!(0, _orkestrel_contract.isArray)(list)) return [];
505
+ if (!(0, _orkestrel_contract.isArray)(list)) return {
506
+ success: false,
507
+ error: new BrowserConnectionError("CDP target list is not a JSON array", { url })
508
+ };
497
509
  const targets = [];
498
510
  for (const entry of list) {
499
511
  if (!(0, _orkestrel_contract.isRecord)(entry)) continue;
500
512
  if (!(0, _orkestrel_contract.isString)(entry["id"]) || !(0, _orkestrel_contract.isString)(entry["type"]) || !(0, _orkestrel_contract.isString)(entry["title"]) || !(0, _orkestrel_contract.isString)(entry["url"])) continue;
501
513
  targets.push({
502
514
  id: entry["id"],
503
- type: entry["type"],
515
+ category: entry["type"],
504
516
  title: entry["title"],
505
517
  url: entry["url"]
506
518
  });
507
519
  }
508
- return targets;
509
- } catch {
510
- return [];
520
+ return {
521
+ success: true,
522
+ value: targets
523
+ };
524
+ } catch (error) {
525
+ return {
526
+ success: false,
527
+ error: new BrowserConnectionError("CDP target list is unreachable", {
528
+ url,
529
+ error
530
+ })
531
+ };
511
532
  } finally {
512
533
  clearTimeout(timer);
513
534
  }
@@ -515,27 +536,36 @@ async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
515
536
  //#endregion
516
537
  //#region src/server/transports/WebSocketCDPTransport.ts
517
538
  /**
518
- * `@orkestrel/websocket`-backed raw CDP text transport.
539
+ * Provides a raw CDP text transport backed by `@orkestrel/websocket`.
519
540
  *
520
541
  * @remarks
521
542
  * Performs and validates the RFC 6455 HTTP upgrade, then delegates frame
522
543
  * handling to `@orkestrel/websocket`. Concurrent and repeated `start()` /
523
544
  * `close()` calls share their active transition, and a later `start()` opens a
524
545
  * fresh socket after the prior one closes.
546
+ *
547
+ * @example
548
+ * ```ts
549
+ * import { WebSocketCDPTransport } from '@orkestrel/browser/server'
550
+ *
551
+ * const transport = new WebSocketCDPTransport({ url: 'ws://127.0.0.1:9222/devtools/browser/abc' })
552
+ * await transport.start()
553
+ * await transport.close()
554
+ * ```
525
555
  */
526
556
  var WebSocketCDPTransport = class {
527
557
  #emitter;
528
558
  #url;
529
559
  #timeout;
530
560
  #socket;
531
- #starting;
532
- #closing;
561
+ #starting = new _src_core.BrowserTransition();
562
+ #closing = new _src_core.BrowserTransition();
533
563
  #request;
534
564
  #resolve;
535
565
  #reject;
536
566
  #timer;
537
567
  #closeResolve;
538
- #onSocketClose = this.#handleSocketClose.bind(this);
568
+ #socketCloseHandler = this.#handleSocketClose.bind(this);
539
569
  constructor(options) {
540
570
  this.#emitter = new _orkestrel_emitter.Emitter({
541
571
  ...options.on !== void 0 ? { on: options.on } : {},
@@ -548,43 +578,27 @@ var WebSocketCDPTransport = class {
548
578
  return this.#emitter;
549
579
  }
550
580
  async start() {
551
- if (this.#closing !== void 0) await this.#closing;
581
+ const closing = this.#closing.pending;
582
+ if (closing !== void 0) await closing;
552
583
  if (this.#socket?.readyState === _orkestrel_websocket.WEBSOCKET_READY_OPEN) return;
553
- const active = this.#starting;
584
+ const active = this.#starting.pending;
554
585
  if (active !== void 0) {
555
586
  await active;
556
587
  return;
557
588
  }
558
589
  this.#socket?.destroy();
559
590
  this.#socket = void 0;
560
- const transition = this.#open();
561
- this.#starting = transition;
562
- try {
563
- await transition;
564
- } finally {
565
- if (this.#starting === transition) this.#starting = void 0;
566
- }
591
+ await this.#starting.execute(() => this.#start());
567
592
  }
568
593
  async send(data) {
569
594
  const socket = this.#socket;
570
- if (socket === void 0 || socket.readyState !== _orkestrel_websocket.WEBSOCKET_READY_OPEN) throw new Error("WebSocket CDP transport is not open");
595
+ if (socket === void 0 || socket.readyState !== _orkestrel_websocket.WEBSOCKET_READY_OPEN) throw new BrowserConnectionError("WebSocket CDP transport is not open", { url: this.#url });
571
596
  socket.send(data);
572
597
  }
573
598
  async close() {
574
- const active = this.#closing;
575
- if (active !== void 0) {
576
- await active;
577
- return;
578
- }
579
- const transition = this.#stop();
580
- this.#closing = transition;
581
- try {
582
- await transition;
583
- } finally {
584
- if (this.#closing === transition) this.#closing = void 0;
585
- }
599
+ await this.#closing.execute(() => this.#close());
586
600
  }
587
- async #open() {
601
+ async #start() {
588
602
  const parsed = (0, _orkestrel_contract.attempt)(() => new URL(this.#url));
589
603
  if (!parsed.success) throw new BrowserConnectionError(`WebSocket CDP URL is invalid: ${this.#url}`, {
590
604
  url: this.#url,
@@ -620,19 +634,19 @@ var WebSocketCDPTransport = class {
620
634
  this.#socket = socket;
621
635
  this.#bind(socket);
622
636
  }
623
- async #stop() {
637
+ async #close() {
624
638
  const request = this.#request;
625
639
  if (request !== void 0) {
626
640
  this.#rejectRequest(request, new BrowserConnectionError(`WebSocket CDP connection to ${this.#url} was closed before it finished connecting`, { url: this.#url }));
627
641
  request.destroy();
628
642
  }
629
- await this.#starting?.catch(() => void 0);
643
+ await this.#starting.pending?.catch(() => void 0);
630
644
  const socket = this.#socket;
631
645
  this.#socket = void 0;
632
646
  if (socket === void 0 || socket.readyState === _orkestrel_websocket.WEBSOCKET_READY_CLOSED) return;
633
647
  const closed = Promise.withResolvers();
634
648
  this.#closeResolve = closed.resolve;
635
- socket.emitter.on("close", this.#onSocketClose);
649
+ socket.emitter.on("close", this.#socketCloseHandler);
636
650
  try {
637
651
  socket.close();
638
652
  if (socket.readyState !== _orkestrel_websocket.WEBSOCKET_READY_CLOSED) await closed.promise;
@@ -640,7 +654,7 @@ var WebSocketCDPTransport = class {
640
654
  socket.destroy();
641
655
  if (socket.readyState !== _orkestrel_websocket.WEBSOCKET_READY_CLOSED) await closed.promise;
642
656
  } finally {
643
- socket.emitter.off("close", this.#onSocketClose);
657
+ socket.emitter.off("close", this.#socketCloseHandler);
644
658
  this.#closeResolve = void 0;
645
659
  }
646
660
  }
@@ -715,16 +729,46 @@ var WebSocketCDPTransport = class {
715
729
  }
716
730
  };
717
731
  //#endregion
732
+ //#region src/server/writers/FileBrowserWriter.ts
733
+ /**
734
+ * Persists captured browser bytes to the filesystem through `node:fs/promises`.
735
+ *
736
+ * @remarks
737
+ * Creates every missing parent directory of the target path before writing, so
738
+ * a caller may name a nested destination that does not exist yet.
739
+ *
740
+ * @example
741
+ * ```ts
742
+ * import { FileBrowserWriter } from '@orkestrel/browser/server'
743
+ *
744
+ * const writer = new FileBrowserWriter()
745
+ * await writer.write('shots/hero.png', new Uint8Array([137, 80, 78, 71]))
746
+ * ```
747
+ */
748
+ var FileBrowserWriter = class {
749
+ /**
750
+ * Writes the captured bytes to a path, creating its parent directories.
751
+ *
752
+ * @param path - Destination file path
753
+ * @param data - Captured bytes to persist
754
+ * @returns A promise resolving once the bytes are on disk
755
+ */
756
+ async write(path, data) {
757
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(path), { recursive: true });
758
+ await (0, node_fs_promises.writeFile)(path, data);
759
+ }
760
+ };
761
+ //#endregion
718
762
  //#region src/server/factories.ts
719
763
  /**
720
- * Create a raw-CDP Browser façade.
764
+ * Creates a raw-CDP Browser façade.
721
765
  *
722
766
  * @param options - Connection, launch, and viewport configuration
723
767
  * @returns A {@link BrowserInterface}
724
768
  *
725
769
  * @example
726
770
  * ```ts
727
- * import { createBrowser } from '@src/server'
771
+ * import { createBrowser } from '@orkestrel/browser/server'
728
772
  *
729
773
  * const browser = createBrowser()
730
774
  * await browser.connect()
@@ -734,7 +778,7 @@ function createBrowser(options) {
734
778
  return new Browser(options);
735
779
  }
736
780
  /**
737
- * Create a Node `WebSocket`-backed CDP transport.
781
+ * Creates a Node `WebSocket`-backed CDP transport.
738
782
  *
739
783
  * @param options - The CDP WebSocket debugger URL (and optional timeout)
740
784
  * @returns A {@link CDPTransportInterface}
@@ -743,20 +787,27 @@ function createCDPTransport(options) {
743
787
  return new WebSocketCDPTransport(options);
744
788
  }
745
789
  /**
746
- * Create a filesystem-backed screenshot writer.
790
+ * Creates a filesystem-backed browser writer.
747
791
  *
748
- * @returns A {@link ScreenshotWriterInterface} that persists bytes via `node:fs/promises`
792
+ * @returns A {@link BrowserWriterInterface} that persists bytes through `node:fs/promises`
749
793
  */
750
- function createScreenshotWriter() {
751
- return { async write(path, data) {
752
- await (0, node_fs_promises.mkdir)((0, node_path.dirname)(path), { recursive: true });
753
- await (0, node_fs_promises.writeFile)(path, data);
754
- } };
794
+ function createBrowserWriter() {
795
+ return new FileBrowserWriter();
755
796
  }
756
797
  //#endregion
757
798
  //#region src/server/Browser.ts
758
799
  /**
759
800
  * Discovers, launches, connects to, and owns Chromium-family browser sessions.
801
+ *
802
+ * @example
803
+ * ```ts
804
+ * import { Browser } from '@orkestrel/browser/server'
805
+ *
806
+ * const browser = new Browser({ headless: true })
807
+ * await browser.connect()
808
+ * const page = await browser.create({ url: 'https://example.com' })
809
+ * await browser.destroy()
810
+ * ```
760
811
  */
761
812
  var Browser = class {
762
813
  #emitter;
@@ -775,14 +826,14 @@ var Browser = class {
775
826
  #profile;
776
827
  #contexts = [];
777
828
  #destroyed = false;
778
- #connecting;
779
- #disconnecting;
829
+ #connecting = new _src_core.BrowserTransition();
830
+ #disconnecting = new _src_core.BrowserTransition();
780
831
  #exitCleanup;
781
832
  #shutdown;
782
833
  #transport;
783
- #onTransportClose = this.#handleTransportLoss.bind(this);
784
- #onTransportError = this.#handleTransportLoss.bind(this);
785
- #onProcessExit = this.#handleProcessExit.bind(this);
834
+ #transportCloseHandler = this.#handleTransportLoss.bind(this);
835
+ #transportErrorHandler = this.#handleTransportLoss.bind(this);
836
+ #processExitHandler = this.#handleProcessExit.bind(this);
786
837
  constructor(options) {
787
838
  this.#emitter = new _orkestrel_emitter.Emitter({
788
839
  ...options?.on !== void 0 ? { on: options.on } : {},
@@ -809,9 +860,6 @@ var Browser = class {
809
860
  get owned() {
810
861
  return this.#owned;
811
862
  }
812
- get connected() {
813
- return this.#status === "connected";
814
- }
815
863
  get pid() {
816
864
  return this.#servingPid ?? this.#process?.pid;
817
865
  }
@@ -822,19 +870,13 @@ var Browser = class {
822
870
  }
823
871
  async connect() {
824
872
  if (this.#destroyed) throw new BrowserDestroyedError();
825
- const active = this.#connecting;
873
+ const active = this.#connecting.pending;
826
874
  if (active !== void 0) {
827
875
  await active;
828
876
  return;
829
877
  }
830
878
  if (this.#status === "connected") return;
831
- const attempt = this.#establish();
832
- this.#connecting = attempt;
833
- try {
834
- await attempt;
835
- } finally {
836
- if (this.#connecting === attempt) this.#connecting = void 0;
837
- }
879
+ await this.#connecting.execute(() => this.#establish());
838
880
  }
839
881
  adopt() {
840
882
  if (this.#destroyed) throw new BrowserDestroyedError();
@@ -843,19 +885,13 @@ var Browser = class {
843
885
  }
844
886
  async disconnect() {
845
887
  if (this.#destroyed) return;
846
- const disconnecting = this.#disconnecting;
847
- const connecting = this.#connecting;
888
+ const disconnecting = this.#disconnecting.pending;
889
+ const connecting = this.#connecting.pending;
848
890
  if (disconnecting !== void 0) await disconnecting;
849
891
  if (connecting !== void 0) await connecting.catch(() => void 0);
850
892
  if (this.#destroyed) return;
851
893
  if (this.#status !== "connected" || this.#client === void 0) return;
852
- const attempt = this.#detach();
853
- this.#disconnecting = attempt;
854
- try {
855
- await attempt;
856
- } finally {
857
- if (this.#disconnecting === attempt) this.#disconnecting = void 0;
858
- }
894
+ await this.#disconnecting.execute(() => this.#detach());
859
895
  }
860
896
  context(index) {
861
897
  const i = index ?? 0;
@@ -879,7 +915,7 @@ var Browser = class {
879
915
  const result = await client.send("Target.createBrowserContext", params);
880
916
  if (!(0, _orkestrel_contract.isRecord)(result) || !(0, _orkestrel_contract.isString)(result["browserContextId"])) throw new BrowserConnectionError("Failed to create isolated browser context");
881
917
  const id = result["browserContextId"];
882
- const context = new _src_core.BrowserContext(client, id, options?.emulation?.viewport ?? this.#options.viewport, createScreenshotWriter(), options?.emulation, options?.downloads);
918
+ const context = new _src_core.BrowserContext(client, id, options?.emulation?.viewport ?? this.#options.viewport, createBrowserWriter(), options?.emulation, options?.downloads, options);
883
919
  try {
884
920
  if (options?.downloads !== void 0) await client.send("Browser.setDownloadBehavior", {
885
921
  behavior: options.downloads.named === true ? "allowAndName" : "allow",
@@ -900,7 +936,7 @@ var Browser = class {
900
936
  if (this.#status !== "connected" || client === void 0) throw new BrowserNotConnectedError();
901
937
  let context = this.#contexts[0];
902
938
  if (context === void 0) {
903
- context = new _src_core.BrowserContext(client, void 0, this.#options.viewport, createScreenshotWriter());
939
+ context = new _src_core.BrowserContext(client, void 0, this.#options.viewport, createBrowserWriter());
904
940
  this.#registerContext(context);
905
941
  }
906
942
  const page = await context.create(options);
@@ -928,7 +964,8 @@ var Browser = class {
928
964
  return shutdown;
929
965
  }
930
966
  async #establish() {
931
- if (this.#disconnecting !== void 0) await this.#disconnecting;
967
+ const disconnecting = this.#disconnecting.pending;
968
+ if (disconnecting !== void 0) await disconnecting;
932
969
  await this.#settleExit();
933
970
  if (this.#destroyed) throw new BrowserDestroyedError();
934
971
  if (this.#status === "connected") return;
@@ -946,7 +983,7 @@ var Browser = class {
946
983
  }
947
984
  if (this.#options.cdp?.discover ?? true) {
948
985
  const discovery = await this.#raceAbort(this.#discoverCDP(this.#signal()));
949
- if (discovery.found && discovery.endpoint !== void 0) {
986
+ if (discovery.endpoint !== void 0) {
950
987
  this.#engine = browserToEngine(discovery.browser);
951
988
  await this.#connectCDP(discovery.endpoint);
952
989
  return;
@@ -1064,24 +1101,24 @@ var Browser = class {
1064
1101
  #bindTransport(transport) {
1065
1102
  this.#unbindTransport();
1066
1103
  this.#transport = transport;
1067
- transport.emitter.on("close", this.#onTransportClose);
1068
- transport.emitter.on("error", this.#onTransportError);
1104
+ transport.emitter.on("close", this.#transportCloseHandler);
1105
+ transport.emitter.on("error", this.#transportErrorHandler);
1069
1106
  }
1070
1107
  #unbindTransport() {
1071
1108
  const transport = this.#transport;
1072
1109
  if (transport === void 0) return;
1073
- transport.emitter.off("close", this.#onTransportClose);
1074
- transport.emitter.off("error", this.#onTransportError);
1110
+ transport.emitter.off("close", this.#transportCloseHandler);
1111
+ transport.emitter.off("error", this.#transportErrorHandler);
1075
1112
  this.#transport = void 0;
1076
1113
  }
1077
1114
  #bindProcess(process) {
1078
1115
  this.#unbindProcess();
1079
1116
  if (this.#servingPid !== void 0) return;
1080
- process.once("exit", this.#onProcessExit);
1081
- if (process.exitCode !== null || process.signalCode !== null) queueMicrotask(this.#onProcessExit);
1117
+ process.once("exit", this.#processExitHandler);
1118
+ if (process.exitCode !== null || process.signalCode !== null) queueMicrotask(this.#processExitHandler);
1082
1119
  }
1083
1120
  #unbindProcess() {
1084
- this.#process?.off("exit", this.#onProcessExit);
1121
+ this.#process?.off("exit", this.#processExitHandler);
1085
1122
  }
1086
1123
  #timeout() {
1087
1124
  return this.#options.timeout ?? _src_core.BROWSER_DEFAULT_TIMEOUT_MS;
@@ -1094,13 +1131,9 @@ var Browser = class {
1094
1131
  if (!response.ok) return this.#notFound();
1095
1132
  const info = await response.json();
1096
1133
  if (!(0, _orkestrel_contract.isRecord)(info)) return this.#notFound();
1097
- const endpoint = (0, _orkestrel_contract.isString)(info["webSocketDebuggerUrl"]) ? info["webSocketDebuggerUrl"] : void 0;
1098
- const browser = (0, _orkestrel_contract.isString)(info["Browser"]) ? info["Browser"] : void 0;
1099
1134
  return {
1100
- found: endpoint !== void 0,
1101
- endpoint,
1102
- browser,
1103
- connection: endpoint !== void 0 ? "cdp" : void 0
1135
+ endpoint: (0, _orkestrel_contract.isString)(info["webSocketDebuggerUrl"]) ? info["webSocketDebuggerUrl"] : void 0,
1136
+ browser: (0, _orkestrel_contract.isString)(info["Browser"]) ? info["Browser"] : void 0
1104
1137
  };
1105
1138
  } catch (error) {
1106
1139
  if (signal?.aborted === true) throw error;
@@ -1109,10 +1142,8 @@ var Browser = class {
1109
1142
  }
1110
1143
  #notFound() {
1111
1144
  return {
1112
- found: false,
1113
1145
  endpoint: void 0,
1114
- browser: void 0,
1115
- connection: void 0
1146
+ browser: void 0
1116
1147
  };
1117
1148
  }
1118
1149
  async #assertPortFree() {
@@ -1313,13 +1344,13 @@ var Browser = class {
1313
1344
  if (!(0, _orkestrel_contract.isRecord)(target) || !(0, _orkestrel_contract.isString)(target["targetId"]) || target["type"] !== "page" || !(0, _orkestrel_contract.isString)(target["title"]) || !(0, _orkestrel_contract.isString)(target["url"])) continue;
1314
1345
  pages.push({
1315
1346
  id: target["targetId"],
1316
- type: target["type"],
1347
+ category: target["type"],
1317
1348
  title: target["title"],
1318
1349
  url: target["url"]
1319
1350
  });
1320
1351
  }
1321
1352
  if (pages.length === 0 || this.#contexts.length > 0) return;
1322
- const context = new _src_core.BrowserContext(client, void 0, this.#options.viewport, createScreenshotWriter());
1353
+ const context = new _src_core.BrowserContext(client, void 0, this.#options.viewport, createBrowserWriter());
1323
1354
  await context.sync(pages);
1324
1355
  this.#registerContext(context);
1325
1356
  }
@@ -1383,8 +1414,8 @@ var Browser = class {
1383
1414
  }
1384
1415
  }
1385
1416
  async #settle() {
1386
- await this.#connecting?.catch(() => void 0);
1387
- await this.#disconnecting?.catch(() => void 0);
1417
+ await this.#connecting.pending?.catch(() => void 0);
1418
+ await this.#disconnecting.pending?.catch(() => void 0);
1388
1419
  await this.#settleExit();
1389
1420
  }
1390
1421
  async #settleExit() {
@@ -1578,21 +1609,20 @@ exports.Browser = Browser;
1578
1609
  exports.BrowserConnectionError = BrowserConnectionError;
1579
1610
  exports.BrowserDestroyedError = BrowserDestroyedError;
1580
1611
  exports.BrowserNotConnectedError = BrowserNotConnectedError;
1612
+ exports.FileBrowserWriter = FileBrowserWriter;
1581
1613
  exports.WebSocketCDPTransport = WebSocketCDPTransport;
1582
1614
  exports.browserToEngine = browserToEngine;
1615
+ exports.buildInstallPaths = buildInstallPaths;
1616
+ exports.buildStoreBases = buildStoreBases;
1617
+ exports.buildWindowsRoots = buildWindowsRoots;
1583
1618
  exports.createBrowser = createBrowser;
1584
1619
  exports.createBrowserProfile = createBrowserProfile;
1620
+ exports.createBrowserWriter = createBrowserWriter;
1585
1621
  exports.createCDPTransport = createCDPTransport;
1586
- exports.createScreenshotWriter = createScreenshotWriter;
1587
- exports.defaultInstallPaths = defaultInstallPaths;
1588
- exports.defaultStoreBases = defaultStoreBases;
1589
1622
  exports.fetchCDPTargets = fetchCDPTargets;
1590
- exports.findAllEnvOverrides = findAllEnvOverrides;
1591
- exports.findAllInStore = findAllInStore;
1592
- exports.findAllInstallPaths = findAllInstallPaths;
1593
- exports.findEnvOverride = findEnvOverride;
1594
- exports.findInStore = findInStore;
1595
- exports.findInstallPath = findInstallPath;
1623
+ exports.findEnvOverrides = findEnvOverrides;
1624
+ exports.findInstallPaths = findInstallPaths;
1625
+ exports.findStorePaths = findStorePaths;
1596
1626
  exports.findSystemBrowser = findSystemBrowser;
1597
1627
  exports.findSystemBrowsers = findSystemBrowsers;
1598
1628
  exports.isBrowserConnectionError = isBrowserConnectionError;
@@ -1601,11 +1631,9 @@ exports.isBrowserNotConnectedError = isBrowserNotConnectedError;
1601
1631
  exports.launchBrowserProcess = launchBrowserProcess;
1602
1632
  exports.normalizeExecutablePath = normalizeExecutablePath;
1603
1633
  exports.parseBrowserEngine = parseBrowserEngine;
1604
- exports.probeAllPathNames = probeAllPathNames;
1605
1634
  exports.probePathNames = probePathNames;
1606
1635
  exports.readFirstLine = readFirstLine;
1607
1636
  exports.removeBrowserProfile = removeBrowserProfile;
1608
1637
  exports.waitForCDPReady = waitForCDPReady;
1609
- exports.windowsRoots = windowsRoots;
1610
1638
 
1611
1639
  //# sourceMappingURL=index.cjs.map