@orkestrel/browser 0.0.14 → 0.0.16

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,75 @@ 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
+ /**
17
+ * Sets the default CDP port probed for an existing browser and used for launches, `9222`.
18
+ */
17
19
  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`). */
20
+ /**
21
+ * Sets the default host probed for an existing browser and used for launches, `'127.0.0.1'`,
22
+ * which avoids `localhost` resolving to `::1` when Chromium binds `127.0.0.1`.
23
+ */
19
24
  var BROWSER_DEFAULT_HOST = "127.0.0.1";
20
- /** Protocol prefix for CDP discovery requests. */
25
+ /** Names the protocol prefix for CDP discovery requests, `'http'`. */
21
26
  var BROWSER_CDP_PROTOCOL = "http";
22
- /** Path appended to the CDP host to fetch version metadata (endpoint discovery). */
27
+ /**
28
+ * Names the path appended to the CDP host to fetch version metadata, `'/json/version'`, which
29
+ * is where endpoint discovery reads.
30
+ */
23
31
  var BROWSER_CDP_VERSION_PATH = "/json/version";
24
- /** Path appended to the CDP host to list open targets (pages, workers, etc). */
32
+ /**
33
+ * Names the path appended to the CDP host to list open targets — pages, workers, and every
34
+ * other target category Chromium reports — `'/json/list'`.
35
+ */
25
36
  var BROWSER_CDP_LIST_PATH = "/json/list";
26
- /** Flags always passed to a launched browser process, alongside the caller's own. */
37
+ /** Lists the flags always passed to a launched browser process, alongside the caller's own. */
27
38
  var BROWSER_LAUNCH_ARGS = Object.freeze(["--no-first-run", "--no-default-browser-check"]);
28
- /** Flag enabling headless mode on a launched browser process. */
39
+ /**
40
+ * Names the flag that enables headless mode on a launched browser process, `'--headless=new'`.
41
+ */
29
42
  var BROWSER_HEADLESS_ARG = "--headless=new";
30
- /** Prefix for isolated browser profiles created beneath the operating-system temp directory. */
43
+ /**
44
+ * Names the prefix for isolated browser profiles created beneath the operating-system temp
45
+ * directory, `'orkestrel-browser-'`.
46
+ */
31
47
  var BROWSER_PROFILE_PREFIX = "orkestrel-browser-";
32
- /** Bound for each launched-process exit window during TERM-to-KILL teardown. */
48
+ /**
49
+ * Bounds each launched-process exit window during TERM-to-KILL teardown at `3_000`
50
+ * milliseconds.
51
+ */
33
52
  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. */
53
+ /**
54
+ * Bounds the `discover: false` port-occupancy probe before launching at `200` milliseconds,
55
+ * which is short because the probe only needs to detect an already-listening CDP endpoint
56
+ * rather than perform full discovery.
57
+ */
35
58
  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. */
59
+ /**
60
+ * Defers once for `50` milliseconds when a transport loss is observed on an owned process,
61
+ * giving a near-simultaneous process-exit event, which libuv may reap slightly later than the
62
+ * socket close, first say over the diagnosis.
63
+ */
37
64
  var BROWSER_TRANSPORT_LOSS_DEFER_MS = 50;
38
- /** Machine-readable error-context cause for an owned browser process exiting. */
65
+ /**
66
+ * Names the machine-readable error-context cause for an owned browser process exiting,
67
+ * `'process-exit'`.
68
+ */
39
69
  var BROWSER_PROCESS_EXIT_CAUSE = "process-exit";
40
- /** Machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */
70
+ /**
71
+ * Names the machine-readable error-context cause for a CDP transport disconnecting while its
72
+ * browser remains alive, `'transport-loss'`.
73
+ */
41
74
  var BROWSER_TRANSPORT_LOSS_CAUSE = "transport-loss";
42
- /** Environment variables checked (in order) for an explicit browser executable path override. */
75
+ /**
76
+ * Lists the environment variables checked, in order, for an explicit browser executable path
77
+ * override: `PLAYWRIGHT_EXECUTABLE_PATH`, then `CHROME_PATH`.
78
+ */
43
79
  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`. */
