From 9745f9214cb8495f020fcbd7c54b0bb4fc085678 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Tue, 29 Dec 2020 15:50:15 -0500 Subject: [PATCH 01/15] feat: support for --remote-debugging-pipe transport --- README.md | 8 +++- lib/chrome.js | 107 +++++++++++++++++++++++++------------------ lib/stdio-wrapper.js | 87 +++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 47 deletions(-) create mode 100644 lib/stdio-wrapper.js diff --git a/README.md b/README.md index 86c4dfe..d77d941 100644 --- a/README.md +++ b/README.md @@ -456,8 +456,12 @@ Connects to a remote instance using the [Chrome Debugging Protocol]. - `protocol`: [Chrome Debugging Protocol] descriptor object. Defaults to use the protocol chosen according to the `local` option; - `local`: a boolean indicating whether the protocol must be fetched *remotely* - or if the local version must be used. It has no effect if the `protocol` - option is set. Defaults to `false`. + or if the local version must be used. It has no effect if the `protocol` or + `process` option is set. Defaults to `false`. +- `process`: a `ChildProcess` object that represents a Chrome instance launched + with `--remote-debugging-pipe`. If passed, websocket-related options will be + ignored and communications will occur over stdio instead. Note: the `protocol` + cannot be fetched remotely if a `process` is passed. These options are also valid properties of all the instances of the `CDP` class. In addition to that, the `webSocketUrl` field contains the currently used diff --git a/lib/chrome.js b/lib/chrome.js index 2bd6946..8e8a455 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -10,6 +10,7 @@ const WebSocket = require('ws'); const api = require('./api.js'); const defaults = require('./defaults.js'); const devtools = require('./devtools.js'); +const StdioWrapper = require('./stdio-wrapper.js'); class ProtocolError extends Error { constructor(request, response) { @@ -55,9 +56,10 @@ class Chrome extends EventEmitter { this.useHostName = !!(options.useHostName); this.alterPath = options.alterPath || ((path) => path); this.protocol = options.protocol; - this.local = !!(options.local); + this.local = !!(options.local || options.process); this.target = options.target || defaultTarget; this.connectOptions = options.connectOptions; + this.process = options.process; // locals this._notifier = notifier; this._callbacks = {}; @@ -104,27 +106,12 @@ class Chrome extends EventEmitter { } close(callback) { - const closeWebSocket = (callback) => { - // don't close if it's already closed - if (this._ws.readyState === 3) { - callback(); - } else { - // don't notify on user-initiated shutdown ('disconnect' event) - this._ws.removeAllListeners('close'); - this._ws.once('close', () => { - this._ws.removeAllListeners(); - this._handleConnectionClose(); - callback(); - }); - this._ws.close(); - } - }; if (typeof callback === 'function') { - closeWebSocket(callback); + this._close(callback); return undefined; } else { return new Promise((fulfill, reject) => { - closeWebSocket(fulfill); + this._close(fulfill); }); } } @@ -140,20 +127,22 @@ class Chrome extends EventEmitter { ...this.connectOptions, }; try { - // fetch the WebSocket debugger URL - const url = await this._fetchDebuggerURL(options); - // allow the user to alter the URL - const urlObject = parseUrl(url); - urlObject.pathname = options.alterPath(urlObject.pathname); - this.webSocketUrl = formatUrl(urlObject); - // update the connection parameters using the debugging URL - options.host = urlObject.hostname; - options.port = urlObject.port || options.port; + if (!this.process) { + // fetch the WebSocket debugger URL + const url = await this._fetchDebuggerURL(options); + // allow the user to alter the URL + const urlObject = parseUrl(url); + urlObject.pathname = options.alterPath(urlObject.pathname); + this.webSocketUrl = formatUrl(urlObject); + // update the connection parameters using the debugging URL + options.host = urlObject.hostname; + options.port = urlObject.port || options.port; + } // fetch the protocol and prepare the API const protocol = await this._fetchProtocol(options); api.prepare(this, protocol); - // finally connect to the WebSocket - await this._connectToWebSocket(); + // finally connect to the WebSocket or stdio + await this._connect(); // since the handler is executed synchronously, the emit() must be // performed in the next tick so that uncaught errors in the client code // are not intercepted by the Promise mechanism and therefore reported @@ -216,36 +205,64 @@ class Chrome extends EventEmitter { } } - // establish the WebSocket connection and start processing user commands - _connectToWebSocket() { + _createStdioWrapper() { + const stdio = new StdioWrapper(this.process.stdio[3], this.process.stdio[4]); + this._close = stdio.close.bind(stdio); + this._send = stdio.send.bind(stdio); + return stdio; + } + + _createWebSocketWrapper() { + if (this.secure) { + this.webSocketUrl = this.webSocketUrl.replace(/^ws:/i, 'wss:'); + } + const ws = new WebSocket(this.webSocketUrl, [], { + followRedirects: true, + ...this.connectOptions, + }); + this._close = (callback) => { + // don't close if it's already closed + if (ws.readyState === 3) { + callback(); + } else { + // don't notify on user-initiated shutdown ('disconnect' event) + ws.removeAllListeners('close'); + ws.once('close', () => { + ws.removeAllListeners(); + this._handleConnectionClose(); + callback(); + }); + ws.close(); + } + }; + this._send = ws.send.bind(ws); + return ws; + } + + // establish the connection wrapper and start processing user commands + _connect() { return new Promise((fulfill, reject) => { - // create the WebSocket + let wrapper; try { - if (this.secure) { - this.webSocketUrl = this.webSocketUrl.replace(/^ws:/i, 'wss:'); - } - this._ws = new WebSocket(this.webSocketUrl, [], { - followRedirects: true, - ...this.connectOptions - }); + wrapper = this.process ? this._createStdioWrapper() : this._createWebSocketWrapper(); } catch (err) { - // handles bad URLs + // handle missing stdio streams, bad URLs... reject(err); return; } // set up event handlers - this._ws.on('open', () => { + wrapper.on('open', () => { fulfill(); }); - this._ws.on('message', (data) => { + wrapper.on('message', (data) => { const message = JSON.parse(data); this._handleMessage(message); }); - this._ws.on('close', (code) => { + wrapper.on('close', (code) => { this._handleConnectionClose(); this.emit('disconnect'); }); - this._ws.on('error', (err) => { + wrapper.on('error', (err) => { reject(err); }); }); @@ -305,7 +322,7 @@ class Chrome extends EventEmitter { sessionId, params: params || {} }; - this._ws.send(JSON.stringify(message), (err) => { + this._send(JSON.stringify(message), (err) => { if (err) { // handle low-level WebSocket errors if (typeof callback === 'function') { diff --git a/lib/stdio-wrapper.js b/lib/stdio-wrapper.js new file mode 100644 index 0000000..2ca288c --- /dev/null +++ b/lib/stdio-wrapper.js @@ -0,0 +1,87 @@ +'use strict'; + +// Adapted from https://github.com/puppeteer/puppeteer/blob/7a2a41f2087b07e8ef1feaf3881bdcc3fd4922ca/src/PipeTransport.js + +/** + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { EventEmitter } = require('events'); + +function addEventListener(emitter, eventName, handler) { + emitter.on(eventName, handler); + return { emitter, eventName, handler }; +} + +function removeEventListeners(listeners) { + for (const listener of listeners) + listener.emitter.removeListener(listener.eventName, listener.handler); + listeners.length = 0; +} + +// wrapper for null-terminated stdio message transport +class StdioWrapper extends EventEmitter { + constructor(pipeWrite, pipeRead) { + super(); + this._pipeWrite = pipeWrite; + this._pendingMessage = ''; + this._eventListeners = [ + addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)), + addEventListener(pipeRead, 'close', () => this.emit('close')), + addEventListener(pipeRead, 'error', (err) => this.emit('error', err)), + addEventListener(pipeWrite, 'error', (err) => this.emit('error', err)), + ]; + process.nextTick(() => { + this.emit('open'); + }); + } + + send(message, callback) { + try { + this._pipeWrite.write(message); + this._pipeWrite.write('\0'); + callback(); + } catch (err) { + callback(err); + } + } + + _dispatch(buffer) { + let end = buffer.indexOf('\0'); + if (end === -1) { + this._pendingMessage += buffer.toString(); + return; + } + const message = this._pendingMessage + buffer.toString(undefined, 0, end); + + this.emit('message', message); + + let start = end + 1; + end = buffer.indexOf('\0', start); + while (end !== -1) { + this.emit('message', buffer.toString(undefined, start, end)); + start = end + 1; + end = buffer.indexOf('\0', start); + } + this._pendingMessage = buffer.toString(undefined, start); + } + + close() { + this._pipeWrite = null; + removeEventListeners(this._eventListeners); + } +} + +module.exports = StdioWrapper; From aa1de13045ac0a2f9d2640d50f1db2694f5d79e2 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Mon, 11 Jan 2021 15:00:26 -0500 Subject: [PATCH 02/15] properly call callback on close --- lib/stdio-wrapper.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/stdio-wrapper.js b/lib/stdio-wrapper.js index 2ca288c..f0370c4 100644 --- a/lib/stdio-wrapper.js +++ b/lib/stdio-wrapper.js @@ -78,9 +78,10 @@ class StdioWrapper extends EventEmitter { this._pendingMessage = buffer.toString(undefined, start); } - close() { + close(callback) { this._pipeWrite = null; removeEventListeners(this._eventListeners); + callback(); } } From c5f2d0c3999eb7633f3b635f3f3f4697d05a7636 Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Wed, 10 Sep 2025 16:39:33 +0300 Subject: [PATCH 03/15] expose ws client for backwards compat --- lib/chrome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chrome.js b/lib/chrome.js index 8e8a455..68a5c37 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -216,7 +216,7 @@ class Chrome extends EventEmitter { if (this.secure) { this.webSocketUrl = this.webSocketUrl.replace(/^ws:/i, 'wss:'); } - const ws = new WebSocket(this.webSocketUrl, [], { + const ws = this._ws = new WebSocket(this.webSocketUrl, [], { followRedirects: true, ...this.connectOptions, }); From 6f09ef05d296b3723cbea680d39e1bfee234f9de Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Tue, 16 Sep 2025 07:17:21 +0300 Subject: [PATCH 04/15] emit messages async --- lib/stdio-wrapper.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/stdio-wrapper.js b/lib/stdio-wrapper.js index f0370c4..eb41aa4 100644 --- a/lib/stdio-wrapper.js +++ b/lib/stdio-wrapper.js @@ -66,12 +66,12 @@ class StdioWrapper extends EventEmitter { } const message = this._pendingMessage + buffer.toString(undefined, 0, end); - this.emit('message', message); + setImmediate(() => this.emit('message', message)); let start = end + 1; end = buffer.indexOf('\0', start); while (end !== -1) { - this.emit('message', buffer.toString(undefined, start, end)); + setImmediate(() => this.emit('message', buffer.toString(undefined, start, end))); start = end + 1; end = buffer.indexOf('\0', start); } From b403e801e909b737dd3a330489a736e7a7525718 Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Tue, 16 Sep 2025 07:20:53 +0300 Subject: [PATCH 05/15] process.nextTick => setImmediate --- lib/stdio-wrapper.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/stdio-wrapper.js b/lib/stdio-wrapper.js index eb41aa4..8490f4b 100644 --- a/lib/stdio-wrapper.js +++ b/lib/stdio-wrapper.js @@ -43,9 +43,7 @@ class StdioWrapper extends EventEmitter { addEventListener(pipeRead, 'error', (err) => this.emit('error', err)), addEventListener(pipeWrite, 'error', (err) => this.emit('error', err)), ]; - process.nextTick(() => { - this.emit('open'); - }); + setImmediate(() => this.emit('open')); } send(message, callback) { From 1fe255580bae5ba48017eaa5be070d5e5ac08f27 Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Wed, 17 Sep 2025 15:15:50 +0300 Subject: [PATCH 06/15] revert emitting messages async --- lib/stdio-wrapper.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/stdio-wrapper.js b/lib/stdio-wrapper.js index 8490f4b..2ab1392 100644 --- a/lib/stdio-wrapper.js +++ b/lib/stdio-wrapper.js @@ -64,12 +64,12 @@ class StdioWrapper extends EventEmitter { } const message = this._pendingMessage + buffer.toString(undefined, 0, end); - setImmediate(() => this.emit('message', message)); + this.emit('message', message); let start = end + 1; end = buffer.indexOf('\0', start); while (end !== -1) { - setImmediate(() => this.emit('message', buffer.toString(undefined, start, end))); + this.emit('message', buffer.toString(undefined, start, end)); start = end + 1; end = buffer.indexOf('\0', start); } From 015efc484405185362d6710cff9a4ae1eefc5c1e Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Wed, 17 Sep 2025 15:49:09 +0300 Subject: [PATCH 07/15] expose underlying wrapper for interop --- lib/chrome.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/chrome.js b/lib/chrome.js index 68a5c37..85d3096 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -242,27 +242,28 @@ class Chrome extends EventEmitter { // establish the connection wrapper and start processing user commands _connect() { return new Promise((fulfill, reject) => { - let wrapper; try { - wrapper = this.process ? this._createStdioWrapper() : this._createWebSocketWrapper(); + this._wrapper = this.process + ? this._createStdioWrapper() + : this._createWebSocketWrapper(); } catch (err) { // handle missing stdio streams, bad URLs... reject(err); return; } // set up event handlers - wrapper.on('open', () => { + this._wrapper.on('open', () => { fulfill(); }); - wrapper.on('message', (data) => { + this._wrapper.on('message', (data) => { const message = JSON.parse(data); this._handleMessage(message); }); - wrapper.on('close', (code) => { + this._wrapper.on('close', (code) => { this._handleConnectionClose(); this.emit('disconnect'); }); - wrapper.on('error', (err) => { + this._wrapper.on('error', (err) => { reject(err); }); }); @@ -334,6 +335,7 @@ class Chrome extends EventEmitter { } }); } + get wrapper() { return this._wrapper; } } module.exports = Chrome; From 893709bf9e78885229a27ca1595a105b9805ea66 Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Sun, 21 Sep 2025 14:38:44 +0300 Subject: [PATCH 08/15] avoid binding exposed wrapper internals to allow re-binding in upper layers needed in order for debug_cdp_ws to work properly --- lib/chrome.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/chrome.js b/lib/chrome.js index 85d3096..3fc2155 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -207,8 +207,8 @@ class Chrome extends EventEmitter { _createStdioWrapper() { const stdio = new StdioWrapper(this.process.stdio[3], this.process.stdio[4]); - this._close = stdio.close.bind(stdio); - this._send = stdio.send.bind(stdio); + this._close = (...args)=>stdio.close(...args); + this._send = (...args)=>stdio.send(...args); return stdio; } @@ -235,7 +235,7 @@ class Chrome extends EventEmitter { ws.close(); } }; - this._send = ws.send.bind(ws); + this._send = (...args)=>ws.send(...args); return ws; } From 1958af843fb022338090ffd38ace63fdb3e89c4d Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Mon, 29 Sep 2025 17:05:55 +0300 Subject: [PATCH 09/15] wrapper => transport --- lib/chrome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chrome.js b/lib/chrome.js index 3fc2155..c43eb1d 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -335,7 +335,7 @@ class Chrome extends EventEmitter { } }); } - get wrapper() { return this._wrapper; } + get transport() { return this._wrapper; } } module.exports = Chrome; From 725f9c680f03babcfcbf030fddeaed32cbe749fd Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Sun, 19 Oct 2025 18:44:59 +0300 Subject: [PATCH 10/15] fix hanging when attempting to write to a closed pipe --- lib/stdio-wrapper.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/stdio-wrapper.js b/lib/stdio-wrapper.js index 2ab1392..4e7ad6f 100644 --- a/lib/stdio-wrapper.js +++ b/lib/stdio-wrapper.js @@ -39,7 +39,10 @@ class StdioWrapper extends EventEmitter { this._pendingMessage = ''; this._eventListeners = [ addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)), - addEventListener(pipeRead, 'close', () => this.emit('close')), + addEventListener(pipeRead, 'close', () => { + this._pipeWrite = null; + this.emit('close'); + }), addEventListener(pipeRead, 'error', (err) => this.emit('error', err)), addEventListener(pipeWrite, 'error', (err) => this.emit('error', err)), ]; @@ -48,6 +51,8 @@ class StdioWrapper extends EventEmitter { send(message, callback) { try { + if (!this._pipeWrite) + throw new Error('CDP pipeWrite closed'); this._pipeWrite.write(message); this._pipeWrite.write('\0'); callback(); From c9c7356fa9b1cd59c59c827f14a7c35a67899e5e Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Wed, 22 Oct 2025 16:50:43 +0300 Subject: [PATCH 11/15] wording (it can be either stdio pipes or WS) --- lib/chrome.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/chrome.js b/lib/chrome.js index c43eb1d..69de279 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -94,7 +94,7 @@ class Chrome extends EventEmitter { const request = {method, params, sessionId}; reject( error instanceof Error - ? error // low-level WebSocket error + ? error // low-level io error : new ProtocolError(request, response) ); } else { From e129c0f9185b781eaad1e6e6979429ef2c1a37b4 Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Tue, 28 Oct 2025 18:02:43 +0200 Subject: [PATCH 12/15] support for fetching the protocol remotely via stdio pipes --- lib/chrome.js | 38 ++++++++++++++++++++++++-------------- lib/devtools.js | 9 +++++++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/chrome.js b/lib/chrome.js index 69de279..fe86225 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -118,16 +118,26 @@ class Chrome extends EventEmitter { // initiate the connection process async _start() { - const options = { - host: this.host, - port: this.port, - secure: this.secure, - useHostName: this.useHostName, - alterPath: this.alterPath, - ...this.connectOptions, - }; try { - if (!this.process) { + if (this.process) + { + const options = {local: this.local, cdp: this}; + // we first "connect" to stdio pipes, so that we can + // first the protocol remotely via the pipe. + await this._connect(); + const protocol = await this._fetchProtocol(options); + api.prepare(this, protocol); + } + else + { + const options = { + host: this.host, + port: this.port, + secure: this.secure, + useHostName: this.useHostName, + alterPath: this.alterPath, + ...this.connectOptions, + }; // fetch the WebSocket debugger URL const url = await this._fetchDebuggerURL(options); // allow the user to alter the URL @@ -137,12 +147,12 @@ class Chrome extends EventEmitter { // update the connection parameters using the debugging URL options.host = urlObject.hostname; options.port = urlObject.port || options.port; + // fetch the protocol and prepare the API + const protocol = await this._fetchProtocol(options); + api.prepare(this, protocol); + // finally connect to the WebSocket + await this._connect(); } - // fetch the protocol and prepare the API - const protocol = await this._fetchProtocol(options); - api.prepare(this, protocol); - // finally connect to the WebSocket or stdio - await this._connect(); // since the handler is executed synchronously, the emit() must be // performed in the next tick so that uncaught errors in the client code // are not intercepted by the Promise mechanism and therefore reported diff --git a/lib/devtools.js b/lib/devtools.js index 3975a00..4649db9 100644 --- a/lib/devtools.js +++ b/lib/devtools.js @@ -48,6 +48,15 @@ function promisesWrapper(func) { } function Protocol(options, callback) { + // fetch remotely via CDP when using stdio pipes (Bright Data exclusive) + if (options.cdp) + { + return options.cdp.send('Browser.getProtocolJson', (err, data)=>{ + if (err) + return callback(err); + callback(null, JSON.parse(data.result)); + }); + } // if the local protocol is requested if (options.local) { const localDescriptor = require('./protocol.json'); From 5623c76a3c7cb17f6f4b708526885819839bca83 Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Sun, 2 Nov 2025 17:33:23 +0200 Subject: [PATCH 13/15] wrapper => transport --- lib/chrome.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/chrome.js b/lib/chrome.js index fe86225..7a51c48 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -253,7 +253,7 @@ class Chrome extends EventEmitter { _connect() { return new Promise((fulfill, reject) => { try { - this._wrapper = this.process + this._transport = this.process ? this._createStdioWrapper() : this._createWebSocketWrapper(); } catch (err) { @@ -262,18 +262,18 @@ class Chrome extends EventEmitter { return; } // set up event handlers - this._wrapper.on('open', () => { + this._transport.on('open', () => { fulfill(); }); - this._wrapper.on('message', (data) => { + this._transport.on('message', (data) => { const message = JSON.parse(data); this._handleMessage(message); }); - this._wrapper.on('close', (code) => { + this._transport.on('close', (code) => { this._handleConnectionClose(); this.emit('disconnect'); }); - this._wrapper.on('error', (err) => { + this._transport.on('error', (err) => { reject(err); }); }); @@ -345,7 +345,7 @@ class Chrome extends EventEmitter { } }); } - get transport() { return this._wrapper; } + get transport() { return this._transport; } } module.exports = Chrome; From 3dfd745793e2e5b0f7f4c3f707cf1fdf6415e58a Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Sun, 2 Nov 2025 18:15:15 +0200 Subject: [PATCH 14/15] fix propagating protocol fetch errors when using stdio pipes (the callback-based implementation doesn't correctly transform the cdp errors) --- lib/devtools.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/devtools.js b/lib/devtools.js index 4649db9..a90fdfb 100644 --- a/lib/devtools.js +++ b/lib/devtools.js @@ -51,11 +51,9 @@ function Protocol(options, callback) { // fetch remotely via CDP when using stdio pipes (Bright Data exclusive) if (options.cdp) { - return options.cdp.send('Browser.getProtocolJson', (err, data)=>{ - if (err) - return callback(err); - callback(null, JSON.parse(data.result)); - }); + return options.cdp.send('Browser.getProtocolJson') + .then(data=>callback(null, JSON.parse(data.result))) + .catch(callback) } // if the local protocol is requested if (options.local) { From c6a8480a905151308afc5a21eb644734c327e74d Mon Sep 17 00:00:00 2001 From: Kevin Rabaev Date: Sun, 2 Nov 2025 20:41:25 +0200 Subject: [PATCH 15/15] coding --- lib/chrome.js | 11 ++++++----- lib/devtools.js | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/chrome.js b/lib/chrome.js index 7a51c48..2d46f3c 100644 --- a/lib/chrome.js +++ b/lib/chrome.js @@ -56,7 +56,7 @@ class Chrome extends EventEmitter { this.useHostName = !!(options.useHostName); this.alterPath = options.alterPath || ((path) => path); this.protocol = options.protocol; - this.local = !!(options.local || options.process); + this.local = !!(options.local); this.target = options.target || defaultTarget; this.connectOptions = options.connectOptions; this.process = options.process; @@ -121,11 +121,10 @@ class Chrome extends EventEmitter { try { if (this.process) { - const options = {local: this.local, cdp: this}; // we first "connect" to stdio pipes, so that we can // first the protocol remotely via the pipe. await this._connect(); - const protocol = await this._fetchProtocol(options); + const protocol = await this._fetchProtocol({}); api.prepare(this, protocol); } else @@ -139,7 +138,7 @@ class Chrome extends EventEmitter { ...this.connectOptions, }; // fetch the WebSocket debugger URL - const url = await this._fetchDebuggerURL(options); + const url = await this._fetchWsDebuggerURL(options); // allow the user to alter the URL const urlObject = parseUrl(url); urlObject.pathname = options.alterPath(urlObject.pathname); @@ -166,7 +165,7 @@ class Chrome extends EventEmitter { } // fetch the WebSocket URL according to 'target' - async _fetchDebuggerURL(options) { + async _fetchWsDebuggerURL(options) { const userTarget = this.target; switch (typeof userTarget) { case 'string': { @@ -211,6 +210,8 @@ class Chrome extends EventEmitter { // otherwise user either the local or the remote version else { options.local = this.local; + if (this.process) + options.cdp = this; return await devtools.Protocol(options); } } diff --git a/lib/devtools.js b/lib/devtools.js index a90fdfb..ad1db0a 100644 --- a/lib/devtools.js +++ b/lib/devtools.js @@ -53,7 +53,7 @@ function Protocol(options, callback) { { return options.cdp.send('Browser.getProtocolJson') .then(data=>callback(null, JSON.parse(data.result))) - .catch(callback) + .catch(callback); } // if the local protocol is requested if (options.local) {