@orkestrel/browser 0.0.3 → 0.0.6

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,17 +1,23 @@
1
1
  import { BrowserContextInterface } from '../core/index.ts';
2
+ import { BrowserContextOptions } from '../core/index.ts';
2
3
  import { BrowserError } from '../core/index.ts';
3
4
  import { BrowserPageInterface } from '../core/index.ts';
4
5
  import { BrowserPageOptions } from '../core/index.ts';
5
6
  import { BrowserViewport } from '../core/index.ts';
6
7
  import { CDPTarget } from '../core/index.ts';
7
- import { CDPTransportEventMap } from '../../core/index.ts';
8
+ import { CDPTransportEventMap } from '../core/index.ts';
9
+ import { CDPTransportEventMap as CDPTransportEventMap_2 } from '../../core/index.ts';
8
10
  import { CDPTransportInterface } from '../../core/index.ts';
9
11
  import { CDPTransportInterface as CDPTransportInterface_2 } from '../core/index.ts';
10
12
  import { ChildProcess } from 'node:child_process';
13
+ import { EmitterErrorHandler } from '@orkestrel/emitter';
11
14
  import { EmitterHooks } from '@orkestrel/emitter';
12
15
  import { EmitterInterface } from '@orkestrel/emitter';
13
16
  import { ScreenshotWriterInterface } from '../core/index.ts';
14
17
 