80
+ /**
81
+ * Lists the well-known Chrome/Chromium/Edge executable paths with no platform-specific root,
82
+ * keyed by `process.platform`, leaving `win32` empty because its roots come from
83
+ * `BROWSER_WINDOWS_SUFFIXES`.
84
+ */
45
85
  var BROWSER_EXECUTABLE_PATHS = Object.freeze({
46
86
  linux: Object.freeze([
47
87
  "/usr/bin/google-chrome",
@@ -61,18 +101,21 @@ var BROWSER_EXECUTABLE_PATHS = Object.freeze({
61
101
  ]),
62
102
  win32: Object.freeze([])
63
103
  });
64
- /** Windows install-root-relative suffixes for Chrome/Edge/Chromium, joined against each candidate root (`PROGRAMFILES`, `PROGRAMFILES(X86)`, `LOCALAPPDATA`). */
104
+ /** Lists the Windows install-root-relative suffixes for Chrome/Edge/Chromium, joined against each candidate root (`PROGRAMFILES`, `PROGRAMFILES(X86)`, `LOCALAPPDATA`). */
65
105
  var BROWSER_WINDOWS_SUFFIXES = Object.freeze([
66
106
  "Google\\Chrome\\Application\\chrome.exe",
67
107
  "Microsoft\\Edge\\Application\\msedge.exe",
68
108
  "Chromium\\Application\\chrome.exe"
69
109
  ]);
70
- /** Fallback Windows install roots used when the corresponding environment variable is absent. */
110
+ /**
111
+ * Lists the fallback Windows install roots used when `PROGRAMFILES`, `PROGRAMFILES(X86)`, or
112
+ * `LOCALAPPDATA` is absent.
113
+ */
71
114
  var BROWSER_WINDOWS_ROOT_FALLBACKS = Object.freeze({
72
115
  PROGRAMFILES: "C:\\Program Files",
73
116
  "PROGRAMFILES(X86)": "C:\\Program Files (x86)"
74
117
  });
75
- /** Command names probed on PATH when no well-known executable path exists. */
118
+ /** Lists the command names probed on PATH when no well-known executable path exists. */
76
119
  var BROWSER_EXECUTABLE_NAMES = Object.freeze([
77
120
  "google-chrome",
78
121
  "google-chrome-stable",
@@ -82,19 +125,28 @@ var BROWSER_EXECUTABLE_NAMES = Object.freeze([
82
125
  "chromium-browser",
83
126
  "chrome"
84
127
  ]);
85
- /** Environment variable naming an additional Playwright browser store base directory. */
128
+ /**
129
+ * Names the environment variable that carries an additional Playwright browser store base
130
+ * directory, `'PLAYWRIGHT_BROWSERS_PATH'`.
131
+ */
86
132
  var BROWSER_STORE_ENV_KEY = "PLAYWRIGHT_BROWSERS_PATH";
87
- /** Well-known Playwright browser store base directories checked in addition to `PLAYWRIGHT_BROWSERS_PATH`. */
133
+ /**
134
+ * Lists the well-known Playwright browser store base directories checked in addition to
135
+ * `PLAYWRIGHT_BROWSERS_PATH`, starting with `/opt/pw-browsers`.
136
+ */
88
137
  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). */
138
+ /** Names the per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */
90
139
  var BROWSER_STORE_CACHE_DIRS = Object.freeze({
91
140
  linux: ".cache/ms-playwright",
92
141
  darwin: "Library/Caches/ms-playwright"
93
142
  });
94
- /** Name of the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */
143
+ /**
144
+ * Names the top-level Chromium symlink or binary Playwright maintains inside a browser store
145
+ * base, `'chromium'`.
146
+ */
95
147
  var BROWSER_STORE_LINK_NAME = "chromium";
96
148
  /**
97
- * Case-insensitive substrings identifying an executable path/name's browser
149
+ * Lists the case-insensitive substrings identifying an executable path/name's browser
98
150
  * engine, checked by `parseBrowserEngine` in the order `edge` → `chromium` → `chrome`.
99
151
  */
100
152
  var BROWSER_ENGINE_HINTS = Object.freeze({
@@ -118,7 +170,7 @@ var BROWSER_ENGINE_HINTS = Object.freeze({
118
170
  "chrome"
119
171
  ])
120
172
  });
121
- /** Glob pattern (relative to a store base) matching a versioned Chromium binary, keyed by `process.platform`. */
173
+ /** Names the glob pattern (relative to a store base) matching a versioned Chromium binary, keyed by `process.platform`. */
122
174
  var BROWSER_STORE_GLOBS = Object.freeze({
123
175
  linux: "chromium-*/chrome-linux*/chrome",
124
176
  darwin: "chromium-*/chrome-mac*/Chromium.app/Contents/MacOS/Chromium",
@@ -127,7 +179,8 @@ var BROWSER_STORE_GLOBS = Object.freeze({
127
179
  //#endregion
128
180
  //#region src/server/errors.ts
129
181
  /**
130
- * A CDP connection, discovery, or launch attempt failed.
182
+ * Reports that a CDP connection, discovery, or launch attempt failed, under the code
183
+ * `BROWSER_CONNECTION_ERROR`.
131
184
  */
132
185
  var BrowserConnectionError = class extends BrowserError {
133
186
  constructor(message, context) {
@@ -136,7 +189,8 @@ var BrowserConnectionError = class extends BrowserError {
136
189
  }
137
190
  };
138
191
  /**
139
- * An operation requiring an active connection was attempted while disconnected.
192
+ * Reports that an operation requiring an active connection was attempted while disconnected,
193
+ * under the code `BROWSER_NOT_CONNECTED_ERROR`.
140
194
  */
141
195
  var BrowserNotConnectedError = class extends BrowserError {
142
196
  constructor(context) {
@@ -145,7 +199,8 @@ var BrowserNotConnectedError = class extends BrowserError {
145
199
  }
146
200
  };
147
201
  /**
148
- * An operation was attempted after the Browser was destroyed.
202
+ * Reports that an operation was attempted after the browser wrapper was destroyed, under the
203
+ * code `BROWSER_DESTROYED_ERROR`.
149
204
  */
150
205
  var BrowserDestroyedError = class extends BrowserError {
151
206
  constructor(context) {
@@ -154,28 +209,28 @@ var BrowserDestroyedError = class extends BrowserError {
154
209
  }
155
210
  };
156
211
  /**
157
- * Narrow an unknown value to BrowserConnectionError.
212
+ * Narrows an unknown value to a `BrowserConnectionError`.
158
213
  *
159
214
  * @param value - Value to check
160
- * @returns True when value is a BrowserConnectionError instance
215
+ * @returns True if value is a BrowserConnectionError instance; false otherwise
161
216
  */
162
217
  function isBrowserConnectionError(value) {
163
218
  return isInstance(value, BrowserConnectionError);
164
219
  }
165
220
  /**
166
- * Narrow an unknown value to BrowserNotConnectedError.
221
+ * Narrows an unknown value to a `BrowserNotConnectedError`.
167
222
  *
168
223
  * @param value - Value to check
169
- * @returns True when value is a BrowserNotConnectedError instance
224
+ * @returns True if value is a BrowserNotConnectedError instance; false otherwise
170
225
  */
171
226
  function isBrowserNotConnectedError(value) {
172
227
  return isInstance(value, BrowserNotConnectedError);
173
228
  }
174
229
  /**
175
- * Narrow an unknown value to BrowserDestroyedError.
230
+ * Narrows an unknown value to a `BrowserDestroyedError`.
176
231
  *
177
232
  * @param value - Value to check
178
- * @returns True when value is a BrowserDestroyedError instance
233
+ * @returns True if value is a BrowserDestroyedError instance; false otherwise
179
234
  */
180
235
  function isBrowserDestroyedError(value) {
181
236
  return isInstance(value, BrowserDestroyedError);
@@ -183,7 +238,7 @@ function isBrowserDestroyedError(value) {
183
238
  //#endregion
184
239
  //#region src/server/helpers.ts
185
240
  /**
186
- * Enumerate every Chrome/Chromium/Edge executable discoverable on this
241
+ * Enumerates every Chrome/Chromium/Edge executable discoverable on this
187
242
  * machine, deduplicated by normalized absolute path.
188
243
  *
189
244
  * @remarks
@@ -197,7 +252,7 @@ function isBrowserDestroyedError(value) {
197
252
  * and the per-OS Playwright cache directory) — the top-level `chromium`
198
253
  * link/binary, then the highest-revision `chromium-*` install found
199
254
  *
200
- * Each candidate is classified into a {@link BrowserEngine} via
255
+ * Each candidate is classified into a {@link BrowserEngine} through
201
256
  * `parseBrowserEngine` (unclassifiable candidates default to `'chromium'`),
202
257
  * and `options.engine` (when given) narrows the result to that engine.
203
258
  *
@@ -208,13 +263,13 @@ function findSystemBrowsers(options) {
208
263
  const platform = process.platform;
209
264
  const env = options?.env ?? process.env;
210
265
  const candidates = [];
211
- candidates.push(...findAllEnvOverrides(env));
212
- const paths = options?.paths ?? defaultInstallPaths(platform, env);
213
- candidates.push(...findAllInstallPaths(paths));
266
+ candidates.push(...findEnvOverrides(env));
267
+ const paths = options?.paths ?? buildInstallPaths(platform, env);
268
+ candidates.push(...findInstallPaths(paths));
214
269
  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));
270
+ candidates.push(...probePathNames(names, platform));
271
+ const stores = options?.stores ?? buildStoreBases(env, platform);
272
+ for (const store of stores) candidates.push(...findStorePaths(store, platform));
218
273
  const seen = /* @__PURE__ */ new Set();
219
274
  const browsers = [];
220
275
  for (const executable of candidates) {
@@ -231,7 +286,7 @@ function findSystemBrowsers(options) {
231
286
  return browsers;
232
287
  }
233
288
  /**
234
- * Locate a Chrome/Chromium/Edge executable on this machine — the first entry
289
+ * Locates a Chrome/Chromium/Edge executable on this machine — the first entry
235
290
  * of {@link findSystemBrowsers}.
236
291
  *
237
292
  * @param options - Overrides for the candidate sources; see {@link SystemBrowserOptions}
@@ -241,7 +296,7 @@ function findSystemBrowser(options) {
241
296
  return findSystemBrowsers(options)[0];
242
297
  }
243
298
  /**
244
- * Classify an executable path/name into a {@link BrowserEngine} by
299
+ * Classifies an executable path/name into a {@link BrowserEngine} by
245
300
  * case-insensitive hint, checked in the order edge → chromium → chrome.
246
301
  *
247
302
  * @param executable - Executable path or command name to classify
@@ -255,19 +310,19 @@ function parseBrowserEngine(executable) {
255
310
  "chrome"
256
311
  ]) if (BROWSER_ENGINE_HINTS[engine].some((hint) => lower.includes(hint))) return engine;
257
312
  }
258
- /** Normalize an executable path for cross-source deduplication (case-insensitive on Windows). */
313
+ /** Normalizes an executable path for cross-source deduplication (case-insensitive on Windows). */
259
314
  function normalizeExecutablePath(path, platform) {
260
315
  const normalized = platform === "win32" ? win32.normalize(path) : posix.normalize(path);
261
316
  return platform === "win32" ? normalized.toLowerCase() : normalized;
262
317
  }
263
- /** Classify a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */
318
+ /** Classifies a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */
264
319
  function browserToEngine(browser) {
265
320
  if (browser?.includes("Edg/") === true) return "edge";
266
321
  if (browser?.includes("Chrome/") === true) return "chrome";
267
322
  return "chromium";
268
323
  }
269
324
  /**
270
- * Resolve a persistent caller profile or create an isolated temporary one.
325
+ * Resolves a persistent caller profile or creates an isolated temporary one.
271
326
  *
272
327
  * @param path - Optional caller-owned persistent user-data directory
273
328
  * @returns The resolved profile and whether the library owns its lifecycle
@@ -283,7 +338,7 @@ async function createBrowserProfile(path) {
283
338
  };
284
339
  }
285
340
  /**
286
- * Remove a library-owned isolated browser profile.
341
+ * Removes a library-owned isolated browser profile.
287
342
  *
288
343
  * @remarks
289
344
  * The path must remain a direct child of the operating-system temp directory
@@ -296,7 +351,7 @@ async function removeBrowserProfile(profile) {
296
351
  if (!profile.temporary) return;
297
352
  const path = resolve(profile.path);
298
353
  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");
354
+ if (dirname(path) !== temporary || !basename(path).startsWith("orkestrel-browser-")) throw new BrowserError("Refusing to remove an unsafe browser profile path", void 0, { path });
300
355
  await rm(path, {
301
356
  recursive: true,
302
357
  force: true,
@@ -304,12 +359,8 @@ async function removeBrowserProfile(profile) {
304
359
  retryDelay: 100
305
360
  });
306
361
  }
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) {
362
+ /** Checks the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order and returns every one that exists. */
363
+ function findEnvOverrides(env) {
313
364
  const found = [];
314
365
  for (const key of BROWSER_ENV_PATH_KEYS) {
315
366
  const value = env[key];
@@ -317,36 +368,28 @@ function findAllEnvOverrides(env) {
317
368
  }
318
369
  return found;
319
370
  }
320
- /** Build the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */
321
- function defaultInstallPaths(platform, env) {
371
+ /** Builds the default well-known install-path candidates for a platform, deriving Windows roots from env vars. */
372
+ function buildInstallPaths(platform, env) {
322
373
  if (platform !== "win32") return BROWSER_EXECUTABLE_PATHS[platform] ?? [];
323
- const roots = windowsRoots(env);
374
+ const roots = buildWindowsRoots(env);
324
375
  const paths = [];
325
376
  for (const root of roots) for (const suffix of BROWSER_WINDOWS_SUFFIXES) paths.push(win32.join(root, suffix));
326
377
  return paths;
327
378
  }
328
- /** Derive Windows install roots from env vars, falling back to well-known literals when absent. */
329
- function windowsRoots(env) {
379
+ /** Derives Windows install roots from env vars, falling back to well-known literals when absent. */
380
+ function buildWindowsRoots(env) {
330
381
  return [
331
382
  env["PROGRAMFILES"] ?? BROWSER_WINDOWS_ROOT_FALLBACKS["PROGRAMFILES"],
332
383
  env["PROGRAMFILES(X86)"] ?? BROWSER_WINDOWS_ROOT_FALLBACKS["PROGRAMFILES(X86)"],
333
384
  env["LOCALAPPDATA"]
334
385
  ].filter((root) => root !== void 0);
335
386
  }
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) {
387
+ /** Returns every candidate path that exists on disk, in the given order. */
388
+ function findInstallPaths(paths) {
342
389
  return paths.filter((path) => existsSync(path));
343
390
  }
344
- /** Probe PATH (`which`/`where`) for the first resolvable command name. */
391
+ /** Probes PATH (`which`/`where`) for every resolvable command name, in the given order. */
345
392
  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
393
  const finder = platform === "win32" ? "where" : "which";
351
394
  const found = [];
352
395
  for (const name of names) {
@@ -381,8 +424,8 @@ function readFirstLine(output) {
381
424
  if (text.length > 0) return text;
382
425
  }
383
426
  }
384
- /** Build the default Playwright browser store base directories to search for a managed Chromium. */
385
- function defaultStoreBases(env, platform) {
427
+ /** Builds the default Playwright browser store base directories to search for a managed Chromium. */
428
+ function buildStoreBases(env, platform) {
386
429
  const bases = [];
387
430
  const envBase = env[BROWSER_STORE_ENV_KEY];
388
431
  if (envBase !== void 0 && envBase.length > 0) bases.push(envBase);
@@ -397,12 +440,8 @@ function defaultStoreBases(env, platform) {
397
440
  }
398
441
  return bases;
399
442
  }
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) {
443
+ /** Searches one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. */
444
+ function findStorePaths(base, platform) {
406
445
  const joiner = platform === "win32" ? win32.join : posix.join;
407
446
  const found = [];
408
447
  const linkPath = joiner(base, BROWSER_STORE_LINK_NAME);
@@ -416,7 +455,7 @@ function findAllInStore(base, platform) {
416
455
  return found;
417
456
  }
418
457
  /**
419
- * Launch a browser process with raw-CDP debugging flags.
458
+ * Launches a browser process with raw-CDP debugging flags.
420
459
  *
421
460
  * @remarks
422
461
  * POSIX launches own an isolated process group so lifecycle teardown can
@@ -446,11 +485,12 @@ function launchBrowserProcess(executable, port, headless, profile, extra) {
446
485
  });
447
486
  }
448
487
  /**
449
- * Poll a browser's CDP version endpoint until it responds or the timeout elapses.
488
+ * Polls a browser's CDP version endpoint until it responds or the timeout elapses.
450
489
  *
451
490
  * @param port - Port the browser exposes its CDP endpoint on
452
491
  * @param timeout - Maximum time to wait in milliseconds
453
492
  * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)
493
+ * @param signal - Optional external abort; an abort while waiting rethrows rather than resolving
454
494
  * @returns The browser's WebSocket debugger URL
455
495
  *
456
496
  * @throws When the endpoint does not become ready before the timeout
@@ -474,15 +514,34 @@ async function waitForCDPReady(port, timeout, host = BROWSER_DEFAULT_HOST, signa
474
514
  const delay = Math.min(BROWSER_WAIT_POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()));
475
515
  if (delay > 0) await setTimeout$1(delay, void 0, { signal });
476
516
  }
477
- throw new Error(`CDP endpoint on port ${port} did not become ready within ${timeout}ms`);
517
+ throw new BrowserConnectionError(`CDP endpoint on port ${port} did not become ready within ${timeout}ms`, {
518
+ port,
519
+ timeout
520
+ });
478
521
  }
479
522
  /**
480
- * Fetch the current CDP target list from a browser's `/json/list` endpoint.
523
+ * Fetches the current CDP target list from a browser's `/json/list` endpoint, as a `Result`
524
+ * carrying either the targets or a coded `BrowserConnectionError`.
525
+ *
526
+ * @remarks
527
+ * The endpoint is a network boundary, so an unreachable host, a non-2xx
528
+ * response, and a body that is not a JSON array each come back as a failed
529
+ * `Result` carrying a coded `BrowserConnectionError`. An entry missing a
530
+ * required string field is skipped rather than failing the whole list.
481
531
  *
482
532
  * @param port - Port the browser exposes its CDP endpoint on
483
533
  * @param timeout - Request timeout in milliseconds
484
534
  * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)
485
- * @returns Normalized CDP targets
535
+ * @returns The normalized CDP targets, or the fault that stopped the request
536
+ *
537
+ * @example
538
+ * ```ts
539
+ * import { fetchCDPTargets } from '@orkestrel/browser/server'
540
+ *
541
+ * const result = await fetchCDPTargets(9222, 2000)
542
+ * if (result.success) log(result.value.length)
543
+ * else log(result.error.code)
544
+ * ```
486
545
  */
487
546
  async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
488
547
  const url = `${BROWSER_CDP_PROTOCOL}://${host}:${port}${BROWSER_CDP_LIST_PATH}`;
@@ -490,23 +549,41 @@ async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
490
549
  const timer = setTimeout(() => controller.abort(), timeout);
491
550
  try {
492
551
  const response = await fetch(url, { signal: controller.signal });
493
- if (!response.ok) return [];
552
+ if (!response.ok) return {
553
+ success: false,
554
+ error: new BrowserConnectionError("CDP target list request was refused", {
555
+ url,
556
+ status: response.status
557
+ })
558
+ };
494
559
  const list = await response.json();
495
- if (!isArray(list)) return [];
560
+ if (!isArray(list)) return {
561
+ success: false,
562
+ error: new BrowserConnectionError("CDP target list is not a JSON array", { url })
563
+ };
496
564
  const targets = [];
497
565
  for (const entry of list) {
498
566
  if (!isRecord(entry)) continue;
499
567
  if (!isString(entry["id"]) || !isString(entry["type"]) || !isString(entry["title"]) || !isString(entry["url"])) continue;
500
568
  targets.push({
501
569
  id: entry["id"],
502
- type: entry["type"],
570
+ category: entry["type"],
503
571
  title: entry["title"],
504
572
  url: entry["url"]
505
573
  });
506
574
  }
507
- return targets;
508
- } catch {
509
- return [];
575
+ return {
576
+ success: true,
577
+ value: targets
578
+ };
579
+ } catch (error) {
580
+ return {
581
+ success: false,
582
+ error: new BrowserConnectionError("CDP target list is unreachable", {
583
+ url,
584
+ error
585
+ })
586
+ };
510
587
  } finally {
511
588
  clearTimeout(timer);
512
589
  }
@@ -514,27 +591,36 @@ async function fetchCDPTargets(port, timeout, host = BROWSER_DEFAULT_HOST) {
514
591
  //#endregion
515
592
  //#region src/server/transports/WebSocketCDPTransport.ts
516
593
  /**
517
- * `@orkestrel/websocket`-backed raw CDP text transport.
594
+ * Provides a raw CDP text transport backed by `@orkestrel/websocket`.
518
595
  *
519
596
  * @remarks
520
597
  * Performs and validates the RFC 6455 HTTP upgrade, then delegates frame
521
598
  * handling to `@orkestrel/websocket`. Concurrent and repeated `start()` /
522
599
  * `close()` calls share their active transition, and a later `start()` opens a
523
600
  * fresh socket after the prior one closes.
601
+ *
602
+ * @example
603
+ * ```ts
604
+ * import { WebSocketCDPTransport } from '@orkestrel/browser/server'
605
+ *
606
+ * const transport = new WebSocketCDPTransport({ url: 'ws://127.0.0.1:9222/devtools/browser/abc' })
607
+ * await transport.start()
608
+ * await transport.close()
609
+ * ```
524
610
  */
525
611
  var WebSocketCDPTransport = class {
526
612
  #emitter;
527
613
  #url;
528
614
  #timeout;
529
615
  #socket;
530
- #starting;
531
- #closing;
616
+ #starting = new BrowserTransition();
617
+ #closing = new BrowserTransition();
532
618
  #request;
533
619
  #resolve;
534
620
  #reject;
535
621
  #timer;
536
622
  #closeResolve;
537
- #onSocketClose = this.#handleSocketClose.bind(this);
623
+ #socketCloseHandler = this.#handleSocketClose.bind(this);
538
624
  constructor(options) {
539
625
  this.#emitter = new Emitter({
540
626
  ...options.on !== void 0 ? { on: options.on } : {},
@@ -547,43 +633,27 @@ var WebSocketCDPTransport = class {
547
633
  return this.#emitter;
548
634
  }
549
635
  async start() {
550
- if (this.#closing !== void 0) await this.#closing;
636
+ const closing = this.#closing.pending;
637
+ if (closing !== void 0) await closing;
551
638
  if (this.#socket?.readyState === WEBSOCKET_READY_OPEN) return;
552
- const active = this.#starting;
639
+ const active = this.#starting.pending;
553
640
  if (active !== void 0) {
554
641
  await active;
555
642
  return;
556
643
  }
557
644
  this.#socket?.destroy();
558
645
  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
- }
646
+ await this.#starting.execute(() => this.#start());
566
647
  }
567
648
  async send(data) {
568
649
  const socket = this.#socket;
569
- if (socket === void 0 || socket.readyState !== WEBSOCKET_READY_OPEN) throw new Error("WebSocket CDP transport is not open");
650
+ if (socket === void 0 || socket.readyState !== WEBSOCKET_READY_OPEN) throw new BrowserConnectionError("WebSocket CDP transport is not open", { url: this.#url });
570
651
  socket.send(data);
571
652
  }
572
653
  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
- }
654
+ await this.#closing.execute(() => this.#close());
585
655
  }
586
- async #open() {
656
+ async #start() {
587
657
  const parsed = attempt(() => new URL(this.#url));
588
658
  if (!parsed.success) throw new BrowserConnectionError(`WebSocket CDP URL is invalid: ${this.#url}`, {
589
659
  url: this.#url,
@@ -619,19 +689,19 @@ var WebSocketCDPTransport = class {
619
689
  this.#socket = socket;
620
690
  this.#bind(socket);
621
691
  }
622
- async #stop() {
692
+ async #close() {
623
693
  const request = this.#request;
624
694
  if (request !== void 0) {
625
695
  this.#rejectRequest(request, new BrowserConnectionError(`WebSocket CDP connection to ${this.#url} was closed before it finished connecting`, { url: this.#url }));
626
696
  request.destroy();
627
697
  }
628
- await this.#starting?.catch(() => void 0);
698
+ await this.#starting.pending?.catch(() => void 0);
629
699
  const socket = this.#socket;
630
700
  this.#socket = void 0;
631
701
  if (socket === void 0 || socket.readyState === WEBSOCKET_READY_CLOSED) return;
632
702
  const closed = Promise.withResolvers();
633
703
  this.#closeResolve = closed.resolve;
634
- socket.emitter.on("close", this.#onSocketClose);
704
+ socket.emitter.on("close", this.#socketCloseHandler);
635
705
  try {
636
706
  socket.close();
637
707
  if (socket.readyState !== WEBSOCKET_READY_CLOSED) await closed.promise;
@@ -639,7 +709,7 @@ var WebSocketCDPTransport = class {
639
709
  socket.destroy();
640
710
  if (socket.readyState !== WEBSOCKET_READY_CLOSED) await closed.promise;
641
711
  } finally {
642
- socket.emitter.off("close", this.#onSocketClose);
712
+ socket.emitter.off("close", this.#socketCloseHandler);
643
713
  this.#closeResolve = void 0;
644
714
  }
645
715
  }
@@ -714,26 +784,61 @@ var WebSocketCDPTransport = class {
714
784
  }
715
785
  };
716
786
  //#endregion
787
+ //#region src/server/writers/FileBrowserWriter.ts
788
+ /**
789
+ * Persists captured browser bytes to the filesystem through `node:fs/promises`.
790
+ *
791
+ * @remarks
792
+ * Creates every missing parent directory of the target path before writing, so
793
+ * a caller may name a nested destination that does not exist yet.
794
+ *
795
+ * @example
796
+ * ```ts
797
+ * import { FileBrowserWriter } from '@orkestrel/browser/server'
798
+ *
799
+ * const writer = new FileBrowserWriter()
800
+ * await writer.write('shots/hero.png', new Uint8Array([137, 80, 78, 71]))
801
+ * ```
802
+ */
803
+ var FileBrowserWriter = class {
804
+ /**
805
+ * Writes the captured bytes to a path, creating its parent directories.
806
+ *
807
+ * @param path - Destination file path
808
+ * @param data - Captured bytes to persist
809
+ * @returns A promise resolving once the bytes are on disk
810
+ */
811
+ async write(path, data) {
812
+ await mkdir(dirname(path), { recursive: true });
813
+ await writeFile(path, data);
814
+ }
815
+ };
816
+ //#endregion
717
817
  //#region src/server/factories.ts
718
818
  /**
719
- * Create a raw-CDP Browser façade.
819
+ * Creates a raw-CDP `BrowserInterface` façade with discovery, connection, and lifecycle
820
+ * management.
720
821
  *
721
822
  * @param options - Connection, launch, and viewport configuration
722
823
  * @returns A {@link BrowserInterface}
723
824
  *
724
- * @example
825
+ * @example Connect to a browser and drive a page
725
826
  * ```ts
726
- * import { createBrowser } from '@src/server'
827
+ * import { createBrowser } from '@orkestrel/browser/server'
727
828
  *
728
- * const browser = createBrowser()
729
- * await browser.connect()
829
+ * const browser = createBrowser({ headless: true })
830
+ * await browser.connect() // CDP endpoint discovery → connect, else launch
831
+ * const page = await browser.create({ url: 'https://example.com' })
832
+ * await page.click('#accept')
833
+ * const shot = await page.screenshot({ path: './out.png' })
834
+ * await browser.destroy()
730
835
  * ```
731
836
  */
732
837
  function createBrowser(options) {
733
838
  return new Browser(options);
734
839
  }
735
840
  /**
736
- * Create a Node `WebSocket`-backed CDP transport.
841
+ * Creates a Node `WebSocket`-backed `CDPTransportInterface` for the given CDP debugger URL.
737
842
  *
738
843
  * @param options - The CDP WebSocket debugger URL (and optional timeout)
739
844
  * @returns A {@link CDPTransportInterface}
@@ -742,20 +847,28 @@ function createCDPTransport(options) {
742
847
  return new WebSocketCDPTransport(options);
743
848
  }
744
849
  /**
745
- * Create a filesystem-backed screenshot writer.
850
+ * Creates a filesystem-backed `BrowserWriterInterface` that persists bytes through
851
+ * `node:fs/promises`.
746
852
  *
747
- * @returns A {@link ScreenshotWriterInterface} that persists bytes via `node:fs/promises`
853
+ * @returns A {@link BrowserWriterInterface} that persists bytes through `node:fs/promises`
748
854
  */
749
- function createScreenshotWriter() {
750
- return { async write(path, data) {
751
- await mkdir(dirname(path), { recursive: true });
752
- await writeFile(path, data);
753
- } };
855
+ function createBrowserWriter() {
856
+ return new FileBrowserWriter();
754
857
  }
755
858
  //#endregion
756
859
  //#region src/server/Browser.ts
757
860
  /**
758
861
  * Discovers, launches, connects to, and owns Chromium-family browser sessions.
862
+ *
863
+ * @example
864
+ * ```ts
865
+ * import { Browser } from '@orkestrel/browser/server'
866
+ *
867
+ * const browser = new Browser({ headless: true })
868
+ * await browser.connect()
869
+ * const page = await browser.create({ url: 'https://example.com' })
870
+ * await browser.destroy()
871
+ * ```
759
872
  */
760
873
  var Browser = class {
761
874
  #emitter;
@@ -774,14 +887,14 @@ var Browser = class {
774
887
  #profile;
775
888
  #contexts = [];
776
889
  #destroyed = false;
777
- #connecting;
778
- #disconnecting;
890
+ #connecting = new BrowserTransition();
891
+ #disconnecting = new BrowserTransition();
779
892
  #exitCleanup;
780
893
  #shutdown;
781
894
  #transport;
782
- #onTransportClose = this.#handleTransportLoss.bind(this);
783
- #onTransportError = this.#handleTransportLoss.bind(this);
784
- #onProcessExit = this.#handleProcessExit.bind(this);
895
+ #transportCloseHandler = this.#handleTransportLoss.bind(this);
896
+ #transportErrorHandler = this.#handleTransportLoss.bind(this);
897
+ #processExitHandler = this.#handleProcessExit.bind(this);
785
898
  constructor(options) {
786
899
  this.#emitter = new Emitter({
787
900
  ...options?.on !== void 0 ? { on: options.on } : {},
@@ -808,9 +921,6 @@ var Browser = class {
808
921
  get owned() {
809
922
  return this.#owned;
810
923
  }
811
- get connected() {
812
- return this.#status === "connected";
813
- }
814
924
  get pid() {
815
925
  return this.#servingPid ?? this.#process?.pid;
816
926
  }
@@ -821,19 +931,13 @@ var Browser = class {
821
931
  }
822
932
  async connect() {
823
933
  if (this.#destroyed) throw new BrowserDestroyedError();
824
- const active = this.#connecting;
934
+ const active = this.#connecting.pending;
825
935
  if (active !== void 0) {
826
936
  await active;
827
937
  return;
828
938
  }
829
939
  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
- }
940
+ await this.#connecting.execute(() => this.#establish());
837
941
  }
838
942
  adopt() {
839
943
  if (this.#destroyed) throw new BrowserDestroyedError();
@@ -842,19 +946,13 @@ var Browser = class {
842
946
  }
843
947
  async disconnect() {
844
948
  if (this.#destroyed) return;
845
- const disconnecting = this.#disconnecting;
846
- const connecting = this.#connecting;
949
+ const disconnecting = this.#disconnecting.pending;
950
+ const connecting = this.#connecting.pending;
847
951
  if (disconnecting !== void 0) await disconnecting;
848
952
  if (connecting !== void 0) await connecting.catch(() => void 0);
849
953
  if (this.#destroyed) return;
850
954
  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
- }
955
+ await this.#disconnecting.execute(() => this.#detach());
858
956
  }
859
957
  context(index) {
860
958
  const i = index ?? 0;
@@ -878,7 +976,7 @@ var Browser = class {
878
976
  const result = await client.send("Target.createBrowserContext", params);
879
977
  if (!isRecord(result) || !isString(result["browserContextId"])) throw new BrowserConnectionError("Failed to create isolated browser context");
880
978
  const id = result["browserContextId"];
881
- const context = new BrowserContext(client, id, options?.emulation?.viewport ?? this.#options.viewport, createScreenshotWriter(), options?.emulation, options?.downloads);
979
+ const context = new BrowserContext(client, id, options?.emulation?.viewport ?? this.#options.viewport, createBrowserWriter(), options?.emulation, options?.downloads, options);
882
980
  try {
883
981
  if (options?.downloads !== void 0) await client.send("Browser.setDownloadBehavior", {
884
982
  behavior: options.downloads.named === true ? "allowAndName" : "allow",
@@ -899,7 +997,7 @@ var Browser = class {
899
997
  if (this.#status !== "connected" || client === void 0) throw new BrowserNotConnectedError();
900
998
  let context = this.#contexts[0];
901
999
  if (context === void 0) {
902
- context = new BrowserContext(client, void 0, this.#options.viewport, createScreenshotWriter());
1000
+ context = new BrowserContext(client, void 0, this.#options.viewport, createBrowserWriter());
903
1001
  this.#registerContext(context);
904
1002
  }
905
1003
  const page = await context.create(options);
@@ -927,7 +1025,8 @@ var Browser = class {
927
1025
  return shutdown;
928
1026
  }
929
1027
  async #establish() {
930
- if (this.#disconnecting !== void 0) await this.#disconnecting;
1028
+ const disconnecting = this.#disconnecting.pending;
1029
+ if (disconnecting !== void 0) await disconnecting;
931
1030
  await this.#settleExit();
932
1031
  if (this.#destroyed) throw new BrowserDestroyedError();
933
1032
  if (this.#status === "connected") return;
@@ -945,7 +1044,7 @@ var Browser = class {
945
1044
  }
946
1045
  if (this.#options.cdp?.discover ?? true) {
947
1046
  const discovery = await this.#raceAbort(this.#discoverCDP(this.#signal()));
948
- if (discovery.found && discovery.endpoint !== void 0) {
1047
+ if (discovery.endpoint !== void 0) {
949
1048
  this.#engine = browserToEngine(discovery.browser);
950
1049
  await this.#connectCDP(discovery.endpoint);
951
1050
  return;
@@ -1063,24 +1162,24 @@ var Browser = class {
1063
1162
  #bindTransport(transport) {
1064
1163
  this.#unbindTransport();
1065
1164
  this.#transport = transport;
1066
- transport.emitter.on("close", this.#onTransportClose);
1067
- transport.emitter.on("error", this.#onTransportError);
1165
+ transport.emitter.on("close", this.#transportCloseHandler);
1166
+ transport.emitter.on("error", this.#transportErrorHandler);
1068
1167
  }
1069
1168
  #unbindTransport() {
1070
1169
  const transport = this.#transport;
1071
1170
  if (transport === void 0) return;
1072
- transport.emitter.off("close", this.#onTransportClose);
1073
- transport.emitter.off("error", this.#onTransportError);
1171
+ transport.emitter.off("close", this.#transportCloseHandler);
1172
+ transport.emitter.off("error", this.#transportErrorHandler);
1074
1173
  this.#transport = void 0;
1075
1174
  }
1076
1175
  #bindProcess(process) {
1077
1176
  this.#unbindProcess();
1078
1177
  if (this.#servingPid !== void 0) return;
1079
- process.once("exit", this.#onProcessExit);
1080
- if (process.exitCode !== null || process.signalCode !== null) queueMicrotask(this.#onProcessExit);
1178
+ process.once("exit", this.#processExitHandler);
1179
+ if (process.exitCode !== null || process.signalCode !== null) queueMicrotask(this.#processExitHandler);
1081
1180
  }
1082
1181
  #unbindProcess() {
1083
- this.#process?.off("exit", this.#onProcessExit);
1182
+ this.#process?.off("exit", this.#processExitHandler);
1084
1183
  }
1085
1184
  #timeout() {
1086
1185
  return this.#options.timeout ?? BROWSER_DEFAULT_TIMEOUT_MS;
@@ -1093,13 +1192,9 @@ var Browser = class {
1093
1192
  if (!response.ok) return this.#notFound();
1094
1193
  const info = await response.json();
1095
1194
  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
1195
  return {
1099
- found: endpoint !== void 0,
1100
- endpoint,
1101
- browser,
1102
- connection: endpoint !== void 0 ? "cdp" : void 0
1196
+ endpoint: isString(info["webSocketDebuggerUrl"]) ? info["webSocketDebuggerUrl"] : void 0,
1197
+ browser: isString(info["Browser"]) ? info["Browser"] : void 0
1103
1198
  };
1104
1199
  } catch (error) {
1105
1200
  if (signal?.aborted === true) throw error;
@@ -1108,10 +1203,8 @@ var Browser = class {
1108
1203
  }
1109
1204
  #notFound() {
1110
1205
  return {
1111
- found: false,
1112
1206
  endpoint: void 0,
1113
- browser: void 0,
1114
- connection: void 0
1207
+ browser: void 0
1115
1208
  };
1116
1209
  }
1117
1210
  async #assertPortFree() {
@@ -1312,13 +1405,13 @@ var Browser = class {
1312
1405
  if (!isRecord(target) || !isString(target["targetId"]) || target["type"] !== "page" || !isString(target["title"]) || !isString(target["url"])) continue;
1313
1406
  pages.push({
1314
1407
  id: target["targetId"],
1315
- type: target["type"],
1408
+ category: target["type"],
1316
1409
  title: target["title"],
1317
1410
  url: target["url"]
1318
1411
  });
1319
1412
  }
1320
1413
  if (pages.length === 0 || this.#contexts.length > 0) return;
1321
- const context = new BrowserContext(client, void 0, this.#options.viewport, createScreenshotWriter());
1414
+ const context = new BrowserContext(client, void 0, this.#options.viewport, createBrowserWriter());
1322
1415
  await context.sync(pages);
1323
1416
  this.#registerContext(context);
1324
1417
  }
@@ -1382,8 +1475,8 @@ var Browser = class {
1382
1475
  }
1383
1476
  }
1384
1477
  async #settle() {
1385
- await this.#connecting?.catch(() => void 0);
1386
- await this.#disconnecting?.catch(() => void 0);
1478
+ await this.#connecting.pending?.catch(() => void 0);
1479
+ await this.#disconnecting.pending?.catch(() => void 0);
1387
1480
  await this.#settleExit();
1388
1481
  }
1389
1482
  async #settleExit() {
@@ -1549,6 +1642,6 @@ var Browser = class {
1549
1642
  }
1550
1643
  };
1551
1644
  //#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 };
1645
+ 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
1646
 
1554
1647
  //# sourceMappingURL=index.js.map