@mefistofelix/cdp.js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +835 -0
- package/cdp.js +544 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,835 @@
|
|
|
1
|
+
# cdp.js
|
|
2
|
+
|
|
3
|
+
A low-level Chromium DevTools Protocol library for Node.js. One ES module,
|
|
4
|
+
standard-library imports, no runtime dependencies or root `package.json`.
|
|
5
|
+
|
|
6
|
+
Use Node.js 22.19+ and an installed Chrome, Chromium or Edge. Import `cdp.js`
|
|
7
|
+
directly from an ES module, for example `example.mjs`, and run `node example.mjs`.
|
|
8
|
+
Browser discovery covers common Windows, macOS and Linux installation paths;
|
|
9
|
+
use `executable_path` or the `CDP_BROWSER` environment variable for other paths.
|
|
10
|
+
|
|
11
|
+
For a published npm release:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @mefistofelix/cdp.js
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import api, { util, jsrpc, browser, cdp } from '@mefistofelix/cdp.js'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The npm package exports the same file and API. Direct file imports in the examples
|
|
22
|
+
below remain supported. Publication metadata is isolated in `npm/`.
|
|
23
|
+
|
|
24
|
+
## Features and scope
|
|
25
|
+
|
|
26
|
+
- Native CDP requests through `call({ method, params })`, with native results.
|
|
27
|
+
- Named browsers and targets, created and connected on demand.
|
|
28
|
+
- Attachment through WebSocket, HTTP discovery or a debugging port.
|
|
29
|
+
- Shared initialization for concurrent calls; reconnection and target recreation
|
|
30
|
+
on subsequent use, without replaying failed commands.
|
|
31
|
+
- Public object mappings and directly replaceable custom method handlers.
|
|
32
|
+
- Configurable target initialization, JavaScript bindings and direct events.
|
|
33
|
+
- XPath `_.click` and `_.find`, including two XPath expression rewrites.
|
|
34
|
+
- Configurable browser launch arguments and profile preferences.
|
|
35
|
+
- Raw WebSocket JSON-RPC transport and reusable static helpers.
|
|
36
|
+
|
|
37
|
+
There is no Page class, batch API, image-processing helper, event buffer/filter
|
|
38
|
+
API or database. Browser, target and session mappings live in memory. Chromium
|
|
39
|
+
profiles and their preferences are ordinary files on disk. Any native CDP method
|
|
40
|
+
supported by the connected browser remains available through `call`.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
This complete example uses a local blank target and needs no website:
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
import { cdp } from './cdp.js'
|
|
48
|
+
|
|
49
|
+
const client = new cdp({
|
|
50
|
+
base_path: './profiles',
|
|
51
|
+
headless: true,
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await client.call({
|
|
56
|
+
method: 'Runtime.evaluate',
|
|
57
|
+
params: {
|
|
58
|
+
browser: 'main',
|
|
59
|
+
target: 'demo',
|
|
60
|
+
expression: `
|
|
61
|
+
document.body.innerHTML = '<button id="hello">Hello</button>';
|
|
62
|
+
window.clicks = 0;
|
|
63
|
+
document.querySelector('button').onclick = () => window.clicks++;
|
|
64
|
+
`,
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
const found = await client.call({
|
|
68
|
+
method: '_.find',
|
|
69
|
+
params: {
|
|
70
|
+
target: 'demo',
|
|
71
|
+
xpath: '//button',
|
|
72
|
+
},
|
|
73
|
+
})
|
|
74
|
+
console.log(found.result.value.items)
|
|
75
|
+
|
|
76
|
+
const clicked = await client.call({
|
|
77
|
+
method: '_.click',
|
|
78
|
+
params: {
|
|
79
|
+
target: 'demo',
|
|
80
|
+
xpath: '//button[@id="hello"]',
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
console.log(clicked.result.value) // true
|
|
84
|
+
} finally {
|
|
85
|
+
await client.close()
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The following short examples assume a `client` that has not yet been closed.
|
|
90
|
+
|
|
91
|
+
## Exports and API
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
import api, { util, jsrpc, browser, cdp } from './cdp.js'
|
|
95
|
+
// api contains the same four classes.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| API | Purpose / result |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `new cdp(options = {})` | Create a manager; does not launch a browser yet. |
|
|
101
|
+
| `client.call({ method, params = {} })` | Resolve routing and return a promise for the native CDP result, or a custom handler's result. |
|
|
102
|
+
| `client.evaluate_xpath(params, fn, options)` | Execute a serialized function with a normalized XPath in a target; return the native `Runtime.evaluate` result. |
|
|
103
|
+
| `client.close()` | Close owned browser processes, disconnect attached browsers, then clear `client.browsers`. Profile directories remain. |
|
|
104
|
+
| `new jsrpc(url, options = {})` | Open a raw WebSocket JSON-RPC connection. |
|
|
105
|
+
| `socket.req(request, timeout_ms)` | Assign a request ID and await its native result. |
|
|
106
|
+
| `socket.notify(request)` | Serialize and send a raw message; no ID allocation or response wait. |
|
|
107
|
+
| `socket.close()` | Native WebSocket close; does not terminate the browser. |
|
|
108
|
+
| `browser.find_executable_path()` | Synchronously return an executable path from the environment or common locations. |
|
|
109
|
+
| `browser.build_args(options = {})` | Return a fresh, editable object of launch switches. |
|
|
110
|
+
| `browser.update_profile_preferences(filename, preferences)` | Update dotted keys in a JSON preferences file; return a promise. |
|
|
111
|
+
| `browser.launch(options)` | Start a local browser and return a promise for `{ proc, url }`. The caller owns the process. |
|
|
112
|
+
| `util.normalize_xpath(xpath)` | Return an XPath string with the supported rewrites. |
|
|
113
|
+
| `util.args_to_strings(args)` | Convert a switch object to an array of command-line argument strings. |
|
|
114
|
+
| `util.emit(target, name, detail)` | Dispatch a `CustomEvent`; return `dispatchEvent`'s boolean result. |
|
|
115
|
+
| `util.on_first(target, names, timeout_ms = 30000)` | Await the first space-separated event name; return `{ type, args }`. |
|
|
116
|
+
|
|
117
|
+
`cdp` is an `EventTarget`; `jsrpc` extends the native `WebSocket`. The `browser`
|
|
118
|
+
and `util` classes contain static helpers only. `browser` does not own CDP
|
|
119
|
+
connections or target/session routing.
|
|
120
|
+
|
|
121
|
+
## Calls and routing
|
|
122
|
+
|
|
123
|
+
| Field | Meaning |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| `method` | Native name such as `Page.navigate`, or a custom name beginning with `_.`. |
|
|
126
|
+
| `params` | Native parameters plus the two routing fields below. Defaults to `{}`. |
|
|
127
|
+
| `params.browser` | Browser label or configuration object with `name`. Defaults to `'main'`. |
|
|
128
|
+
| `params.target` | Target label or configuration object with `name`. Omitted or `null` means a browser-level request. |
|
|
129
|
+
|
|
130
|
+
For native requests, the manager removes `browser` and `target` from a copy of
|
|
131
|
+
`params` and adds the resolved `sessionId` to the protocol envelope. The caller's
|
|
132
|
+
object is not mutated. A string label is shorthand for `{ name: 'label' }`.
|
|
133
|
+
Put routing inside `params`, not beside `method`.
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
const version = await client.call({
|
|
137
|
+
method: 'Browser.getVersion',
|
|
138
|
+
params: {
|
|
139
|
+
browser: 'main',
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
console.log(version.product)
|
|
143
|
+
|
|
144
|
+
const result = await client.call({
|
|
145
|
+
method: 'Runtime.evaluate',
|
|
146
|
+
params: {
|
|
147
|
+
browser: 'main',
|
|
148
|
+
target: 'demo',
|
|
149
|
+
expression: 'window.clicks',
|
|
150
|
+
returnByValue: true,
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
console.log(result.result.value)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`call` unwraps only the outer protocol response. `result.result.value` above is
|
|
157
|
+
the remote value inside `Runtime.evaluate`'s own result object. Other methods
|
|
158
|
+
have their own result shapes and parameters, defined by the
|
|
159
|
+
[CDP reference](https://chromedevtools.github.io/devtools-protocol/).
|
|
160
|
+
|
|
161
|
+
## Configuration scope and precedence
|
|
162
|
+
|
|
163
|
+
`new cdp({ base_path, ...options })` sets the profile root and default **browser**
|
|
164
|
+
options. `params.browser` overrides them for a particular label. Target options
|
|
165
|
+
belong in `params.target` and do not inherit from the constructor.
|
|
166
|
+
|
|
167
|
+
For a new browser record, configuration is assembled in this order:
|
|
168
|
+
|
|
169
|
+
1. Default `user_data_dir` derived from `base_path` and the browser name.
|
|
170
|
+
2. Constructor browser options.
|
|
171
|
+
3. The `params.browser` configuration object.
|
|
172
|
+
|
|
173
|
+
`args` and `preferences` are shallow-merged separately between steps 2 and 3.
|
|
174
|
+
For duplicate keys, the per-browser value wins. Arrays replace previous arrays;
|
|
175
|
+
they are not concatenated during this merge.
|
|
176
|
+
|
|
177
|
+
At local launch, another two independent merges happen:
|
|
178
|
+
|
|
179
|
+
- Generated CLI defaults, adjusted by high-level browser options, then raw `args`.
|
|
180
|
+
- Generated profile preference defaults, then raw `preferences`.
|
|
181
|
+
|
|
182
|
+
There is no conflict resolver across CLI flags and preferences. Each is passed
|
|
183
|
+
to Chromium through its own mechanism. Raw settings can therefore contradict a
|
|
184
|
+
high-level option; the library does not silently reconcile them.
|
|
185
|
+
|
|
186
|
+
Configuration is recorded on the first use of a label. A subsequent configuration
|
|
187
|
+
object with the same name does not reconfigure that record. Public records can
|
|
188
|
+
be edited directly: launch settings apply at a later launch, target settings at
|
|
189
|
+
a later initialization. Direct edits do not immediately send CDP commands. Use
|
|
190
|
+
a new browser label, or close the manager and configure it again, for a fresh
|
|
191
|
+
local configuration.
|
|
192
|
+
|
|
193
|
+
## Browser options and defaults
|
|
194
|
+
|
|
195
|
+
| Option | Type / default | Meaning |
|
|
196
|
+
| --- | --- | --- |
|
|
197
|
+
| `base_path` | string, `'.cdp'` | Constructor-only profile root, resolved against the working directory. |
|
|
198
|
+
| `name` | string, `'main'` when routing is omitted | Required in a browser configuration object; dictionary key and default profile directory label. |
|
|
199
|
+
| `user_data_dir` | absolute path string, `<base_path>/<name>` | Chromium user-data directory containing profiles such as `Default`. The generated default is absolute; explicit overrides should be absolute too. |
|
|
200
|
+
| `executable_path` | string, automatic discovery | Executable to spawn; takes precedence over `CDP_BROWSER`. |
|
|
201
|
+
| `headless` | boolean, `false` | When true, add `headless: 'new'` and default `window-size: '1440,900'`. |
|
|
202
|
+
| `extensions` | boolean, `false` | When true, omit the two extension-disabling switches; does not install extensions. |
|
|
203
|
+
| `images` | boolean, `true` | When false, request `blink-settings: 'imagesEnabled=false'`; controls loading, not image processing. |
|
|
204
|
+
| `translations` | boolean, `false` | Set translation preferences and, unless true, disable translation feature IDs. |
|
|
205
|
+
| `login` | boolean, `false` | Set browser sign-in preferences and, unless true, disable sync and sign-in promotions. Does not prevent website login. |
|
|
206
|
+
| `args` | object, `{}` | Raw CLI overrides applied after generated defaults; keys omit `--`. |
|
|
207
|
+
| `preferences` | object, `{}` | Dotted JSON preference overrides applied after generated preference defaults. |
|
|
208
|
+
| `connect_timeout_ms` | number, `15000` | Timeout for each discovery, launch-readiness or socket-opening wait; not one combined deadline. |
|
|
209
|
+
| `request_timeout_ms` | number, `30000` | Default timeout for each protocol request on this browser's socket. |
|
|
210
|
+
| `websocket_url` | string, unset | Attach directly to a browser WebSocket endpoint. |
|
|
211
|
+
| `http_url` | string, unset | Discover the endpoint from an HTTP(S) base URL or exact `/json/version` URL. |
|
|
212
|
+
| `port` | number, unset | Discover an existing browser at `http://<host>:<port>/json/version`. |
|
|
213
|
+
| `host` | string, `'127.0.0.1'` | Host used with `port`. |
|
|
214
|
+
|
|
215
|
+
### Why these defaults
|
|
216
|
+
|
|
217
|
+
The preset aims to make local automation predictable while keeping the browser
|
|
218
|
+
visible by default. These are practical purposes and tradeoffs of the current
|
|
219
|
+
settings, not a claim that every flag is required by every workload:
|
|
220
|
+
|
|
221
|
+
| Default | Purpose / tradeoff |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| Visible browser | Allows direct inspection and manual interaction; use `headless: true` for unattended runs. |
|
|
224
|
+
| Images enabled | Preserves normal page content and layout; disabling them can reduce loading work. |
|
|
225
|
+
| Extensions disabled | Avoids extension behavior and background pages affecting a run; enable them when the profile needs them. |
|
|
226
|
+
| Translations disabled | Avoids browser translation changing page content or presenting translation UI. |
|
|
227
|
+
| Browser login/sync disabled | Keeps browser-account integration out of the automation profile; website authentication remains available. |
|
|
228
|
+
| Separate named profile directories | Separates browser state by label while retaining normal profile data between launches. |
|
|
229
|
+
| Debugging port `0` | Lets Chromium choose an available port; launch reads the actual endpoint from stderr. |
|
|
230
|
+
| Bounded connection/request waits | Prevents indefinite local waits; timeout does not cancel execution already sent to Chromium. |
|
|
231
|
+
| Raw results and direct events | Keeps native protocol data available without another response or subscription abstraction. |
|
|
232
|
+
|
|
233
|
+
Automatic discovery checks `CDP_BROWSER` first. On Windows it checks Chrome and
|
|
234
|
+
Edge below `ProgramFiles`, `ProgramFiles(x86)` and `LOCALAPPDATA`. On macOS/Linux
|
|
235
|
+
it checks the application paths and `/usr/bin` candidates listed in
|
|
236
|
+
`browser.find_executable_path()`. It does not download a browser or search
|
|
237
|
+
arbitrary locations in `PATH`.
|
|
238
|
+
|
|
239
|
+
### Attach to an existing browser
|
|
240
|
+
|
|
241
|
+
`websocket_url` takes precedence over HTTP discovery; `http_url` takes precedence
|
|
242
|
+
over `host`/`port`. Use one endpoint form:
|
|
243
|
+
|
|
244
|
+
```js
|
|
245
|
+
await client.call({
|
|
246
|
+
method: 'Browser.getVersion',
|
|
247
|
+
params: {
|
|
248
|
+
browser: {
|
|
249
|
+
name: 'existing',
|
|
250
|
+
port: 9222,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The existing browser must already expose CDP. Launch flags and profile
|
|
257
|
+
preferences are not applied to it. `client.close()` disconnects its socket and
|
|
258
|
+
leaves that browser running.
|
|
259
|
+
|
|
260
|
+
`port: 9222` means **attach**. To **launch** on that port, use
|
|
261
|
+
`args: { 'remote-debugging-port': 9222 }` without an attachment endpoint.
|
|
262
|
+
|
|
263
|
+
## Command-line arguments
|
|
264
|
+
|
|
265
|
+
The library exposes a JavaScript API, not a command-line program. `args` refers
|
|
266
|
+
to the switches passed to the Chromium executable.
|
|
267
|
+
|
|
268
|
+
`browser.build_args(options)` builds defaults, applies boolean options, then
|
|
269
|
+
overwrites keys with `options.args`. The result remains an object until
|
|
270
|
+
`util.args_to_strings` materializes it for `child_process.spawn`. No shell command
|
|
271
|
+
is assembled; a value containing spaces stays inside one argument.
|
|
272
|
+
|
|
273
|
+
| Object value | Generated argument |
|
|
274
|
+
| --- | --- |
|
|
275
|
+
| `true` | `--key` |
|
|
276
|
+
| `false`, `null`, `undefined` | Omitted |
|
|
277
|
+
| string or number | `--key=value` |
|
|
278
|
+
| array | `--key=first,second` |
|
|
279
|
+
|
|
280
|
+
The array rule applies to every switch. An empty array emits `--key=`. There is
|
|
281
|
+
no separate `disabled_features` option. Setting a generated flag to `false`
|
|
282
|
+
removes it; it does not automatically emit an opposite flag.
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
import { browser, util } from './cdp.js'
|
|
286
|
+
|
|
287
|
+
const args = browser.build_args({
|
|
288
|
+
user_data_dir: './profiles/example',
|
|
289
|
+
headless: true,
|
|
290
|
+
args: {
|
|
291
|
+
'mute-audio': false,
|
|
292
|
+
'window-size': '800,600',
|
|
293
|
+
'enable-features': ['FeatureOne', 'FeatureTwo'],
|
|
294
|
+
},
|
|
295
|
+
})
|
|
296
|
+
args['disable-features'].push('AnotherFeature')
|
|
297
|
+
delete args['hide-crash-restore-bubble']
|
|
298
|
+
console.log(util.args_to_strings(args))
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
To launch with a modified object, supply it as `options.args`; defaults are built
|
|
302
|
+
again, so suppress a default with `false` in that override object. Deleting a key
|
|
303
|
+
from a standalone object suppresses it only when that object itself is
|
|
304
|
+
materialized directly.
|
|
305
|
+
|
|
306
|
+
### Generated switches
|
|
307
|
+
|
|
308
|
+
These are the library's requested defaults and their intended purpose. The
|
|
309
|
+
installed Chromium build determines which switches and feature IDs it honors;
|
|
310
|
+
some are platform-specific or retained compatibility switches. The preset does
|
|
311
|
+
not guarantee that every browser version implements every entry. Native
|
|
312
|
+
reference definitions include Chromium's [Chrome switches](https://raw.githubusercontent.com/chromium/chromium/main/chrome/common/chrome_switches.h)
|
|
313
|
+
and [content switches](https://raw.githubusercontent.com/chromium/chromium/main/content/public/common/content_switches.cc).
|
|
314
|
+
|
|
315
|
+
| Switch key | Value / condition | Purpose |
|
|
316
|
+
| --- | --- | --- |
|
|
317
|
+
| `user-data-dir` | `user_data_dir` | Select user-data storage. |
|
|
318
|
+
| `remote-debugging-port` | `0` | Enable CDP on a port chosen by Chromium. |
|
|
319
|
+
| `enable-automation` | `true` | Enable Chromium automation mode. |
|
|
320
|
+
| `mute-audio` | `true` | Mute browser audio. |
|
|
321
|
+
| `disable-blink-features` | `'AutomationControlled'` | Disable that Blink runtime feature. |
|
|
322
|
+
| `hide-crash-restore-bubble` | `true` | Suppress crash-restore UI where supported. |
|
|
323
|
+
| `disable-field-trial-config` | `true` | Disable field-trial configuration. |
|
|
324
|
+
| `disable-background-networking` | `true` | Reduce subsystem background networking. |
|
|
325
|
+
| `enable-features` | array below | Enable named Chromium features. |
|
|
326
|
+
| `disable-background-timer-throttling` | `true` | Disable background-page timer throttling. |
|
|
327
|
+
| `disable-backgrounding-occluded-windows` | `true` | Avoid backgrounding occluded windows. |
|
|
328
|
+
| `disable-renderer-backgrounding` | `true` | Avoid lowering renderer priority in background. |
|
|
329
|
+
| `disable-back-forward-cache` | `true` | Disable the back/forward page cache. |
|
|
330
|
+
| `disable-breakpad` | `true` | Disable Breakpad crash reporting where supported. |
|
|
331
|
+
| `disable-client-side-phishing-detection` | `true` | Disable client-side phishing detection. |
|
|
332
|
+
| `disable-component-update` | `true` | Disable browser component updates. |
|
|
333
|
+
| `no-default-browser-check` | `true` | Skip the default-browser check. |
|
|
334
|
+
| `disable-default-apps` | `true` | Skip default application installation. |
|
|
335
|
+
| `disable-dev-shm-usage` | `true` | Avoid `/dev/shm` storage on Linux. |
|
|
336
|
+
| `allow-pre-commit-input` | `true` | Allow input before frame commit where supported. |
|
|
337
|
+
| `disable-hang-monitor` | `true` | Disable renderer hang monitoring. |
|
|
338
|
+
| `disable-ipc-flooding-protection` | `true` | Disable IPC flooding rate limits. |
|
|
339
|
+
| `disable-popup-blocking` | `true` | Disable automatic popup blocking. |
|
|
340
|
+
| `disable-prompt-on-repost` | `true` | Suppress form-repost confirmation. |
|
|
341
|
+
| `force-color-profile` | `'srgb'` | Select the sRGB color profile. |
|
|
342
|
+
| `metrics-recording-only` | `true` | Request metrics recording without reporting. |
|
|
343
|
+
| `no-first-run` | `true` | Skip the first-run experience. |
|
|
344
|
+
| `password-store` | `'basic'` | Select the basic password-store backend. |
|
|
345
|
+
| `use-mock-keychain` | `true` | Use the test keychain where supported. |
|
|
346
|
+
| `no-service-autorun` | `true` | Suppress service autorun where supported. |
|
|
347
|
+
| `export-tagged-pdf` | `true` | Request tagged PDF output where supported. |
|
|
348
|
+
| `disable-search-engine-choice-screen` | `true` | Suppress search-engine selection UI. |
|
|
349
|
+
| `disable-features` | array below | Disable named Chromium features. |
|
|
350
|
+
| `headless` | `'new'` when `headless` is true | Run without a visible browser window. |
|
|
351
|
+
| `window-size` | `'1440,900'` when headless | Set initial window dimensions. |
|
|
352
|
+
| `disable-extensions` | `true` unless `extensions` is true | Disable browser extensions. |
|
|
353
|
+
| `disable-component-extensions-with-background-pages` | same condition | Disable those component extensions. |
|
|
354
|
+
| `blink-settings` | `'imagesEnabled=false'` when `images` is false | Disable image loading through Blink settings. |
|
|
355
|
+
| `disable-signin-promo-on-avatar-pill-for-testing` | `true` unless `login` is true | Suppress the avatar sign-in promotion. |
|
|
356
|
+
| `disable-sync` | same condition | Disable browser sync. |
|
|
357
|
+
|
|
358
|
+
The sign-in promotion switch is defined in Chromium's
|
|
359
|
+
[sign-in switches](https://raw.githubusercontent.com/chromium/chromium/main/components/signin/public/base/signin_switches.cc).
|
|
360
|
+
`about:blank` is appended as the initial URL. Launching or creating a managed
|
|
361
|
+
target does not close other tabs.
|
|
362
|
+
|
|
363
|
+
The initial `enable-features` array is:
|
|
364
|
+
|
|
365
|
+
```js
|
|
366
|
+
[
|
|
367
|
+
'NetworkService',
|
|
368
|
+
'NetworkServiceInProcess',
|
|
369
|
+
]
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
The initial `disable-features` array is:
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
[
|
|
376
|
+
'InfiniteSessionRestore',
|
|
377
|
+
'ImprovedCookieControls',
|
|
378
|
+
'LazyFrameLoading',
|
|
379
|
+
'GlobalMediaControls',
|
|
380
|
+
'DestroyProfileOnBrowserClose',
|
|
381
|
+
'MediaRouter',
|
|
382
|
+
'DialMediaRouteProvider',
|
|
383
|
+
'AcceptCHFrame',
|
|
384
|
+
'AutoExpandDetailsElement',
|
|
385
|
+
'CertificateTransparencyComponentUpdater',
|
|
386
|
+
'AvoidUnnecessaryBeforeUnloadCheckSync',
|
|
387
|
+
'HttpsUpgrades',
|
|
388
|
+
'PaintHolding',
|
|
389
|
+
]
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
These are native Chromium feature identifiers, not additional library options.
|
|
393
|
+
Unless `translations` is true, the library appends `Translate`, `TranslateToast`
|
|
394
|
+
and `EnableTranslatePdf`. Unless `login` is true, it appends
|
|
395
|
+
`DiceWebSigninInterception` and `SigninPromoOnAvatarPill`. A raw
|
|
396
|
+
`args['disable-features']` replaces that entire generated array.
|
|
397
|
+
|
|
398
|
+
## Profile preferences
|
|
399
|
+
|
|
400
|
+
Local launch edits the profile's JSON `Preferences` file before spawning
|
|
401
|
+
Chromium. The effective path is:
|
|
402
|
+
|
|
403
|
+
```text
|
|
404
|
+
<args['user-data-dir']>/<args['profile-directory'] or Default>/Preferences
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
`profile-directory` is a raw switch, for example `'Profile 1'`. The generated
|
|
408
|
+
preference defaults are:
|
|
409
|
+
|
|
410
|
+
| Dotted key | Value | Meaning |
|
|
411
|
+
| --- | --- | --- |
|
|
412
|
+
| `translate.enabled` | `translations === true` | Allow browser translation. |
|
|
413
|
+
| `signin.allowed` | `login === true` | Allow browser profile sign-in. |
|
|
414
|
+
| `signin.allowed_on_next_startup` | `login === true` | Apply sign-in permission at startup. |
|
|
415
|
+
|
|
416
|
+
`options.preferences` overwrites these defaults by key. Preferences and switches
|
|
417
|
+
are separate layers; overriding one does not remove the other.
|
|
418
|
+
|
|
419
|
+
```js
|
|
420
|
+
await client.call({
|
|
421
|
+
method: 'Browser.getVersion',
|
|
422
|
+
params: {
|
|
423
|
+
browser: {
|
|
424
|
+
name: 'downloads',
|
|
425
|
+
headless: true,
|
|
426
|
+
translations: true,
|
|
427
|
+
preferences: {
|
|
428
|
+
'download.prompt_for_download': false,
|
|
429
|
+
'download.default_directory': '/absolute/path/to/downloads',
|
|
430
|
+
},
|
|
431
|
+
args: {
|
|
432
|
+
'profile-directory': 'Default',
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
})
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
The helper is also usable independently, before starting the browser:
|
|
440
|
+
|
|
441
|
+
```js
|
|
442
|
+
await browser.update_profile_preferences('./profiles/example/Default/Preferences', {
|
|
443
|
+
'translate.enabled': false,
|
|
444
|
+
'download.prompt_for_download': false,
|
|
445
|
+
})
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
It creates missing directories and a missing JSON file, traverses dotted keys,
|
|
449
|
+
assigns JSON-compatible values and preserves unrelated values. An object
|
|
450
|
+
assigned at a key replaces that value; this is not a recursive merge of the
|
|
451
|
+
supplied object. `null` is stored as JSON null. Malformed JSON, incompatible
|
|
452
|
+
existing path values and filesystem errors propagate. It does not coordinate
|
|
453
|
+
writes with a running browser, which may overwrite the file itself.
|
|
454
|
+
|
|
455
|
+
## Overlaps and override examples
|
|
456
|
+
|
|
457
|
+
| Settings | Effective library behavior |
|
|
458
|
+
| --- | --- |
|
|
459
|
+
| `headless: true` plus `args.headless: false` | Omit `--headless`; the generated window-size argument remains unless also overridden. |
|
|
460
|
+
| `headless: false` plus `args.headless: 'new'` | Send `--headless=new`; no automatic headless window-size default was generated. |
|
|
461
|
+
| `extensions: true` plus `args['disable-extensions']: true` | The raw extension-disabling switch still wins. |
|
|
462
|
+
| `extensions: false` plus only `args['disable-extensions']: false` | Remove that flag, but retain `disable-component-extensions-with-background-pages`. Use `extensions: true` to omit both generated flags. |
|
|
463
|
+
| `images: false` plus an overridden `blink-settings` | Replace the whole string; image disabling is not appended to the caller's value. |
|
|
464
|
+
| `translations: false` plus `preferences['translate.enabled']: true` | Store true in the profile, while generated translation-disabling feature IDs remain on the CLI. |
|
|
465
|
+
| `login: true` plus `args['disable-sync']: true` | Allow profile sign-in through generated preferences while still requesting sync to be disabled. |
|
|
466
|
+
| Any high-level settings plus a raw `disable-features` array | Replace the whole generated list, including translation/sign-in additions. |
|
|
467
|
+
| `user_data_dir` plus `args['user-data-dir']` | The raw argument determines both the profile write location and the launched browser directory. |
|
|
468
|
+
| `port` plus `args['remote-debugging-port']` | Attach using `port`; no launch occurs, so the raw launch argument is unused. |
|
|
469
|
+
| Constructor options plus an existing browser label | Reuse the stored record; configuration is not merged again on every call. |
|
|
470
|
+
| `initialize: false` plus `runtime: true` or a binding name | Skip optional target setup, including domain enabling and binding installation. |
|
|
471
|
+
| `binding: false` plus `runtime: true` | Skip binding installation but retain Runtime enabling/reporting. |
|
|
472
|
+
|
|
473
|
+
For translation/sign-in behavior, prefer the high-level option unless a mixed
|
|
474
|
+
configuration is intentional. Browser versions and policies ultimately determine
|
|
475
|
+
the outcome of contradictory native settings; the library only constructs the
|
|
476
|
+
arguments and writes the preferences described here.
|
|
477
|
+
|
|
478
|
+
A raw feature list can be extended without losing the generated entries:
|
|
479
|
+
|
|
480
|
+
```js
|
|
481
|
+
const generated = browser.build_args({
|
|
482
|
+
translations: true,
|
|
483
|
+
login: false,
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
const clientWithOverrides = new cdp({
|
|
487
|
+
translations: true,
|
|
488
|
+
login: false,
|
|
489
|
+
args: {
|
|
490
|
+
'disable-features': [...generated['disable-features'], 'AnotherFeature'],
|
|
491
|
+
},
|
|
492
|
+
})
|
|
493
|
+
await clientWithOverrides.close()
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
## Target options and lifecycle
|
|
497
|
+
|
|
498
|
+
Target configuration belongs in `params.target`:
|
|
499
|
+
|
|
500
|
+
```js
|
|
501
|
+
await client.call({
|
|
502
|
+
method: 'Runtime.evaluate',
|
|
503
|
+
params: {
|
|
504
|
+
target: {
|
|
505
|
+
name: 'events',
|
|
506
|
+
binding: 'send_to_host',
|
|
507
|
+
runtime: true,
|
|
508
|
+
network: false,
|
|
509
|
+
create_params: {
|
|
510
|
+
background: false,
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
expression: 'document.title',
|
|
514
|
+
returnByValue: true,
|
|
515
|
+
},
|
|
516
|
+
})
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
| Option | Default | Meaning / purpose of default |
|
|
520
|
+
| --- | --- | --- |
|
|
521
|
+
| `name` | required in an object | Logical label in this browser's `targets` mapping. |
|
|
522
|
+
| `targetId` | `null` | Optional existing physical target ID. Reused if discovered; otherwise create a new target. |
|
|
523
|
+
| `create_params` | `{}` | Native creation overrides, merged over `url: 'about:blank'` and `background: true`; start from a blank target without requesting foreground activation. |
|
|
524
|
+
| `initialize` | `true` | Run the convenience setup sequence; false skips it. |
|
|
525
|
+
| `runtime` | `'bootstrap'` | Enable Runtime for setup, then disable reporting. `true` leaves it enabled; `false` skips both operations. |
|
|
526
|
+
| `page` | `true` | Enable Page domain reporting for navigation/page operations and events. |
|
|
527
|
+
| `network` | `true` | Enable Network reporting so native network events are available. |
|
|
528
|
+
| `service_worker` | `true` | Enable ServiceWorker reporting. |
|
|
529
|
+
| `focus_emulation` | `true` | Request target focus emulation, including when the actual window is not focused. |
|
|
530
|
+
| `binding` | `'_send_to_cdp'` | Default page-to-host JavaScript binding. String changes its name; false skips installation; true selects the default name. |
|
|
531
|
+
| `background_service` | `true` | Clear, observe and record `pushMessaging` background-service events in Chromium. |
|
|
532
|
+
|
|
533
|
+
Domain options set to false skip setup commands; they do not actively disable a
|
|
534
|
+
domain already enabled by another caller. Likewise, `binding: false` does not
|
|
535
|
+
remove a previously installed binding. Use native CDP commands for immediate
|
|
536
|
+
changes. `initialize: false` skips binding installation too;
|
|
537
|
+
`Runtime.runIfWaitingForDebugger` is still sent at the end. Auto-attachment uses
|
|
538
|
+
`waitForDebuggerOnStart: false`.
|
|
539
|
+
|
|
540
|
+
Setup CDP errors are collected as strings in `target.setup_errors`, allowing the
|
|
541
|
+
sequence to continue when a browser/target does not support a setup command.
|
|
542
|
+
Transport failures and timeouts reject initialization. Errors from the caller's
|
|
543
|
+
actual native request reject normally.
|
|
544
|
+
|
|
545
|
+
The first request creates/selects a target, attaches a flattened session and
|
|
546
|
+
runs setup. Concurrent requests share that work. Detachment invalidates the
|
|
547
|
+
cached session; destruction/crash invalidates target discovery information.
|
|
548
|
+
Later use reattaches or creates a target as needed. Reconnection retains labels
|
|
549
|
+
and configuration, reuses surviving physical targets and reapplies setup.
|
|
550
|
+
Failed commands are never replayed.
|
|
551
|
+
|
|
552
|
+
Navigation readiness is the caller's responsibility. For example, with one
|
|
553
|
+
selected target and no other concurrent navigation:
|
|
554
|
+
|
|
555
|
+
```js
|
|
556
|
+
import { util } from './cdp.js'
|
|
557
|
+
|
|
558
|
+
await client.call({
|
|
559
|
+
method: 'Page.enable',
|
|
560
|
+
params: {
|
|
561
|
+
target: 'demo',
|
|
562
|
+
},
|
|
563
|
+
})
|
|
564
|
+
const loaded = util.on_first(client, 'Page.loadEventFired')
|
|
565
|
+
await client.call({
|
|
566
|
+
method: 'Page.navigate',
|
|
567
|
+
params: {
|
|
568
|
+
target: 'demo',
|
|
569
|
+
url: 'data:text/html,<title>Example</title><p>Ready</p>',
|
|
570
|
+
},
|
|
571
|
+
})
|
|
572
|
+
await loaded
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
## XPath custom methods
|
|
576
|
+
|
|
577
|
+
Both built-ins require `params.target`; `params.browser` defaults to `main`
|
|
578
|
+
through the normal router. They use `Runtime.evaluate` with `returnByValue`,
|
|
579
|
+
`awaitPromise`, `silent` and `userGesture` set to true: serialize the result,
|
|
580
|
+
await async page code, suppress evaluation exception reporting, and evaluate
|
|
581
|
+
with a user gesture respectively.
|
|
582
|
+
|
|
583
|
+
| Method | Parameters | Remote result in `response.result.value` |
|
|
584
|
+
| --- | --- | --- |
|
|
585
|
+
| `_.click` | `xpath` string; `attempts` number, default `5`; `interval_ms` number, default `300` | True after the first matching node's `.click()`. False when no node is found after the attempts or the node has no click function. |
|
|
586
|
+
| `_.find` | `xpath` string; `limit` number, default `20` | `{ count, items }`: total matches and at most `limit` serialized nodes. |
|
|
587
|
+
|
|
588
|
+
The click defaults provide a short wait for a node to appear; the find limit
|
|
589
|
+
bounds returned item data. Use positive integer attempt counts and non-negative
|
|
590
|
+
integer limits. Click waits only between unsuccessful attempts. It calls DOM
|
|
591
|
+
`.click()`, not mouse movement or coordinate input. `_.find` does not retry.
|
|
592
|
+
|
|
593
|
+
| Find item field | Meaning |
|
|
594
|
+
| --- | --- |
|
|
595
|
+
| `node_type`, `node_name` | DOM `nodeType` and `nodeName`; non-element nodes are supported. |
|
|
596
|
+
| `text` | Trimmed `innerText` or `textContent`, limited to 2,000 characters to bound returned text. |
|
|
597
|
+
| `tag` | Lowercase `tagName`, when present. |
|
|
598
|
+
| `id`, `href`, `value` | Corresponding DOM properties, when present. |
|
|
599
|
+
| `class` | String form of `className`, when present. |
|
|
600
|
+
| `rect` | `getBoundingClientRect().toJSON()` for nodes that support it. |
|
|
601
|
+
|
|
602
|
+
Absent optional properties may be omitted by serialization. `count` is the full
|
|
603
|
+
XPath snapshot length, even when `items` is limited or empty.
|
|
604
|
+
|
|
605
|
+
`util.normalize_xpath(xpath)` rewrites `ends-with(a, b)` and ASCII
|
|
606
|
+
`icontains(a, b)` into XPath 1 expressions. These are regular-expression rewrites,
|
|
607
|
+
not a complete parser; arbitrary nested or comma-containing arguments are outside
|
|
608
|
+
that rewriting logic. Ordinary XPath expressions pass through unchanged.
|
|
609
|
+
|
|
610
|
+
`client.evaluate_xpath(params, fn, options)` is available for other helpers:
|
|
611
|
+
|
|
612
|
+
```js
|
|
613
|
+
const text = await client.evaluate_xpath({
|
|
614
|
+
target: 'demo',
|
|
615
|
+
xpath: '//p',
|
|
616
|
+
}, xpath => document.evaluate(
|
|
617
|
+
xpath,
|
|
618
|
+
document,
|
|
619
|
+
null,
|
|
620
|
+
XPathResult.FIRST_ORDERED_NODE_TYPE,
|
|
621
|
+
null,
|
|
622
|
+
).singleNodeValue?.textContent)
|
|
623
|
+
console.log(text.result.value)
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
`params` supplies `browser`, `target` and `xpath`. `fn` is serialized and called in
|
|
627
|
+
the target as `fn(normalizedXPath, options)`; it cannot capture Node.js variables
|
|
628
|
+
or imported helpers. `options` must be JSON-serializable; omission becomes null
|
|
629
|
+
in the argument array. Results retain native `exceptionDetails` if page code throws.
|
|
630
|
+
|
|
631
|
+
### Register, replace or remove handlers
|
|
632
|
+
|
|
633
|
+
`client.custom_methods` is an ordinary public object with a separate copy of the
|
|
634
|
+
built-ins per client. Assign or delete keys directly; there are no registration
|
|
635
|
+
methods. Only method names starting with `_.` use this dispatch path.
|
|
636
|
+
|
|
637
|
+
```js
|
|
638
|
+
client.custom_methods['_.title'] = function (params) {
|
|
639
|
+
return this.call({
|
|
640
|
+
method: 'Runtime.evaluate',
|
|
641
|
+
params: {
|
|
642
|
+
...params,
|
|
643
|
+
expression: 'document.title',
|
|
644
|
+
returnByValue: true,
|
|
645
|
+
},
|
|
646
|
+
})
|
|
647
|
+
}
|
|
648
|
+
const title = await client.call({
|
|
649
|
+
method: '_.title',
|
|
650
|
+
params: {
|
|
651
|
+
target: 'demo',
|
|
652
|
+
},
|
|
653
|
+
})
|
|
654
|
+
console.log(title.result.value)
|
|
655
|
+
|
|
656
|
+
client.custom_methods['_.click'] = async function (params) {
|
|
657
|
+
return { handled: params.xpath }
|
|
658
|
+
}
|
|
659
|
+
delete client.custom_methods['_.find']
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
Handlers receive the original `params`, with `this` bound to the `cdp` instance.
|
|
663
|
+
Use a regular function when that binding is needed. They run before automatic
|
|
664
|
+
browser/target resolution, may be synchronous or asynchronous, and define their
|
|
665
|
+
own return value. Their exceptions propagate. An unregistered `_.` name rejects
|
|
666
|
+
without launching a browser.
|
|
667
|
+
|
|
668
|
+
## Events and bindings
|
|
669
|
+
|
|
670
|
+
| Emitter / event | `event.detail` |
|
|
671
|
+
| --- | --- |
|
|
672
|
+
| `client`, `notify` | CDP message with browser and, when known, target labels added to `params`. |
|
|
673
|
+
| `client`, native method such as `Runtime.bindingCalled` | That message's routed parameters. |
|
|
674
|
+
| `client`, `close` | `{ browser, code }` for closure of the current browser socket. |
|
|
675
|
+
| `socket`, `notify` | The unmodified CDP notification from the raw transport. |
|
|
676
|
+
|
|
677
|
+
Labels are strings, not record objects. Native `sessionId` remains available on
|
|
678
|
+
messages that carry it. Events are delivered directly: there is no history,
|
|
679
|
+
polling API or library-level filtering. Use normal event listeners and inspect
|
|
680
|
+
labels when handling several targets.
|
|
681
|
+
|
|
682
|
+
```js
|
|
683
|
+
client.addEventListener('Runtime.bindingCalled', event => {
|
|
684
|
+
const { browser, target, name, payload } = event.detail
|
|
685
|
+
console.log(browser, target, name, payload)
|
|
686
|
+
})
|
|
687
|
+
await client.call({
|
|
688
|
+
method: 'Runtime.evaluate',
|
|
689
|
+
params: {
|
|
690
|
+
target: {
|
|
691
|
+
name: 'bridge',
|
|
692
|
+
binding: 'send_to_host',
|
|
693
|
+
runtime: true,
|
|
694
|
+
},
|
|
695
|
+
expression: 'send_to_host(JSON.stringify({ hello: "world" }))',
|
|
696
|
+
},
|
|
697
|
+
})
|
|
698
|
+
console.log(client.browsers.main.targets.bridge.binding) // send_to_host
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
Bindings accept a string payload. `runtime: true` keeps reporting enabled for
|
|
702
|
+
ongoing binding and console events; bootstrap mode disables Runtime after setup.
|
|
703
|
+
The configured binding name lives on the target record and is reapplied during
|
|
704
|
+
subsequent initialization.
|
|
705
|
+
|
|
706
|
+
`util.on_first(target, 'open error close', timeout_ms)` supports EventTarget and
|
|
707
|
+
EventEmitter. For EventTarget, `args[0]` is the event; for EventEmitter, `args` is
|
|
708
|
+
the emitted argument list. The helper removes listeners and cancels its timer
|
|
709
|
+
after completion. Timeout rejects with `AbortError`; EventEmitter error handling
|
|
710
|
+
follows Node.js `events.once` semantics.
|
|
711
|
+
|
|
712
|
+
## Public records
|
|
713
|
+
|
|
714
|
+
Mappings use object indexing, not `Map` instances or accessor methods. Some
|
|
715
|
+
dictionary containers have a null prototype.
|
|
716
|
+
|
|
717
|
+
| Path | Contents |
|
|
718
|
+
| --- | --- |
|
|
719
|
+
| `client.base_path` | Resolved profile root. |
|
|
720
|
+
| `client.options` | Constructor browser defaults, excluding `base_path`. |
|
|
721
|
+
| `client.custom_methods[name]` | Handler function. |
|
|
722
|
+
| `client.browsers[name]` | Browser configuration fields plus live state. |
|
|
723
|
+
| `record.socket` | Current `jsrpc` connection once created. |
|
|
724
|
+
| `record.proc` | Owned child process; absent for external attachment. |
|
|
725
|
+
| `record.connecting` | In-progress connection promise, cleared after settlement. |
|
|
726
|
+
| `record.targets[label]` | Target options, physical `targetId`, `sessionId`, `connecting` and `setup_errors` after setup. |
|
|
727
|
+
| `record.target_info[targetId]` | Discovered native target info plus cached `sessionId` when attached. |
|
|
728
|
+
| `record.session_targets[sessionId]` | Physical `targetId` for a session. |
|
|
729
|
+
| `socket.pending[id]` | Response-wait promise, removed on completion. |
|
|
730
|
+
| `socket.id`, `socket.timeout_ms` | Request counter and effective timeout. |
|
|
731
|
+
|
|
732
|
+
```js
|
|
733
|
+
const record = client.browsers.main
|
|
734
|
+
const target = record.targets.demo
|
|
735
|
+
console.log(target.targetId, target.sessionId, target.binding)
|
|
736
|
+
console.log(target.setup_errors)
|
|
737
|
+
console.log(record.target_info[target.targetId])
|
|
738
|
+
console.log(record.session_targets[target.sessionId])
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
Mappings appear as their connection/setup steps run and are updated by events.
|
|
742
|
+
`target_info` and `session_targets` are rebuilt on reconnection. They are live,
|
|
743
|
+
mutable state, not persistent snapshots.
|
|
744
|
+
|
|
745
|
+
## Raw transport and standalone launch
|
|
746
|
+
|
|
747
|
+
This complete example bypasses the manager:
|
|
748
|
+
|
|
749
|
+
```js
|
|
750
|
+
import { browser, jsrpc, util } from './cdp.js'
|
|
751
|
+
import * as path from 'node:path'
|
|
752
|
+
|
|
753
|
+
const launched = await browser.launch({
|
|
754
|
+
user_data_dir: path.resolve('./profiles/raw'),
|
|
755
|
+
headless: true,
|
|
756
|
+
})
|
|
757
|
+
const socket = new jsrpc(launched.url, {
|
|
758
|
+
request_timeout_ms: 10000,
|
|
759
|
+
})
|
|
760
|
+
try {
|
|
761
|
+
await util.on_first(socket, 'open error close')
|
|
762
|
+
console.log(await socket.req({
|
|
763
|
+
method: 'Browser.getVersion',
|
|
764
|
+
}, 5000))
|
|
765
|
+
await socket.req({ method: 'Browser.close' })
|
|
766
|
+
} finally {
|
|
767
|
+
socket.close()
|
|
768
|
+
launched.proc.kill()
|
|
769
|
+
}
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
`browser.launch` requires a usable absolute directory through `user_data_dir` or
|
|
773
|
+
`args['user-data-dir']`; this helper does not resolve that path for you. It writes
|
|
774
|
+
preferences, starts the process, reads the
|
|
775
|
+
DevTools WebSocket URL from stderr and returns `{ proc, url }`. It does not open
|
|
776
|
+
a CDP connection. Readiness timeout or launch failure rejects and attempts to
|
|
777
|
+
terminate the spawned process.
|
|
778
|
+
|
|
779
|
+
`jsrpc` takes a WebSocket URL and an options object whose recognized option is
|
|
780
|
+
`request_timeout_ms` (default `30000`). Wait for the socket to open before `req`.
|
|
781
|
+
The request is a raw envelope: `method`, optional `params`, and optional top-level
|
|
782
|
+
`sessionId`. `req` assigns its own incrementing ID even if the input contains one.
|
|
783
|
+
Its second argument overrides the timeout for that request. There are no browser
|
|
784
|
+
labels, target labels, custom methods or reconnection policy in this layer.
|
|
785
|
+
|
|
786
|
+
## Errors and timeouts
|
|
787
|
+
|
|
788
|
+
| Situation | Behavior |
|
|
789
|
+
| --- | --- |
|
|
790
|
+
| CDP returns `error` | Reject with `Error`; response in `error.cdp`, request/response in `error.cause.req` / `.ret`. |
|
|
791
|
+
| Page JavaScript throws during evaluation | Native result may contain `exceptionDetails`; not converted to a rejected promise. |
|
|
792
|
+
| Request times out | Reject with `AbortError`, clear local waiting state; Chromium may still execute the command. |
|
|
793
|
+
| Socket closes during a request | Reject the pending request; no automatic replay. |
|
|
794
|
+
| `req` before the socket opens | Reject with a connection-state error. |
|
|
795
|
+
| Unknown `_.` handler | Reject before browser creation. |
|
|
796
|
+
| Invalid profile JSON or filesystem failure | Propagate the parsing/filesystem error. |
|
|
797
|
+
| Failed discovery or local launch | Reject the call establishing the connection. |
|
|
798
|
+
|
|
799
|
+
```js
|
|
800
|
+
try {
|
|
801
|
+
await client.call({
|
|
802
|
+
method: 'NoSuchDomain.noSuchMethod',
|
|
803
|
+
params: {
|
|
804
|
+
target: 'demo',
|
|
805
|
+
},
|
|
806
|
+
})
|
|
807
|
+
} catch (error) {
|
|
808
|
+
console.error(error.message)
|
|
809
|
+
if (error.cdp) console.error(error.cdp.error.code)
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
## Development
|
|
814
|
+
|
|
815
|
+
Contributors and coding agents should read [AGENTS.md](AGENTS.md) and
|
|
816
|
+
[DEV_PREF.md](DEV_PREF.md). The maintained implementation is [cdp.js](cdp.js).
|
|
817
|
+
`extra/`, when present locally, holds ignored reference files and is not part of
|
|
818
|
+
the tracked source or runtime dependencies.
|
|
819
|
+
|
|
820
|
+
[Manual chat monitoring](tests/chat-monitoring.md) documents the observed network
|
|
821
|
+
workflow for detecting new conversations and extracting connector session handles
|
|
822
|
+
from tool-call history. It is a caller-side recipe, not additional library API.
|
|
823
|
+
|
|
824
|
+
For npm packaging, account setup, and GitHub publishing, see
|
|
825
|
+
[Publishing](npm/PUBLISHING.md). `build.bat` prepares the package on Windows;
|
|
826
|
+
`node npm/prepare.mjs` prepares its files on any supported Node platform.
|
|
827
|
+
|
|
828
|
+
```sh
|
|
829
|
+
node --check cdp.js
|
|
830
|
+
node --test tests/cdp.test.js
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
Integration tests launch local headless Chromium with disposable profiles under
|
|
834
|
+
`build/tests/`. Set `CDP_BROWSER` if discovery does not match the machine. Direct
|
|
835
|
+
library use needs no build or package installation; npm packaging is optional.
|