18
+ /**
19
+ * Discovers, launches, connects to, and owns Chromium-family browser sessions.
20
+ */
15
21
  export declare class Browser implements BrowserInterface {
16
22
  #private;
17
23
  constructor(options?: BrowserOptions);
@@ -19,25 +25,18 @@ export declare class Browser implements BrowserInterface {
19
25
  get engine(): BrowserEngine;
20
26
  get status(): BrowserStatus;
21
27
  get connection(): BrowserConnection | undefined;
28
+ get owned(): boolean | undefined;
22
29
  get connected(): boolean;
23
30
  get pid(): number | undefined;
24
31
  discover(): Promise<BrowserDiscoveryResult>;
25
32
  connect(): Promise<void>;
33
+ adopt(): void;
26
34
  disconnect(): Promise<void>;
27
35
  context(index?: number): BrowserContextInterface | undefined;
28
36
  contexts(): readonly BrowserContextInterface[];
37
+ isolate(options?: BrowserContextOptions): Promise<BrowserContextInterface>;
29
38
  create(options?: BrowserPageOptions): Promise<BrowserPageInterface>;
30
39
  destroy(): Promise<void>;
31
- /**
32
- * Gracefully shut down the remote browser, whether this instance owns its
33
- * process or merely attached to it via CDP.
34
- *
35
- * @remarks
36
- * Sends CDP `Browser.close` best-effort; on an owned browser also awaits
37
- * the process's exit (bounded by the kill-escalation grace period,
38
- * escalating to a kill only if it does not exit in time). Ends in the
39
- * same local-cleanup state as `destroy()`.
40
- */
41
40
  close(): Promise<void>;
42
41
  }
43
42
 
@@ -80,12 +79,15 @@ export declare const BROWSER_KILL_GRACE_MS = 3000;
80
79
  /** Flags always passed to a launched browser process, alongside the caller's own. */
81
80
  export declare const BROWSER_LAUNCH_ARGS: readonly string[];
82
81
 
83
- /** Sentinel result returned by discovery when no browser is reachable. */
84
- export declare const BROWSER_NOT_FOUND_RESULT: BrowserDiscoveryResult;
85
-
86
82
  /** 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. */
87
83
  export declare const BROWSER_PORT_PROBE_TIMEOUT_MS = 200;
88
84
 
85
+ /** Machine-readable error-context cause for an owned browser process exiting. */
86
+ export declare const BROWSER_PROCESS_EXIT_CAUSE = "process-exit";
87
+
88
+ /** Prefix for isolated browser profiles created beneath the operating-system temp directory. */
89
+ export declare const BROWSER_PROFILE_PREFIX = "orkestrel-browser-";
90
+
89
91
  /** Per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */
90
92
  export declare const BROWSER_STORE_CACHE_DIRS: Readonly<Record<string, string>>;
91
93
 
@@ -101,6 +103,9 @@ export declare const BROWSER_STORE_GLOBS: Readonly<Record<string, string>>;
101
103
  /** Name of the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */
102
104
  export declare const BROWSER_STORE_LINK_NAME = "chromium";
103
105
 
106
+ /** Machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */
107
+ export declare const BROWSER_TRANSPORT_LOSS_CAUSE = "transport-loss";
108
+
104
109
  /** 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. */
105
110
  export declare const BROWSER_TRANSPORT_LOSS_DEFER_MS = 50;
106
111
 
@@ -125,7 +130,7 @@ export declare const BROWSER_WINDOWS_SUFFIXES: readonly string[];
125
130
  * listening there, so a demanded fresh launch never silently attaches to a
126
131
  * stranger browser
127
132
  */
128
- export declare interface BrowserCdpOptions {
133
+ export declare interface BrowserCDPOptions {
129
134
  readonly port?: number;
130
135
  readonly host?: string;
131
136
  readonly endpoint?: string;
@@ -193,6 +198,7 @@ export declare type BrowserEventMap = {
193
198
  readonly disconnect: readonly [];
194
199
  readonly launch: readonly [engine: BrowserEngine];
195
200
  readonly page: readonly [page: BrowserPageInterface];
201
+ readonly context: readonly [context: BrowserContextInterface];
196
202
  readonly error: readonly [error: unknown];
197
203
  readonly destroy: readonly [];
198
204
  };
@@ -215,22 +221,19 @@ export declare type BrowserEventMap = {
215
221
  * **Lifecycle:**
216
222
  * - `discover` — passive CDP probe, no side effects
217
223
  * - `connect` — establish connection using the strategy above
218
- * - `disconnect` — detach from the browser. For `'cdp'` and `'persistent'`
219
- * connections this closes the client WITHOUT killing the browser process —
220
- * a `'persistent'` (profile-backed) launch releases ownership of its process
221
- * (no kill, no exit listener) so the browser stays alive for later
222
- * reattachment via CDP discovery on the same port. Rejects with the coded
223
- * `BrowserConnectionError` for `'launch'` (ephemeral, no profile) sessions —
224
- * use `destroy()` instead. An external disconnect (transport loss while the
225
- * owned process is still alive, or the owned process exiting on its own)
226
- * drives this same released/disconnected state automatically, preceded by
224
+ * - `adopt` — explicitly assume responsibility for terminating the connected
225
+ * browser, including a browser this instance attached to over CDP
226
+ * - `disconnect` — detach from the browser. For attached CDP connections this
227
+ * closes only the client. For owned launches and adopted connections, it
228
+ * retains ownership and the endpoint so the same instance can reconnect
229
+ * and remains responsible for eventual termination. An external disconnect
230
+ * (transport loss while the owned process is still alive, or the owned
231
+ * process exiting on its own) drives the disconnected state, preceded by
227
232
  * a coded `error` — `connect()` on the same instance can reattach afterward.
228
- * - `destroy` — release local resources. On an owned (`'launch'`/`'persistent'`)
229
- * browser this closes pages/contexts, then kills the process (SIGTERM,
230
- * escalating to SIGKILL). On a `'cdp'`-attached browser this is a LOCAL
231
- * DETACH ONLY — the client is closed and local context/page objects are
232
- * dropped WITHOUT sending any remote close to the browser, since other
233
- * clients may share those targets. Idempotent.
233
+ * - `destroy` — release local resources. On a launched browser this closes
234
+ * pages/contexts, then kills and awaits the process. On an adopted browser
235
+ * it sends `Browser.close`. On a merely attached browser this is a LOCAL
236
+ * DETACH ONLY because other clients may share its targets. Idempotent.
234
237
  * - `close` — graceful REMOTE shutdown: best-effort sends CDP `Browser.close`
235
238
  * (works whether attached or owned), and when owned also awaits the
236
239
  * process's exit (escalating to a kill only if it doesn't exit in time),
@@ -247,21 +250,32 @@ export declare interface BrowserInterface {
247
250
  readonly engine: BrowserEngine;
248
251
  readonly status: BrowserStatus;
249
252
  readonly connection: BrowserConnection | undefined;
253
+ /**
254
+ * Whether this instance is responsible for terminating the represented browser.
255
+ *
256
+ * @remarks
257
+ * `true` for launched and explicitly adopted sessions, `false` for an
258
+ * active attachment, and `undefined` when no session is represented.
259
+ */
260
+ readonly owned: boolean | undefined;
250
261
  readonly connected: boolean;
251
262
  /**
252
263
  * The process this instance launched, if any, while it is believed alive.
253
264
  *
254
265
  * @remarks
255
- * Remains readable after a persistent disconnect-release (the process
256
- * keeps running, detached from this instance) until `destroy()` or an
266
+ * Remains readable after a persistent disconnect (the process keeps
267
+ * running, detached from the transport) until `destroy()` or an
257
268
  * observed process exit clears it.
258
269
  */
259
270
  readonly pid: number | undefined;
260
271
  discover(): Promise<BrowserDiscoveryResult>;
261
272
  connect(): Promise<void>;
273
+ /** Assume responsibility for terminating the currently connected browser. */
274
+ adopt(): void;
262
275
  disconnect(): Promise<void>;
263
276
  context(index?: number): BrowserContextInterface | undefined;
264
277
  contexts(): readonly BrowserContextInterface[];
278
+ isolate(options?: BrowserContextOptions): Promise<BrowserContextInterface>;
265
279
  create(options?: BrowserPageOptions): Promise<BrowserPageInterface>;
266
280
  destroy(): Promise<void>;
267
281
  close(): Promise<void>;
@@ -279,6 +293,7 @@ export declare class BrowserNotConnectedError extends BrowserError {
279
293
  *
280
294
  * @remarks
281
295
  * - `on` — initial event listeners wired at construction
296
+ * - `error` — observer error handler forwarded to the emitter
282
297
  * - `headless` — launch in headless mode (default `true`; ignored for CDP connections)
283
298
  * - `executable` — absolute path to a browser executable; when provided, skips
284
299
  * system browser discovery and launches this binary directly
@@ -297,10 +312,11 @@ export declare class BrowserNotConnectedError extends BrowserError {
297
312
  */
298
313
  export declare interface BrowserOptions {
299
314
  readonly on?: EmitterHooks<BrowserEventMap>;
315
+ readonly error?: EmitterErrorHandler;
300
316
  readonly headless?: boolean;
301
317
  readonly executable?: string;
302
318
  readonly profile?: string;
303
- readonly cdp?: BrowserCdpOptions;
319
+ readonly cdp?: BrowserCDPOptions;
304
320
  readonly timeout?: number;
305
321
  readonly viewport?: BrowserViewport;
306
322
  readonly signal?: AbortSignal;
@@ -309,11 +325,24 @@ export declare interface BrowserOptions {
309
325
  readonly browsers?: SystemBrowserOptions;
310
326
  }
311
327
 
328
+ /**
329
+ * Resolved browser profile directory used for a Chromium-family launch.
330
+ *
331
+ * @remarks
332
+ * `temporary` is true only for an isolated profile created by
333
+ * {@link createBrowserProfile}; caller-supplied persistent profiles are
334
+ * never removed by the library.
335
+ */
336
+ export declare interface BrowserProfileResult {
337
+ readonly path: string;
338
+ readonly temporary: boolean;
339
+ }
340
+
312
341
  /** Lifecycle status of a browser wrapper. */
313
342
  export declare type BrowserStatus = 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
314
343
 
315
344
  /** Classify a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */
316
- export declare function browserToEngine(browser: string): BrowserEngine;
345
+ export declare function browserToEngine(browser?: string): BrowserEngine;
317
346
 
318
347
  /**
319
348
  * Create a raw-CDP Browser façade.
@@ -331,6 +360,14 @@ export declare function browserToEngine(browser: string): BrowserEngine;
331
360
  */
332
361
  export declare function createBrowser(options?: BrowserOptions): BrowserInterface;
333
362
 
363
+ /**
364
+ * Resolve a persistent caller profile or create an isolated temporary one.
365
+ *
366
+ * @param path - Optional caller-owned persistent user-data directory
367
+ * @returns The resolved profile and whether the library owns its lifecycle
368
+ */
369
+ export declare function createBrowserProfile(path?: string): Promise<BrowserProfileResult>;
370
+
334
371
  /**
335
372
  * Create a Node `WebSocket`-backed CDP transport.
336
373
  *
@@ -360,7 +397,7 @@ export declare function defaultStoreBases(env: Readonly<Record<string, string |
360
397
  * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)
361
398
  * @returns Normalized CDP targets
362
399
  */
363
- export declare function fetchCdpTargets(port: number, timeout: number, host?: string): Promise<readonly CDPTarget[]>;
400
+ export declare function fetchCDPTargets(port: number, timeout: number, host?: string): Promise<readonly CDPTarget[]>;
364
401
 
365
402
  /** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order, returning every one that exists. */
366
403
  export declare function findAllEnvOverrides(env: Readonly<Record<string, string | undefined>>): readonly string[];
@@ -467,6 +504,18 @@ export declare function probeAllPathNames(names: readonly string[], platform: st
467
504
  /** Probe PATH (`which`/`where`) for the first resolvable command name. */
468
505
  export declare function probePathNames(names: readonly string[], platform: string): string | undefined;
469
506
 
507
+ /**
508
+ * Remove a library-owned isolated browser profile.
509
+ *
510
+ * @remarks
511
+ * The path must remain a direct child of the operating-system temp directory
512
+ * with {@link BROWSER_PROFILE_PREFIX}; this defensive check prevents a
513
+ * malformed profile value from widening recursive deletion.
514
+ *
515
+ * @param profile - Resolved profile lifecycle result
516
+ */
517
+ export declare function removeBrowserProfile(profile: BrowserProfileResult): Promise<void>;
518
+
470
519
  /**
471
520
  * One discovered browser executable on this machine.
472
521
  *
@@ -518,32 +567,21 @@ export declare interface SystemBrowserOptions {
518
567
  *
519
568
  * @throws When the endpoint does not become ready before the timeout
520
569
  */
521
- export declare function waitForCdpReady(port: number, timeout: number, host?: string): Promise<string>;
570
+ export declare function waitForCDPReady(port: number, timeout: number, host?: string, signal?: AbortSignal): Promise<string>;
522
571
 
523
572
  /**
524
- * `@orkestrel/websocket`-backed {@link CDPTransportInterface} — the dumb text
525
- * pipe a {@link import('@src/core').CDPClientInterface} sends and receives
526
- * JSON-RPC frames over.
573
+ * `@orkestrel/websocket`-backed raw CDP text transport.
527
574
  *
528
575
  * @remarks
529
- * `start()` hand-rolls the RFC 6455 client handshake: it opens a `node:http`
530
- * `GET` carrying `Connection: Upgrade` / `Upgrade: websocket` / a random
531
- * `Sec-WebSocket-Key` / `Sec-WebSocket-Version`, awaits the client `'upgrade'`
532
- * event, and validates `Sec-WebSocket-Accept === computeWebSocketAccept(key)`
533
- * — a mismatch (or a connection/request error, or a timeout) rejects `start()`
534
- * with a coded {@link BrowserConnectionError} and cleans up the socket. On
535
- * success it wraps the raw upgraded socket in `createNodeWebSocket({ socket,
536
- * head })` (CLIENT mode — no `key` — so outgoing frames are masked per RFC
537
- * 6455 §5.3) and bridges its `message`/`close`/`error` events onto this
538
- * transport's emitter. `start()` opens a fresh socket each call (safe to call
539
- * again after `close()` — a new request/socket/NodeWebSocket triple is
540
- * created every time, which is what `CDPClient.reconnect()` depends on). CDP
541
- * frames are text-only, so `message` always carries a `string`.
576
+ * Performs and validates the RFC 6455 HTTP upgrade, then delegates frame
577
+ * handling to `@orkestrel/websocket`. Concurrent and repeated `start()` /
578
+ * `close()` calls share their active transition, and a later `start()` opens a
579
+ * fresh socket after the prior one closes.
542
580
  */
543
581
  export declare class WebSocketCDPTransport implements CDPTransportInterface {
544
582
  #private;
545
583
  constructor(options: WebSocketCDPTransportOptions);
546
- get emitter(): EmitterInterface<CDPTransportEventMap>;
584
+ get emitter(): EmitterInterface<CDPTransportEventMap_2>;
547
585
  start(): Promise<void>;
548
586
  send(data: string): Promise<void>;
549
587
  close(): Promise<void>;
@@ -553,10 +591,14 @@ export declare class WebSocketCDPTransport implements CDPTransportInterface {
553
591
  * Options for creating a WebSocketCDPTransport.
554
592
  *
555
593
  * @remarks
594
+ * - `on` — initial event listeners wired at construction
595
+ * - `error` — observer error handler forwarded to the emitter
556
596
  * - `url` — the CDP WebSocket debugger URL to connect to
557
597
  * - `timeout` — ms before the connection attempt fails (default from constants)
558
598
  */
559
599
  export declare interface WebSocketCDPTransportOptions {
600
+ readonly on?: EmitterHooks<CDPTransportEventMap>;
601
+ readonly error?: EmitterErrorHandler;
560
602
  readonly url: string;
561
603
  readonly timeout?: number;
562
604
  }
@@ -1,17 +1,23 @@
1
1
  import { BrowserContextInterface } from '../core/index.ts';
2
+ import { BrowserContextOptions } from '../core/index.ts';
2
3
  import { BrowserError } from '../core/index.ts';
3
4
  import { BrowserPageInterface } from '../core/index.ts';
4
5
  import { BrowserPageOptions } from '../core/index.ts';
5
6
  import { BrowserViewport } from '../core/index.ts';
6
7
  import { CDPTarget } from '../core/index.ts';
7
- import { CDPTransportEventMap } from '../../core/index.ts';
8
+ import { CDPTransportEventMap } from '../core/index.ts';
9
+ import { CDPTransportEventMap as CDPTransportEventMap_2 } from '../../core/index.ts';
8
10
  import { CDPTransportInterface } from '../../core/index.ts';
9
11
  import { CDPTransportInterface as CDPTransportInterface_2 } from '../core/index.ts';
10
12
  import { ChildProcess } from 'node:child_process';
13
+ import { EmitterErrorHandler } from '@orkestrel/emitter';
11
14
  import { EmitterHooks } from '@orkestrel/emitter';
12
15
  import { EmitterInterface } from '@orkestrel/emitter';
13
16
  import { ScreenshotWriterInterface } from '../core/index.ts';
14
17
 
18
+ /**
19
+ * Discovers, launches, connects to, and owns Chromium-family browser sessions.
20
+ */
15
21
  export declare class Browser implements BrowserInterface {
16
22
  #private;
17
23
  constructor(options?: BrowserOptions);
@@ -19,25 +25,18 @@ export declare class Browser implements BrowserInterface {
19
25
  get engine(): BrowserEngine;
20
26
  get status(): BrowserStatus;
21
27
  get connection(): BrowserConnection | undefined;
28
+ get owned(): boolean | undefined;
22
29
  get connected(): boolean;
23
30
  get pid(): number | undefined;
24
31
  discover(): Promise<BrowserDiscoveryResult>;
25
32
  connect(): Promise<void>;
33
+ adopt(): void;
26
34
  disconnect(): Promise<void>;
27
35
  context(index?: number): BrowserContextInterface | undefined;
28
36
  contexts(): readonly BrowserContextInterface[];
37
+ isolate(options?: BrowserContextOptions): Promise<BrowserContextInterface>;
29
38
  create(options?: BrowserPageOptions): Promise<BrowserPageInterface>;
30
39
  destroy(): Promise<void>;
31
- /**
32
- * Gracefully shut down the remote browser, whether this instance owns its
33
- * process or merely attached to it via CDP.
34
- *
35
- * @remarks
36
- * Sends CDP `Browser.close` best-effort; on an owned browser also awaits
37
- * the process's exit (bounded by the kill-escalation grace period,
38
- * escalating to a kill only if it does not exit in time). Ends in the
39
- * same local-cleanup state as `destroy()`.
40
- */
41
40
  close(): Promise<void>;
42
41
  }
43
42
 
@@ -80,12 +79,15 @@ export declare const BROWSER_KILL_GRACE_MS = 3000;
80
79
  /** Flags always passed to a launched browser process, alongside the caller's own. */
81
80
  export declare const BROWSER_LAUNCH_ARGS: readonly string[];
82
81
 
83
- /** Sentinel result returned by discovery when no browser is reachable. */
84
- export declare const BROWSER_NOT_FOUND_RESULT: BrowserDiscoveryResult;
85
-
86
82
  /** 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. */
87
83
  export declare const BROWSER_PORT_PROBE_TIMEOUT_MS = 200;
88
84
 
85
+ /** Machine-readable error-context cause for an owned browser process exiting. */
86
+ export declare const BROWSER_PROCESS_EXIT_CAUSE = "process-exit";
87
+
88
+ /** Prefix for isolated browser profiles created beneath the operating-system temp directory. */
89
+ export declare const BROWSER_PROFILE_PREFIX = "orkestrel-browser-";
90
+
89
91
  /** Per-OS default Playwright browser cache directory, relative to the home directory (win32 uses `LOCALAPPDATA` directly). */
90
92
  export declare const BROWSER_STORE_CACHE_DIRS: Readonly<Record<string, string>>;
91
93
 
@@ -101,6 +103,9 @@ export declare const BROWSER_STORE_GLOBS: Readonly<Record<string, string>>;
101
103
  /** Name of the top-level Chromium symlink/binary Playwright maintains inside a browser store base. */
102
104
  export declare const BROWSER_STORE_LINK_NAME = "chromium";
103
105
 
106
+ /** Machine-readable error-context cause for a CDP transport disconnecting while its browser remains alive. */
107
+ export declare const BROWSER_TRANSPORT_LOSS_CAUSE = "transport-loss";
108
+
104
109
  /** 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. */
105
110
  export declare const BROWSER_TRANSPORT_LOSS_DEFER_MS = 50;
106
111
 
@@ -125,7 +130,7 @@ export declare const BROWSER_WINDOWS_SUFFIXES: readonly string[];
125
130
  * listening there, so a demanded fresh launch never silently attaches to a
126
131
  * stranger browser
127
132
  */
128
- export declare interface BrowserCdpOptions {
133
+ export declare interface BrowserCDPOptions {
129
134
  readonly port?: number;
130
135
  readonly host?: string;
131
136
  readonly endpoint?: string;
@@ -193,6 +198,7 @@ export declare type BrowserEventMap = {
193
198
  readonly disconnect: readonly [];
194
199
  readonly launch: readonly [engine: BrowserEngine];
195
200
  readonly page: readonly [page: BrowserPageInterface];
201
+ readonly context: readonly [context: BrowserContextInterface];
196
202
  readonly error: readonly [error: unknown];
197
203
  readonly destroy: readonly [];
198
204
  };
@@ -215,22 +221,19 @@ export declare type BrowserEventMap = {
215
221
  * **Lifecycle:**
216
222
  * - `discover` — passive CDP probe, no side effects
217
223
  * - `connect` — establish connection using the strategy above
218
- * - `disconnect` — detach from the browser. For `'cdp'` and `'persistent'`
219
- * connections this closes the client WITHOUT killing the browser process —
220
- * a `'persistent'` (profile-backed) launch releases ownership of its process
221
- * (no kill, no exit listener) so the browser stays alive for later
222
- * reattachment via CDP discovery on the same port. Rejects with the coded
223
- * `BrowserConnectionError` for `'launch'` (ephemeral, no profile) sessions —
224
- * use `destroy()` instead. An external disconnect (transport loss while the
225
- * owned process is still alive, or the owned process exiting on its own)
226
- * drives this same released/disconnected state automatically, preceded by
224
+ * - `adopt` — explicitly assume responsibility for terminating the connected
225
+ * browser, including a browser this instance attached to over CDP
226
+ * - `disconnect` — detach from the browser. For attached CDP connections this
227
+ * closes only the client. For owned launches and adopted connections, it
228
+ * retains ownership and the endpoint so the same instance can reconnect
229
+ * and remains responsible for eventual termination. An external disconnect
230
+ * (transport loss while the owned process is still alive, or the owned
231
+ * process exiting on its own) drives the disconnected state, preceded by
227
232
  * a coded `error` — `connect()` on the same instance can reattach afterward.
228
- * - `destroy` — release local resources. On an owned (`'launch'`/`'persistent'`)
229
- * browser this closes pages/contexts, then kills the process (SIGTERM,
230
- * escalating to SIGKILL). On a `'cdp'`-attached browser this is a LOCAL
231
- * DETACH ONLY — the client is closed and local context/page objects are
232
- * dropped WITHOUT sending any remote close to the browser, since other
233
- * clients may share those targets. Idempotent.
233
+ * - `destroy` — release local resources. On a launched browser this closes
234
+ * pages/contexts, then kills and awaits the process. On an adopted browser
235
+ * it sends `Browser.close`. On a merely attached browser this is a LOCAL
236
+ * DETACH ONLY because other clients may share its targets. Idempotent.
234
237
  * - `close` — graceful REMOTE shutdown: best-effort sends CDP `Browser.close`
235
238
  * (works whether attached or owned), and when owned also awaits the
236
239
  * process's exit (escalating to a kill only if it doesn't exit in time),
@@ -247,21 +250,32 @@ export declare interface BrowserInterface {
247
250
  readonly engine: BrowserEngine;
248
251
  readonly status: BrowserStatus;
249
252
  readonly connection: BrowserConnection | undefined;
253
+ /**
254
+ * Whether this instance is responsible for terminating the represented browser.
255
+ *
256
+ * @remarks
257
+ * `true` for launched and explicitly adopted sessions, `false` for an
258
+ * active attachment, and `undefined` when no session is represented.
259
+ */
260
+ readonly owned: boolean | undefined;
250
261
  readonly connected: boolean;
251
262
  /**
252
263
  * The process this instance launched, if any, while it is believed alive.
253
264
  *
254
265
  * @remarks
255
- * Remains readable after a persistent disconnect-release (the process
256
- * keeps running, detached from this instance) until `destroy()` or an
266
+ * Remains readable after a persistent disconnect (the process keeps
267
+ * running, detached from the transport) until `destroy()` or an
257
268
  * observed process exit clears it.
258
269
  */
259
270
  readonly pid: number | undefined;
260
271
  discover(): Promise<BrowserDiscoveryResult>;
261
272
  connect(): Promise<void>;
273
+ /** Assume responsibility for terminating the currently connected browser. */
274
+ adopt(): void;
262
275
  disconnect(): Promise<void>;
263
276
  context(index?: number): BrowserContextInterface | undefined;
264
277
  contexts(): readonly BrowserContextInterface[];
278
+ isolate(options?: BrowserContextOptions): Promise<BrowserContextInterface>;
265
279
  create(options?: BrowserPageOptions): Promise<BrowserPageInterface>;
266
280
  destroy(): Promise<void>;
267
281
  close(): Promise<void>;
@@ -279,6 +293,7 @@ export declare class BrowserNotConnectedError extends BrowserError {
279
293
  *
280
294
  * @remarks
281
295
  * - `on` — initial event listeners wired at construction
296
+ * - `error` — observer error handler forwarded to the emitter
282
297
  * - `headless` — launch in headless mode (default `true`; ignored for CDP connections)
283
298
  * - `executable` — absolute path to a browser executable; when provided, skips
284
299
  * system browser discovery and launches this binary directly
@@ -297,10 +312,11 @@ export declare class BrowserNotConnectedError extends BrowserError {
297
312
  */
298
313
  export declare interface BrowserOptions {
299
314
  readonly on?: EmitterHooks<BrowserEventMap>;
315
+ readonly error?: EmitterErrorHandler;
300
316
  readonly headless?: boolean;
301
317
  readonly executable?: string;
302
318
  readonly profile?: string;
303
- readonly cdp?: BrowserCdpOptions;
319
+ readonly cdp?: BrowserCDPOptions;
304
320
  readonly timeout?: number;
305
321
  readonly viewport?: BrowserViewport;
306
322
  readonly signal?: AbortSignal;
@@ -309,11 +325,24 @@ export declare interface BrowserOptions {
309
325
  readonly browsers?: SystemBrowserOptions;
310
326
  }
311
327
 
328
+ /**
329
+ * Resolved browser profile directory used for a Chromium-family launch.
330
+ *
331
+ * @remarks
332
+ * `temporary` is true only for an isolated profile created by
333
+ * {@link createBrowserProfile}; caller-supplied persistent profiles are
334
+ * never removed by the library.
335
+ */
336
+ export declare interface BrowserProfileResult {
337
+ readonly path: string;
338
+ readonly temporary: boolean;
339
+ }
340
+
312
341
  /** Lifecycle status of a browser wrapper. */
313
342
  export declare type BrowserStatus = 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
314
343
 
315
344
  /** Classify a `/json/version` `Browser` string into a {@link BrowserEngine} (`Edg/` → edge, `Chrome/` → chrome, else chromium). */
316
- export declare function browserToEngine(browser: string): BrowserEngine;
345
+ export declare function browserToEngine(browser?: string): BrowserEngine;
317
346
 
318
347
  /**
319
348
  * Create a raw-CDP Browser façade.
@@ -331,6 +360,14 @@ export declare function browserToEngine(browser: string): BrowserEngine;
331
360
  */
332
361
  export declare function createBrowser(options?: BrowserOptions): BrowserInterface;
333
362
 
363
+ /**
364
+ * Resolve a persistent caller profile or create an isolated temporary one.
365
+ *
366
+ * @param path - Optional caller-owned persistent user-data directory
367
+ * @returns The resolved profile and whether the library owns its lifecycle
368
+ */
369
+ export declare function createBrowserProfile(path?: string): Promise<BrowserProfileResult>;
370
+
334
371
  /**
335
372
  * Create a Node `WebSocket`-backed CDP transport.
336
373
  *
@@ -360,7 +397,7 @@ export declare function defaultStoreBases(env: Readonly<Record<string, string |
360
397
  * @param host - Host the browser exposes its CDP endpoint on (default `127.0.0.1`)
361
398
  * @returns Normalized CDP targets
362
399
  */
363
- export declare function fetchCdpTargets(port: number, timeout: number, host?: string): Promise<readonly CDPTarget[]>;
400
+ export declare function fetchCDPTargets(port: number, timeout: number, host?: string): Promise<readonly CDPTarget[]>;
364
401
 
365
402
  /** Check the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order, returning every one that exists. */
366
403
  export declare function findAllEnvOverrides(env: Readonly<Record<string, string | undefined>>): readonly string[];
@@ -467,6 +504,18 @@ export declare function probeAllPathNames(names: readonly string[], platform: st
467
504
  /** Probe PATH (`which`/`where`) for the first resolvable command name. */
468
505
  export declare function probePathNames(names: readonly string[], platform: string): string | undefined;
469
506
 
507
+ /**
508
+ * Remove a library-owned isolated browser profile.
509
+ *
510
+ * @remarks
511
+ * The path must remain a direct child of the operating-system temp directory
512
+ * with {@link BROWSER_PROFILE_PREFIX}; this defensive check prevents a
513
+ * malformed profile value from widening recursive deletion.
514
+ *
515
+ * @param profile - Resolved profile lifecycle result
516
+ */
517
+ export declare function removeBrowserProfile(profile: BrowserProfileResult): Promise<void>;
518
+
470
519
  /**
471
520
  * One discovered browser executable on this machine.
472
521
  *
@@ -518,32 +567,21 @@ export declare interface SystemBrowserOptions {
518
567
  *
519
568
  * @throws When the endpoint does not become ready before the timeout
520
569
  */
521
- export declare function waitForCdpReady(port: number, timeout: number, host?: string): Promise<string>;
570
+ export declare function waitForCDPReady(port: number, timeout: number, host?: string, signal?: AbortSignal): Promise<string>;
522
571
 
523
572
  /**
524
- * `@orkestrel/websocket`-backed {@link CDPTransportInterface} — the dumb text
525
- * pipe a {@link import('@src/core').CDPClientInterface} sends and receives
526
- * JSON-RPC frames over.
573
+ * `@orkestrel/websocket`-backed raw CDP text transport.
527
574
  *
528
575
  * @remarks
529
- * `start()` hand-rolls the RFC 6455 client handshake: it opens a `node:http`
530
- * `GET` carrying `Connection: Upgrade` / `Upgrade: websocket` / a random
531
- * `Sec-WebSocket-Key` / `Sec-WebSocket-Version`, awaits the client `'upgrade'`
532
- * event, and validates `Sec-WebSocket-Accept === computeWebSocketAccept(key)`
533
- * — a mismatch (or a connection/request error, or a timeout) rejects `start()`
534
- * with a coded {@link BrowserConnectionError} and cleans up the socket. On
535
- * success it wraps the raw upgraded socket in `createNodeWebSocket({ socket,
536
- * head })` (CLIENT mode — no `key` — so outgoing frames are masked per RFC
537
- * 6455 §5.3) and bridges its `message`/`close`/`error` events onto this
538
- * transport's emitter. `start()` opens a fresh socket each call (safe to call
539
- * again after `close()` — a new request/socket/NodeWebSocket triple is
540
- * created every time, which is what `CDPClient.reconnect()` depends on). CDP
541
- * frames are text-only, so `message` always carries a `string`.
576
+ * Performs and validates the RFC 6455 HTTP upgrade, then delegates frame
577
+ * handling to `@orkestrel/websocket`. Concurrent and repeated `start()` /
578
+ * `close()` calls share their active transition, and a later `start()` opens a
579
+ * fresh socket after the prior one closes.
542
580
  */
543
581
  export declare class WebSocketCDPTransport implements CDPTransportInterface {
544
582
  #private;
545
583
  constructor(options: WebSocketCDPTransportOptions);
546
- get emitter(): EmitterInterface<CDPTransportEventMap>;
584
+ get emitter(): EmitterInterface<CDPTransportEventMap_2>;
547
585
  start(): Promise<void>;
548
586
  send(data: string): Promise<void>;
549
587
  close(): Promise<void>;
@@ -553,10 +591,14 @@ export declare class WebSocketCDPTransport implements CDPTransportInterface {
553
591
  * Options for creating a WebSocketCDPTransport.
554
592
  *
555
593
  * @remarks
594
+ * - `on` — initial event listeners wired at construction
595
+ * - `error` — observer error handler forwarded to the emitter
556
596
  * - `url` — the CDP WebSocket debugger URL to connect to
557
597
  * - `timeout` — ms before the connection attempt fails (default from constants)
558
598
  */
559
599
  export declare interface WebSocketCDPTransportOptions {
600
+ readonly on?: EmitterHooks<CDPTransportEventMap>;
601
+ readonly error?: EmitterErrorHandler;
560
602
  readonly url: string;
561
603
  readonly timeout?: number;
562
604
  }