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