@mefistofelix/cdp.js 0.5.0 → 0.5.1
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 +39 -9
- package/cdp.js +3 -5
- package/cdp_ext/cdp_ext.js +48 -9
- package/cdp_ext/manifest.json +1 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -542,8 +542,8 @@ await client.call({
|
|
|
542
542
|
Provide `user_data_dir` or raw `args['user-data-dir']` to choose a custom
|
|
543
543
|
directory. An effective custom directory makes `cdp_ext_install` default to true:
|
|
544
544
|
the manager copies the two extension files into
|
|
545
|
-
`<user-data-dir>/<profile-directory>/cdp_ext/` (`Default` when unset)
|
|
546
|
-
|
|
545
|
+
`<user-data-dir>/<profile-directory>/cdp_ext/` (`Default` when unset) and adds
|
|
546
|
+
startup loading flags. The server address comes only from the trigger URL. Normal launch
|
|
547
547
|
options and profile preferences then apply. Set `cdp_ext_install: false` to use
|
|
548
548
|
an extension already installed in that profile, or true to force preparation and
|
|
549
549
|
loading. A null/false raw directory override makes automatic installation default off.
|
|
@@ -568,6 +568,13 @@ and enable the bridge. An `extensions` array adds its directories;
|
|
|
568
568
|
`extensions: true` retains enabled profile extensions through `'*'`. Raw `args`
|
|
569
569
|
still win and can prevent loading or connection.
|
|
570
570
|
|
|
571
|
+
Both launch paths keep `--no-first-run` and
|
|
572
|
+
`--disable-search-engine-choice-screen`, including when opening a new custom
|
|
573
|
+
profile with installation disabled. This suppresses onboarding and the search
|
|
574
|
+
engine selection prompt without changing the chosen search provider or writing
|
|
575
|
+
search preferences. Raw `args` can override either flag. An existing Chrome only
|
|
576
|
+
receives the URL; new startup flags require restarting that instance.
|
|
577
|
+
|
|
571
578
|
The manager opens an actual local HTTP URL on the shared listener, for example
|
|
572
579
|
`http://127.0.0.1:9223/cdp_ext?browser=work&websocket_url=...&token=...`.
|
|
573
580
|
The port is the effective listening port, including an automatically allocated
|
|
@@ -590,15 +597,22 @@ manager while connected returns an explicit error, preserving the existing
|
|
|
590
597
|
connection. After disconnection, a new bootstrap can rebind it.
|
|
591
598
|
|
|
592
599
|
Passive external attachment remains available through `reverse: true`: it opens
|
|
593
|
-
no URL and waits for `extension_id` (or the browser label).
|
|
594
|
-
|
|
595
|
-
|
|
600
|
+
no URL and waits for `extension_id` (or the browser label). This compatibility
|
|
601
|
+
mode is optional; `cdp_ext: true` needs neither `reverse` nor an ID.
|
|
602
|
+
The current extension still requires a trigger URL in passive mode; it never
|
|
603
|
+
connects automatically to a manifest endpoint or a default port.
|
|
604
|
+
|
|
605
|
+
The extension stays idle until a valid trigger URL supplies the logical name,
|
|
606
|
+
WebSocket endpoint and token. Before that it makes no server requests and logs
|
|
607
|
+
no connection messages. A worker restart may resume the same browser session's
|
|
608
|
+
previous trigger from `chrome.storage.session`.
|
|
596
609
|
|
|
597
|
-
The manifest
|
|
610
|
+
The shipped manifest needs no custom configuration keys. An optional custom
|
|
611
|
+
`cdp.reconnect_ms` override remains supported (Chrome displays a harmless
|
|
612
|
+
unrecognized-key warning if it is added):
|
|
598
613
|
|
|
599
614
|
| Manifest `cdp` key | Default | Meaning |
|
|
600
615
|
| --- | --- | --- |
|
|
601
|
-
| `websocket_url` | `ws://127.0.0.1:9223` | Initial shared endpoint; URL bootstrap overrides it. |
|
|
602
616
|
| `reconnect_ms` | `5000` | Awake retry and connected heartbeat interval; use a positive value below 30000. |
|
|
603
617
|
|
|
604
618
|
Construction and direct CDP calls do not start a listener. The first browser call
|
|
@@ -662,10 +676,20 @@ another connection attempt; the configured interval applies while it is awake.
|
|
|
662
676
|
Connected empty-text heartbeats keep an otherwise idle WebSocket worker active.
|
|
663
677
|
These are transport messages, not event buffering or polling of browser state.
|
|
664
678
|
|
|
679
|
+
After a trigger, the server may be offline normally. Before each disconnected
|
|
680
|
+
WebSocket attempt the extension checks the same server's HTTP `/cdp_ext` endpoint
|
|
681
|
+
with a two-second timeout and no cache. It opens the socket only when that
|
|
682
|
+
endpoint identifies CDP.js. Concurrent retries share the check; an unavailable or
|
|
683
|
+
incompatible server causes one informational waiting message, not a failing
|
|
684
|
+
WebSocket attempt on every timer tick. Successful connections and later
|
|
685
|
+
disconnects log their status once per transition. Chrome can still emit a native
|
|
686
|
+
network diagnostic if the server disappears between the HTTP check and upgrade.
|
|
687
|
+
|
|
665
688
|
### Reverse protocol and supported commands
|
|
666
689
|
|
|
667
|
-
The first announcement contains `{ browser, extension_id, token }`
|
|
668
|
-
|
|
690
|
+
The current extension's first announcement contains `{ browser, extension_id, token }`
|
|
691
|
+
after a trigger. The server also accepts legacy native-ID announcements.
|
|
692
|
+
Subsequent messages use CDP envelopes:
|
|
669
693
|
|
|
670
694
|
- Request: `{ id, method, params, sessionId? }`.
|
|
671
695
|
- Response: `{ id, result }` or `{ id, error: { code, message } }`.
|
|
@@ -1805,5 +1829,11 @@ already running instance, startup when absent, one shared extension directory,
|
|
|
1805
1829
|
logical names, binding tokens, conflicting names and preservation on manager close.
|
|
1806
1830
|
Installation defaults, raw directory overrides, profile writes independent of
|
|
1807
1831
|
installation and shared wildcard expansion are covered without opening personal profiles.
|
|
1832
|
+
Argument coverage crosses direct/extension launch modes with headless, proxy,
|
|
1833
|
+
image/login/translation options, extension selectors and raw overrides. Profile
|
|
1834
|
+
combinations include default/custom directories, null/false raw directory
|
|
1835
|
+
overrides, forced installation and independent preference-write controls.
|
|
1836
|
+
Offline worker checks verify silence before a trigger, deduplicated waiting logs,
|
|
1837
|
+
no WebSocket attempts against absent/incompatible servers and concurrent retry checks.
|
|
1808
1838
|
The npm tarball contains `package.json`, `cdp.js`, `README.md` and the two extension
|
|
1809
1839
|
files required by managed reverse launches.
|
package/cdp.js
CHANGED
|
@@ -153,12 +153,10 @@ export class browser {
|
|
|
153
153
|
'disable-prompt-on-repost': true,
|
|
154
154
|
'force-color-profile': 'srgb',
|
|
155
155
|
'metrics-recording-only': true,
|
|
156
|
-
'no-first-run': true,
|
|
157
156
|
'password-store': 'basic',
|
|
158
157
|
'use-mock-keychain': true,
|
|
159
158
|
'no-service-autorun': true,
|
|
160
159
|
'export-tagged-pdf': true,
|
|
161
|
-
'disable-search-engine-choice-screen': true,
|
|
162
160
|
'disable-features': [
|
|
163
161
|
'InfiniteSessionRestore',
|
|
164
162
|
'ImprovedCookieControls',
|
|
@@ -177,6 +175,8 @@ export class browser {
|
|
|
177
175
|
'user-data-dir': options.user_data_dir,
|
|
178
176
|
'remote-debugging-port': 0,
|
|
179
177
|
}
|
|
178
|
+
args['no-first-run'] = true
|
|
179
|
+
args['disable-search-engine-choice-screen'] = true
|
|
180
180
|
if (options.headless) {
|
|
181
181
|
args.headless = 'new'
|
|
182
182
|
args['window-size'] = '1440,900'
|
|
@@ -658,9 +658,7 @@ export class cdp extends EventTarget {
|
|
|
658
658
|
await fs.mkdir(record.extension_path, { recursive: true })
|
|
659
659
|
record.extension_path = await fs.realpath(record.extension_path)
|
|
660
660
|
record.extension_id = browser.extension_id(record.extension_path)
|
|
661
|
-
|
|
662
|
-
manifest.cdp.websocket_url = record.reverse_url
|
|
663
|
-
await fs.writeFile(path.join(record.extension_path, 'manifest.json'), JSON.stringify(manifest))
|
|
661
|
+
await fs.copyFile(new URL('./cdp_ext/manifest.json', import.meta.url), path.join(record.extension_path, 'manifest.json'))
|
|
664
662
|
await fs.copyFile(new URL('./cdp_ext/cdp_ext.js', import.meta.url), path.join(record.extension_path, 'cdp_ext.js'))
|
|
665
663
|
}
|
|
666
664
|
if (args['user-data-dir'] && record.update_preferences !== false) {
|
package/cdp_ext/cdp_ext.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const config =
|
|
1
|
+
const config = {
|
|
2
|
+
reconnect_ms: chrome.runtime.getManifest().cdp?.reconnect_ms ?? 5000,
|
|
3
|
+
}
|
|
2
4
|
const configured = chrome.storage.session.get('cdp_bootstrap').then(value => Object.assign(config, value.cdp_bootstrap))
|
|
3
5
|
const sessions = {}
|
|
4
6
|
const attached = {}
|
|
@@ -8,6 +10,14 @@ let disconnecting
|
|
|
8
10
|
let discovering = false
|
|
9
11
|
let auto_attach = {}
|
|
10
12
|
let bootstrapping
|
|
13
|
+
let checking = false
|
|
14
|
+
let connection_message
|
|
15
|
+
|
|
16
|
+
function report_connection(message) {
|
|
17
|
+
if (connection_message === message) return
|
|
18
|
+
connection_message = message
|
|
19
|
+
console.info('[cdp_ext] ' + message)
|
|
20
|
+
}
|
|
11
21
|
|
|
12
22
|
async function bootstrap(tab) {
|
|
13
23
|
const text = tab.pendingUrl ?? tab.url ?? ''
|
|
@@ -245,15 +255,43 @@ for (const [name, options] of Object.entries({
|
|
|
245
255
|
|
|
246
256
|
async function connect() {
|
|
247
257
|
await configured
|
|
248
|
-
if (
|
|
258
|
+
if (!config.browser || !config.websocket_url || !config.token) return
|
|
259
|
+
if (disconnecting || checking) return
|
|
249
260
|
if (socket?.readyState === WebSocket.CONNECTING) return
|
|
250
261
|
if (socket?.readyState === WebSocket.OPEN) return socket.send('')
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
262
|
+
const endpoint = config.websocket_url
|
|
263
|
+
const url = new URL(endpoint)
|
|
264
|
+
url.protocol = url.protocol === 'wss:' ? 'https:' : 'http:'
|
|
265
|
+
url.pathname = '/cdp_ext'
|
|
266
|
+
url.search = ''
|
|
267
|
+
url.hash = ''
|
|
268
|
+
let available = false
|
|
269
|
+
checking = true
|
|
270
|
+
try {
|
|
271
|
+
const response = await fetch(url, {
|
|
272
|
+
cache: 'no-store',
|
|
273
|
+
signal: AbortSignal.timeout(2000),
|
|
274
|
+
})
|
|
275
|
+
available = response.ok && await response.text() === 'CDP.js browser connection'
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if (!(error instanceof TypeError) && error.name !== 'TimeoutError') throw error
|
|
278
|
+
} finally {
|
|
279
|
+
checking = false
|
|
280
|
+
}
|
|
281
|
+
if (endpoint !== config.websocket_url) return connect()
|
|
282
|
+
if (!available) {
|
|
283
|
+
report_connection('Waiting for CDP.js server at ' + endpoint + '; retrying automatically.')
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
const connection = socket = new WebSocket(endpoint)
|
|
287
|
+
connection.onopen = () => {
|
|
288
|
+
report_connection('Connected to CDP.js server at ' + endpoint + '.')
|
|
289
|
+
connection.send(JSON.stringify({
|
|
290
|
+
browser: config.browser,
|
|
291
|
+
extension_id: chrome.runtime.id,
|
|
292
|
+
token: config.token,
|
|
293
|
+
}))
|
|
294
|
+
}
|
|
257
295
|
connection.onmessage = async event => {
|
|
258
296
|
if (!event.data) return
|
|
259
297
|
const request = JSON.parse(event.data)
|
|
@@ -300,6 +338,7 @@ async function connect() {
|
|
|
300
338
|
if (id != null && connection.readyState === WebSocket.OPEN) connection.send(JSON.stringify(response))
|
|
301
339
|
}
|
|
302
340
|
connection.onclose = () => {
|
|
341
|
+
report_connection('Waiting for CDP.js server at ' + endpoint + '; retrying automatically.')
|
|
303
342
|
discovering = false
|
|
304
343
|
disconnecting = Promise.all(Object.keys(attached).map(id => {
|
|
305
344
|
const source = { tabId: Number(id) }
|
|
@@ -323,5 +362,5 @@ async function start() {
|
|
|
323
362
|
chrome.runtime.onStartup.addListener(start)
|
|
324
363
|
chrome.alarms.onAlarm.addListener(connect)
|
|
325
364
|
chrome.alarms.create('cdp-reconnect', { periodInMinutes: 0.5 })
|
|
326
|
-
setInterval(connect, config.reconnect_ms
|
|
365
|
+
setInterval(connect, config.reconnect_ms)
|
|
327
366
|
start()
|
package/cdp_ext/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "CDP reverse connection",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"minimum_chrome_version": "125",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"accessibilityFeatures.read",
|
|
@@ -68,9 +68,5 @@
|
|
|
68
68
|
"incognito": "spanning",
|
|
69
69
|
"background": {
|
|
70
70
|
"service_worker": "cdp_ext.js"
|
|
71
|
-
},
|
|
72
|
-
"cdp": {
|
|
73
|
-
"websocket_url": "ws://127.0.0.1:9223",
|
|
74
|
-
"reconnect_ms": 5000
|
|
75
71
|
}
|
|
76
72
|
}
|
package/package.json
CHANGED