Add Brave CDP automation, replace Oracle browser mode
Connects to user's running Brave via Chrome DevTools Protocol to automate ChatGPT interaction. Uses puppeteer-core to open a tab, send the prompt, wait for response, and extract the result. No cookies, no separate profiles, no copy/paste. Just connects to the browser where the user is already logged in. One-time setup: relaunch Brave with --remote-debugging-port=9222 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
23
node_modules/chromium-bidi/lib/esm/bidiServer/BrowserInstance.d.ts
generated
vendored
Normal file
23
node_modules/chromium-bidi/lib/esm/bidiServer/BrowserInstance.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import { type Process } from '@puppeteer/browsers';
|
||||
import { MapperServerCdpConnection } from './MapperCdpConnection.js';
|
||||
import type { SimpleTransport } from './SimpleTransport.js';
|
||||
export interface ChromeOptions {
|
||||
chromeArgs: string[];
|
||||
chromeBinary?: string;
|
||||
}
|
||||
/**
|
||||
* BrowserProcess is responsible for running the browser and BiDi Mapper within
|
||||
* it.
|
||||
* 1. Launch Chromium (using Puppeteer for now).
|
||||
* 2. Get `BiDi-CDP` mapper JS binaries using `MapperReader`.
|
||||
* 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
|
||||
* 4. Bind `BiDi-CDP` mapper to the `BiDi server` to forward messages from BiDi
|
||||
* Mapper to the client.
|
||||
*/
|
||||
export declare class BrowserInstance {
|
||||
#private;
|
||||
static run(chromeOptions: ChromeOptions, verbose: boolean): Promise<BrowserInstance>;
|
||||
constructor(mapperCdpConnection: MapperServerCdpConnection, browserProcess: Process);
|
||||
close(): Promise<void>;
|
||||
bidiSession(): SimpleTransport;
|
||||
}
|
||||
107
node_modules/chromium-bidi/lib/esm/bidiServer/BrowserInstance.js
generated
vendored
Normal file
107
node_modules/chromium-bidi/lib/esm/bidiServer/BrowserInstance.js
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2023 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
import { mkdtemp } from 'fs/promises';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { launch } from '@puppeteer/browsers';
|
||||
import debug from 'debug';
|
||||
import { MapperCdpConnection } from '../cdp/CdpConnection.js';
|
||||
import { MapperServerCdpConnection } from './MapperCdpConnection.js';
|
||||
import { PipeTransport } from './PipeTransport.js';
|
||||
import { getMapperTabSource } from './reader.js';
|
||||
const debugInternal = debug('bidi:mapper:internal');
|
||||
/**
|
||||
* BrowserProcess is responsible for running the browser and BiDi Mapper within
|
||||
* it.
|
||||
* 1. Launch Chromium (using Puppeteer for now).
|
||||
* 2. Get `BiDi-CDP` mapper JS binaries using `MapperReader`.
|
||||
* 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
|
||||
* 4. Bind `BiDi-CDP` mapper to the `BiDi server` to forward messages from BiDi
|
||||
* Mapper to the client.
|
||||
*/
|
||||
export class BrowserInstance {
|
||||
#mapperCdpConnection;
|
||||
#browserProcess;
|
||||
static async run(chromeOptions, verbose) {
|
||||
const profileDir = await mkdtemp(path.join(os.tmpdir(), 'web-driver-bidi-server-'));
|
||||
// See https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
|
||||
const chromeArguments = [
|
||||
// keep-sorted start
|
||||
'--allow-browser-signin=false',
|
||||
'--disable-background-networking',
|
||||
'--disable-background-timer-throttling',
|
||||
'--disable-backgrounding-occluded-windows',
|
||||
'--disable-component-update',
|
||||
'--disable-default-apps',
|
||||
'--disable-notifications',
|
||||
'--disable-popup-blocking',
|
||||
'--disable-search-engine-choice-screen',
|
||||
'--enable-automation',
|
||||
'--no-default-browser-check',
|
||||
'--no-first-run',
|
||||
'--password-store=basic',
|
||||
'--remote-debugging-pipe',
|
||||
'--use-mock-keychain',
|
||||
`--user-data-dir=${profileDir}`,
|
||||
// keep-sorted end
|
||||
...chromeOptions.chromeArgs,
|
||||
'about:blank',
|
||||
];
|
||||
const executablePath = chromeOptions.chromeBinary ?? process.env['BROWSER_BIN'];
|
||||
if (!executablePath) {
|
||||
throw new Error('Could not find Chrome binary');
|
||||
}
|
||||
const launchArguments = {
|
||||
executablePath,
|
||||
args: chromeArguments,
|
||||
env: process.env,
|
||||
pipe: true,
|
||||
};
|
||||
debugInternal(`Launching browser`, {
|
||||
executablePath,
|
||||
args: chromeArguments,
|
||||
});
|
||||
const browserProcess = launch(launchArguments);
|
||||
const cdpConnection = this.#establishPipeConnection(browserProcess);
|
||||
// 2. Get `BiDi-CDP` mapper JS binaries.
|
||||
const mapperTabSource = await getMapperTabSource();
|
||||
// 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
|
||||
const mapperCdpConnection = await MapperServerCdpConnection.create(cdpConnection, mapperTabSource, verbose);
|
||||
return new BrowserInstance(mapperCdpConnection, browserProcess);
|
||||
}
|
||||
constructor(mapperCdpConnection, browserProcess) {
|
||||
this.#mapperCdpConnection = mapperCdpConnection;
|
||||
this.#browserProcess = browserProcess;
|
||||
}
|
||||
async close() {
|
||||
// Close the mapper tab.
|
||||
this.#mapperCdpConnection.close();
|
||||
// Close browser.
|
||||
await this.#browserProcess.close();
|
||||
}
|
||||
bidiSession() {
|
||||
return this.#mapperCdpConnection.bidiSession();
|
||||
}
|
||||
static #establishPipeConnection(browserProcess) {
|
||||
debugInternal('Establishing pipe connection to browser process with pid: ', browserProcess.nodeProcess.pid);
|
||||
const { 3: pipeWrite, 4: pipeRead } = browserProcess.nodeProcess.stdio;
|
||||
const transport = new PipeTransport(pipeWrite, pipeRead);
|
||||
return new MapperCdpConnection(transport);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=BrowserInstance.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/BrowserInstance.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/BrowserInstance.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"BrowserInstance.js","sourceRoot":"","sources":["../../../src/bidiServer/BrowserInstance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAC,MAAM,EAAe,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAC,mBAAmB,EAAC,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAC,kBAAkB,EAAC,MAAM,aAAa,CAAC;AAG/C,MAAM,aAAa,GAAG,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAOpD;;;;;;;;GAQG;AACH,MAAM,OAAO,eAAe;IAC1B,oBAAoB,CAA4B;IAChD,eAAe,CAAU;IAEzB,MAAM,CAAC,KAAK,CAAC,GAAG,CACd,aAA4B,EAC5B,OAAgB;QAEhB,MAAM,UAAU,GAAG,MAAM,OAAO,CAC9B,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAClD,CAAC;QAEF,+FAA+F;QAC/F,MAAM,eAAe,GAAG;YACtB,oBAAoB;YACpB,8BAA8B;YAC9B,iCAAiC;YACjC,uCAAuC;YACvC,0CAA0C;YAC1C,4BAA4B;YAC5B,wBAAwB;YACxB,yBAAyB;YACzB,0BAA0B;YAC1B,uCAAuC;YACvC,qBAAqB;YACrB,4BAA4B;YAC5B,gBAAgB;YAChB,wBAAwB;YACxB,yBAAyB;YACzB,qBAAqB;YACrB,mBAAmB,UAAU,EAAE;YAC/B,kBAAkB;YAClB,GAAG,aAAa,CAAC,UAAU;YAC3B,aAAa;SACd,CAAC;QAEF,MAAM,cAAc,GAClB,aAAa,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAE3D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,eAAe,GAAG;YACtB,cAAc;YACd,IAAI,EAAE,eAAe;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,IAAI,EAAE,IAAI;SACX,CAAC;QAEF,aAAa,CAAC,mBAAmB,EAAE;YACjC,cAAc;YACd,IAAI,EAAE,eAAe;SACtB,CAAC,CAAC;QAEH,MAAM,cAAc,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;QAE/C,MAAM,aAAa,GAAG,IAAI,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;QACpE,wCAAwC;QACxC,MAAM,eAAe,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAEnD,qEAAqE;QACrE,MAAM,mBAAmB,GAAG,MAAM,yBAAyB,CAAC,MAAM,CAChE,aAAa,EACb,eAAe,EACf,OAAO,CACR,CAAC;QAEF,OAAO,IAAI,eAAe,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;IAClE,CAAC;IAED,YACE,mBAA8C,EAC9C,cAAuB;QAEvB,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;QAChD,IAAI,CAAC,eAAe,GAAG,cAAc,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,wBAAwB;QACxB,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,CAAC;QAElC,iBAAiB;QACjB,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IACrC,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,wBAAwB,CAC7B,cAAuB;QAEvB,aAAa,CACX,4DAA4D,EAC5D,cAAc,CAAC,WAAW,CAAC,GAAG,CAC/B,CAAC;QACF,MAAM,EAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAC,GAAG,cAAc,CAAC,WAAW,CAAC,KAAK,CAAC;QACrE,MAAM,SAAS,GAAG,IAAI,aAAa,CACjC,SAAkC,EAClC,QAAiC,CAClC,CAAC;QACF,OAAO,IAAI,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;CACF"}
|
||||
25
node_modules/chromium-bidi/lib/esm/bidiServer/MapperCdpConnection.d.ts
generated
vendored
Normal file
25
node_modules/chromium-bidi/lib/esm/bidiServer/MapperCdpConnection.d.ts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import type { MapperCdpConnection } from '../cdp/CdpConnection.js';
|
||||
import { SimpleTransport } from './SimpleTransport.js';
|
||||
export declare class MapperServerCdpConnection {
|
||||
#private;
|
||||
static create(cdpConnection: MapperCdpConnection, mapperTabSource: string, verbose: boolean): Promise<MapperServerCdpConnection>;
|
||||
private constructor();
|
||||
close(): void;
|
||||
bidiSession(): SimpleTransport;
|
||||
}
|
||||
138
node_modules/chromium-bidi/lib/esm/bidiServer/MapperCdpConnection.js
generated
vendored
Normal file
138
node_modules/chromium-bidi/lib/esm/bidiServer/MapperCdpConnection.js
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import debug from 'debug';
|
||||
import { SimpleTransport } from './SimpleTransport.js';
|
||||
const debugInternal = debug('bidi:mapper:internal');
|
||||
const debugInfo = debug('bidi:mapper:info');
|
||||
const debugOthers = debug('bidi:mapper:debug:others');
|
||||
// Memorizes a debug creation
|
||||
const loggers = new Map();
|
||||
const getLogger = (type) => {
|
||||
const prefix = `bidi:mapper:${type}`;
|
||||
let logger = loggers.get(prefix);
|
||||
if (!logger) {
|
||||
logger = debug(prefix);
|
||||
loggers.set(prefix, logger);
|
||||
}
|
||||
return logger;
|
||||
};
|
||||
export class MapperServerCdpConnection {
|
||||
#cdpConnection;
|
||||
#bidiSession;
|
||||
static async create(cdpConnection, mapperTabSource, verbose) {
|
||||
try {
|
||||
const bidiSession = await this.#initMapper(cdpConnection, mapperTabSource, verbose);
|
||||
return new MapperServerCdpConnection(cdpConnection, bidiSession);
|
||||
}
|
||||
catch (e) {
|
||||
cdpConnection.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
constructor(cdpConnection, bidiSession) {
|
||||
this.#cdpConnection = cdpConnection;
|
||||
this.#bidiSession = bidiSession;
|
||||
}
|
||||
static async #sendMessage(mapperCdpClient, message) {
|
||||
try {
|
||||
await mapperCdpClient.sendCommand('Runtime.evaluate', {
|
||||
expression: `onBidiMessage(${JSON.stringify(message)})`,
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
debugInternal('Call to onBidiMessage failed', error);
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this.#cdpConnection.close();
|
||||
}
|
||||
bidiSession() {
|
||||
return this.#bidiSession;
|
||||
}
|
||||
static #onBindingCalled = (params, bidiSession) => {
|
||||
if (params.name === 'sendBidiResponse') {
|
||||
bidiSession.emit('message', params.payload);
|
||||
}
|
||||
else if (params.name === 'sendDebugMessage') {
|
||||
this.#onDebugMessage(params.payload);
|
||||
}
|
||||
};
|
||||
static #onDebugMessage = (json) => {
|
||||
try {
|
||||
const log = JSON.parse(json);
|
||||
if (log.logType !== undefined && log.messages !== undefined) {
|
||||
const logger = getLogger(log.logType);
|
||||
logger(log.messages);
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// Fall back to raw log in case of unknown
|
||||
debugOthers(json);
|
||||
}
|
||||
};
|
||||
static #onConsoleAPICalled = (params) => {
|
||||
debugInfo('consoleAPICalled: %s %O', params.type, params.args.map((arg) => arg.value));
|
||||
};
|
||||
static #onRuntimeExceptionThrown = (params) => {
|
||||
debugInfo('exceptionThrown:', params);
|
||||
};
|
||||
static async #initMapper(cdpConnection, mapperTabSource, verbose) {
|
||||
debugInternal('Initializing Mapper.');
|
||||
const browserClient = await cdpConnection.createBrowserSession();
|
||||
const { targetId: mapperTargetId } = await browserClient.sendCommand('Target.createTarget', {
|
||||
url: 'about:blank#MAPPER_TARGET',
|
||||
hidden: true,
|
||||
background: true,
|
||||
});
|
||||
const { sessionId: mapperSessionId } = await browserClient.sendCommand('Target.attachToTarget', { targetId: mapperTargetId, flatten: true });
|
||||
const mapperCdpClient = cdpConnection.getCdpClient(mapperSessionId);
|
||||
const bidiSession = new SimpleTransport(async (message) => await this.#sendMessage(mapperCdpClient, message));
|
||||
// Process responses from the mapper tab.
|
||||
mapperCdpClient.on('Runtime.bindingCalled', (params) => this.#onBindingCalled(params, bidiSession));
|
||||
// Forward console messages from the mapper tab.
|
||||
mapperCdpClient.on('Runtime.consoleAPICalled', this.#onConsoleAPICalled);
|
||||
// Catch unhandled exceptions in the mapper.
|
||||
mapperCdpClient.on('Runtime.exceptionThrown', this.#onRuntimeExceptionThrown);
|
||||
await mapperCdpClient.sendCommand('Runtime.enable');
|
||||
await browserClient.sendCommand('Target.exposeDevToolsProtocol', {
|
||||
bindingName: 'cdp',
|
||||
targetId: mapperTargetId,
|
||||
inheritPermissions: true,
|
||||
});
|
||||
await mapperCdpClient.sendCommand('Runtime.addBinding', {
|
||||
name: 'sendBidiResponse',
|
||||
});
|
||||
if (verbose) {
|
||||
// Needed to request verbose logs from Mapper.
|
||||
await mapperCdpClient.sendCommand('Runtime.addBinding', {
|
||||
name: 'sendDebugMessage',
|
||||
});
|
||||
}
|
||||
// Evaluate Mapper Tab sources in the tab.
|
||||
await mapperCdpClient.sendCommand('Runtime.evaluate', {
|
||||
expression: mapperTabSource,
|
||||
});
|
||||
// TODO: handle errors in all these evaluate calls!
|
||||
await mapperCdpClient.sendCommand('Runtime.evaluate', {
|
||||
expression: `window.runMapperInstance('${mapperTargetId}')`,
|
||||
awaitPromise: true,
|
||||
});
|
||||
debugInternal('Mapper is launched!');
|
||||
return bidiSession;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=MapperCdpConnection.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/MapperCdpConnection.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/MapperCdpConnection.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"MapperCdpConnection.js","sourceRoot":"","sources":["../../../src/bidiServer/MapperCdpConnection.ts"],"names":[],"mappings":"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"}
|
||||
8
node_modules/chromium-bidi/lib/esm/bidiServer/PipeTransport.d.ts
generated
vendored
Normal file
8
node_modules/chromium-bidi/lib/esm/bidiServer/PipeTransport.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Transport } from '../utils/transport.js';
|
||||
export declare class PipeTransport implements Transport {
|
||||
#private;
|
||||
constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream);
|
||||
setOnMessage(onMessage: (message: string) => void): void;
|
||||
sendMessage(message: string): void;
|
||||
close(): void;
|
||||
}
|
||||
77
node_modules/chromium-bidi/lib/esm/bidiServer/PipeTransport.js
generated
vendored
Normal file
77
node_modules/chromium-bidi/lib/esm/bidiServer/PipeTransport.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2025 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
import debug from 'debug';
|
||||
const debugInternal = debug('bidi:server:pipeTranspot');
|
||||
export class PipeTransport {
|
||||
#pipeWrite;
|
||||
#onMessage = null;
|
||||
#pendingMessage = '';
|
||||
constructor(pipeWrite, pipeRead) {
|
||||
this.#pipeWrite = pipeWrite;
|
||||
pipeRead.on('data', (chunk) => {
|
||||
return this.#dispatch(chunk);
|
||||
});
|
||||
pipeRead.on('close', () => {
|
||||
this.close();
|
||||
});
|
||||
pipeRead.on('error', (error) => {
|
||||
debugInternal('Pipe read error: ', error);
|
||||
this.close();
|
||||
});
|
||||
pipeWrite.on('error', (error) => {
|
||||
debugInternal('Pipe read error: ', error);
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
setOnMessage(onMessage) {
|
||||
this.#onMessage = onMessage;
|
||||
}
|
||||
sendMessage(message) {
|
||||
// TODO: WebSocketServer keeps sending messages after closing the transport.
|
||||
// TODO: we should assert that the pipe was not closed.
|
||||
this.#pipeWrite.write(message);
|
||||
this.#pipeWrite.write('\0');
|
||||
}
|
||||
#dispatch(buffer) {
|
||||
// TODO: WebSocketServer keeps sending messages after closing the transport.
|
||||
// TODO: we should assert that the pipe was not closed.
|
||||
let end = buffer.indexOf('\0');
|
||||
if (end === -1) {
|
||||
this.#pendingMessage += buffer.toString();
|
||||
return;
|
||||
}
|
||||
const message = this.#pendingMessage + buffer.toString(undefined, 0, end);
|
||||
if (this.#onMessage) {
|
||||
this.#onMessage.call(null, message);
|
||||
}
|
||||
let start = end + 1;
|
||||
end = buffer.indexOf('\0', start);
|
||||
while (end !== -1) {
|
||||
if (this.#onMessage) {
|
||||
this.#onMessage.call(null, buffer.toString(undefined, start, end));
|
||||
}
|
||||
start = end + 1;
|
||||
end = buffer.indexOf('\0', start);
|
||||
}
|
||||
this.#pendingMessage = buffer.toString(undefined, start);
|
||||
}
|
||||
close() {
|
||||
debugInternal('Closing pipe');
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=PipeTransport.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/PipeTransport.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/PipeTransport.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"PipeTransport.js","sourceRoot":"","sources":["../../../src/bidiServer/PipeTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,aAAa,GAAG,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAExD,MAAM,OAAO,aAAa;IACxB,UAAU,CAAwB;IAClC,UAAU,GAAuC,IAAI,CAAC;IAEtD,eAAe,GAAG,EAAE,CAAC;IAErB,YACE,SAAgC,EAChC,QAA+B;QAE/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAE5B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACxB,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7B,aAAa,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC9B,aAAa,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAED,YAAY,CAAC,SAAoC;QAC/C,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;IAC9B,CAAC;IACD,WAAW,CAAC,OAAe;QACzB,4EAA4E;QAC5E,uDAAuD;QAEvD,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,SAAS,CAAC,MAAc;QACtB,4EAA4E;QAC5E,uDAAuD;QAEvD,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,eAAe,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC1C,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1E,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;QACpB,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;YAClB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;YACrE,CAAC;YACD,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;YAChB,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK;QACH,aAAa,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;CACF"}
|
||||
13
node_modules/chromium-bidi/lib/esm/bidiServer/SimpleTransport.d.ts
generated
vendored
Normal file
13
node_modules/chromium-bidi/lib/esm/bidiServer/SimpleTransport.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { EventEmitter } from '../utils/EventEmitter.js';
|
||||
/**
|
||||
* Implements simple transport that allows sending string messages via
|
||||
* `sendCommand` and receiving them via `on('message')`.
|
||||
*/
|
||||
export declare class SimpleTransport extends EventEmitter<Record<'message', string>> {
|
||||
#private;
|
||||
/**
|
||||
* @param sendCommandDelegate delegate to be called in `sendCommand`.
|
||||
*/
|
||||
constructor(sendCommandDelegate: (plainCommand: string) => Promise<void>);
|
||||
sendCommand(plainCommand: string): Promise<void>;
|
||||
}
|
||||
35
node_modules/chromium-bidi/lib/esm/bidiServer/SimpleTransport.js
generated
vendored
Normal file
35
node_modules/chromium-bidi/lib/esm/bidiServer/SimpleTransport.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2023 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import { EventEmitter } from '../utils/EventEmitter.js';
|
||||
/**
|
||||
* Implements simple transport that allows sending string messages via
|
||||
* `sendCommand` and receiving them via `on('message')`.
|
||||
*/
|
||||
export class SimpleTransport extends EventEmitter {
|
||||
#sendCommandDelegate;
|
||||
/**
|
||||
* @param sendCommandDelegate delegate to be called in `sendCommand`.
|
||||
*/
|
||||
constructor(sendCommandDelegate) {
|
||||
super();
|
||||
this.#sendCommandDelegate = sendCommandDelegate;
|
||||
}
|
||||
async sendCommand(plainCommand) {
|
||||
await this.#sendCommandDelegate(plainCommand);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=SimpleTransport.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/SimpleTransport.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/SimpleTransport.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"SimpleTransport.js","sourceRoot":"","sources":["../../../src/bidiServer/SimpleTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAEtD;;;GAGG;AACH,MAAM,OAAO,eAAgB,SAAQ,YAAuC;IACjE,oBAAoB,CAA0C;IAEvE;;OAEG;IACH,YAAY,mBAA4D;QACtE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,YAAoB;QACpC,MAAM,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC;CACF"}
|
||||
6
node_modules/chromium-bidi/lib/esm/bidiServer/WebSocketServer.d.ts
generated
vendored
Normal file
6
node_modules/chromium-bidi/lib/esm/bidiServer/WebSocketServer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import debug from 'debug';
|
||||
export declare const debugInfo: debug.Debugger;
|
||||
export declare class WebSocketServer {
|
||||
#private;
|
||||
constructor(port: number, verbose: boolean);
|
||||
}
|
||||
374
node_modules/chromium-bidi/lib/esm/bidiServer/WebSocketServer.js
generated
vendored
Normal file
374
node_modules/chromium-bidi/lib/esm/bidiServer/WebSocketServer.js
generated
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import http from 'http';
|
||||
import debug from 'debug';
|
||||
import * as websocket from 'websocket';
|
||||
import { Deferred } from '../utils/Deferred.js';
|
||||
import { uuidv4 } from '../utils/uuid.js';
|
||||
import { BrowserInstance } from './BrowserInstance.js';
|
||||
export const debugInfo = debug('bidi:server:info');
|
||||
const debugInternal = debug('bidi:server:internal');
|
||||
const debugSend = debug('bidi:server:SEND ▸');
|
||||
const debugRecv = debug('bidi:server:RECV ◂');
|
||||
export class WebSocketServer {
|
||||
#sessions = new Map();
|
||||
#port;
|
||||
#verbose;
|
||||
#server;
|
||||
#wsServer;
|
||||
constructor(port, verbose) {
|
||||
this.#port = port;
|
||||
this.#verbose = verbose;
|
||||
this.#server = http.createServer((request, response) => {
|
||||
return this.#onRequest(request, response).catch((e) => {
|
||||
debugInfo('Error while processing request', e);
|
||||
response.writeHead(500, String(e));
|
||||
});
|
||||
});
|
||||
this.#wsServer = new websocket.server({
|
||||
httpServer: this.#server,
|
||||
autoAcceptConnections: false,
|
||||
});
|
||||
this.#wsServer.on('request', this.#onWsRequest.bind(this));
|
||||
void this.#listen();
|
||||
}
|
||||
#logServerStarted() {
|
||||
debugInfo('BiDi server is listening on port', this.#port);
|
||||
debugInfo('BiDi server was started successfully.');
|
||||
}
|
||||
async #listen() {
|
||||
try {
|
||||
this.#server.listen(this.#port, () => {
|
||||
this.#logServerStarted();
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
if (error &&
|
||||
typeof error === 'object' &&
|
||||
'code' in error &&
|
||||
error.code === 'EADDRINUSE') {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 500);
|
||||
});
|
||||
debugInfo('Retrying to run BiDi server');
|
||||
this.#server.listen(this.#port, () => {
|
||||
this.#logServerStarted();
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async #onRequest(request, response) {
|
||||
debugInternal(`Received HTTP ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)}`);
|
||||
if (!request.url) {
|
||||
throw new Error('Request URL is empty.');
|
||||
}
|
||||
// https://w3c.github.io/webdriver-bidi/#transport, step 2.
|
||||
if (request.url === '/session') {
|
||||
const body = await new Promise((resolve, reject) => {
|
||||
const bodyArray = [];
|
||||
request.on('data', (chunk) => {
|
||||
bodyArray.push(chunk);
|
||||
});
|
||||
request.on('error', reject);
|
||||
request.on('end', () => {
|
||||
resolve(Buffer.concat(bodyArray));
|
||||
});
|
||||
});
|
||||
debugInternal(`Creating session by HTTP request ${body.toString()}`);
|
||||
// https://w3c.github.io/webdriver-bidi/#transport, step 3.
|
||||
const jsonBody = JSON.parse(body.toString());
|
||||
response.writeHead(200, {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'Cache-Control': 'no-cache',
|
||||
});
|
||||
const sessionId = uuidv4();
|
||||
const session = {
|
||||
sessionId,
|
||||
// TODO: launch browser instance and set it to the session after WPT
|
||||
// tests clean up is switched to pure BiDi.
|
||||
browserInstancePromise: undefined,
|
||||
sessionOptions: {
|
||||
chromeOptions: this.#getChromeOptions(jsonBody.capabilities),
|
||||
verbose: this.#verbose,
|
||||
sessionNewBody: `{"id":0,"method":"session.new","params":${body.toString()}}`,
|
||||
},
|
||||
};
|
||||
this.#sessions.set(sessionId, session);
|
||||
const webSocketUrl = `ws://localhost:${this.#port}/session/${sessionId}`;
|
||||
debugInternal(`Session created. WebSocket URL: ${JSON.stringify(webSocketUrl)}.`);
|
||||
response.write(JSON.stringify({
|
||||
value: {
|
||||
sessionId,
|
||||
capabilities: {
|
||||
webSocketUrl,
|
||||
},
|
||||
},
|
||||
}));
|
||||
return response.end();
|
||||
}
|
||||
else if (request.url.startsWith('/session')) {
|
||||
debugInternal(`Unknown session command ${request.method ?? 'UNKNOWN METHOD'} request for ${request.url} with payload ${await this.#getHttpRequestPayload(request)}. 200 returned.`);
|
||||
response.writeHead(200, {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'Cache-Control': 'no-cache',
|
||||
});
|
||||
response.write(JSON.stringify({
|
||||
value: {},
|
||||
}));
|
||||
return response.end();
|
||||
}
|
||||
throw new Error(`Unknown "${request.method}" request for "${JSON.stringify(request.url)}" with payload "${await this.#getHttpRequestPayload(request)}".`);
|
||||
}
|
||||
#onWsRequest(request) {
|
||||
// Session is set either by Classic or BiDi commands.
|
||||
let session;
|
||||
// Request to `/session` should be treated as a new session request.
|
||||
let requestSessionId = '';
|
||||
if ((request.resource ?? '').startsWith(`/session/`)) {
|
||||
requestSessionId = (request.resource ?? '').split('/').pop() ?? '';
|
||||
}
|
||||
debugInternal(`new WS request received. Path: ${JSON.stringify(request.resourceURL.path)}, sessionId: ${JSON.stringify(requestSessionId)}`);
|
||||
if (requestSessionId !== '' &&
|
||||
requestSessionId !== undefined &&
|
||||
!this.#sessions.has(requestSessionId)) {
|
||||
debugInternal('Unknown session id:', requestSessionId);
|
||||
request.reject();
|
||||
return;
|
||||
}
|
||||
const connection = request.accept();
|
||||
session = this.#sessions.get(requestSessionId ?? '');
|
||||
if (session !== undefined) {
|
||||
// BrowserInstance is created for each new WS connection, even for the
|
||||
// same SessionId. This is because WPT uses a single session for all the
|
||||
// tests, but cleans up tests using WebDriver Classic commands, which is
|
||||
// not implemented in this Mapper runner.
|
||||
// TODO: connect to an existing BrowserInstance instead.
|
||||
const sessionOptions = session.sessionOptions;
|
||||
session.browserInstancePromise = this.#closeBrowserInstanceIfLaunched(session)
|
||||
.then(async () => await this.#launchBrowserInstance(connection, sessionOptions))
|
||||
.catch((e) => {
|
||||
debugInfo('Error while creating session', e);
|
||||
connection.close(500, 'cannot create browser instance');
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
connection.on('message', async (message) => {
|
||||
// If type is not text, return error.
|
||||
if (message.type !== 'utf8') {
|
||||
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `not supported type (${message.type})`);
|
||||
return;
|
||||
}
|
||||
const plainCommandData = message.utf8Data;
|
||||
if (debugRecv.enabled) {
|
||||
try {
|
||||
debugRecv(JSON.parse(plainCommandData));
|
||||
}
|
||||
catch {
|
||||
debugRecv(plainCommandData);
|
||||
}
|
||||
}
|
||||
// Try to parse the message to handle some of BiDi commands.
|
||||
let parsedCommandData;
|
||||
try {
|
||||
parsedCommandData = JSON.parse(plainCommandData);
|
||||
}
|
||||
catch (error) {
|
||||
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `unable to parse BiDi command: ${error}`);
|
||||
return;
|
||||
}
|
||||
// Handle creating new session.
|
||||
if (parsedCommandData.method === 'session.new') {
|
||||
if (session !== undefined) {
|
||||
debugInfo('WS connection already have an associated session.');
|
||||
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, 'WS connection already have an associated session.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const sessionOptions = {
|
||||
chromeOptions: this.#getChromeOptions(parsedCommandData.params?.capabilities),
|
||||
verbose: this.#verbose,
|
||||
sessionNewBody: plainCommandData,
|
||||
};
|
||||
const browserInstance = await this.#launchBrowserInstance(connection, sessionOptions, true);
|
||||
const sessionId = uuidv4();
|
||||
session = {
|
||||
sessionId,
|
||||
browserInstancePromise: Promise.resolve(browserInstance),
|
||||
sessionOptions,
|
||||
};
|
||||
this.#sessions.set(sessionId, session);
|
||||
}
|
||||
catch (e) {
|
||||
debugInfo('Error while creating session', e);
|
||||
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, e?.message ?? 'Unknown error');
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Handle ending session. Close browser if open, remove session.
|
||||
if (parsedCommandData.method === 'session.end') {
|
||||
if (session === undefined) {
|
||||
debugInfo('WS connection does not have an associated session.');
|
||||
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, 'WS connection does not have an associated session.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.#closeBrowserInstanceIfLaunched(session);
|
||||
this.#sessions.delete(session.sessionId);
|
||||
}
|
||||
catch (e) {
|
||||
debugInfo('Error while closing session', e);
|
||||
this.#respondWithError(connection, plainCommandData, "unknown error" /* ErrorCode.UnknownError */, `Session cannot be closed. Error: ${e?.message}`);
|
||||
return;
|
||||
}
|
||||
this.#sendClientMessage({
|
||||
id: parsedCommandData.id,
|
||||
type: 'success',
|
||||
result: {},
|
||||
}, connection);
|
||||
return;
|
||||
}
|
||||
if (session === undefined) {
|
||||
debugInfo('Session is not yet initialized.');
|
||||
this.#respondWithError(connection, plainCommandData, "invalid session id" /* ErrorCode.InvalidSessionId */, 'Session is not yet initialized.');
|
||||
return;
|
||||
}
|
||||
if (session.browserInstancePromise === undefined) {
|
||||
debugInfo('Browser instance is not launched.');
|
||||
this.#respondWithError(connection, plainCommandData, "invalid session id" /* ErrorCode.InvalidSessionId */, 'Browser instance is not launched.');
|
||||
return;
|
||||
}
|
||||
const browserInstance = await session.browserInstancePromise;
|
||||
// Handle `browser.close` command.
|
||||
if (parsedCommandData.method === 'browser.close') {
|
||||
await browserInstance.close();
|
||||
this.#sendClientMessage({
|
||||
id: parsedCommandData.id,
|
||||
type: 'success',
|
||||
result: {},
|
||||
}, connection);
|
||||
return;
|
||||
}
|
||||
// Forward all other commands to BiDi Mapper.
|
||||
await browserInstance.bidiSession().sendCommand(plainCommandData);
|
||||
});
|
||||
connection.on('close', async () => {
|
||||
debugInternal(`Peer ${connection.remoteAddress} disconnected.`);
|
||||
// TODO: don't close Browser instance to allow re-connecting to the session.
|
||||
await this.#closeBrowserInstanceIfLaunched(session);
|
||||
});
|
||||
}
|
||||
async #closeBrowserInstanceIfLaunched(session) {
|
||||
if (session === undefined || session.browserInstancePromise === undefined) {
|
||||
return;
|
||||
}
|
||||
const browserInstance = await session.browserInstancePromise;
|
||||
session.browserInstancePromise = undefined;
|
||||
void browserInstance.close();
|
||||
}
|
||||
#getChromeOptions(capabilities) {
|
||||
const chromeCapabilities = capabilities?.alwaysMatch?.['goog:chromeOptions'];
|
||||
return {
|
||||
chromeArgs: chromeCapabilities?.args ?? [],
|
||||
chromeBinary: chromeCapabilities?.binary ?? undefined,
|
||||
};
|
||||
}
|
||||
async #launchBrowserInstance(connection, sessionOptions, passSessionNewThrough = false) {
|
||||
debugInfo('Scheduling browser launch...');
|
||||
const browserInstance = await BrowserInstance.run(sessionOptions.chromeOptions, sessionOptions.verbose);
|
||||
const body = JSON.parse(sessionOptions.sessionNewBody);
|
||||
const id = body.id;
|
||||
const sessionCreated = new Deferred();
|
||||
const sessionResponseListener = (message) => {
|
||||
const jsonMessage = JSON.parse(message);
|
||||
if (jsonMessage['id'] === id) {
|
||||
debugInfo('Receiving session.new response from mapper', message);
|
||||
sessionCreated.resolve();
|
||||
if (passSessionNewThrough) {
|
||||
this.#sendClientMessageString(message, connection);
|
||||
}
|
||||
}
|
||||
};
|
||||
browserInstance.bidiSession().on('message', sessionResponseListener);
|
||||
debugInfo('Sending session.new to mapper', sessionOptions.sessionNewBody);
|
||||
await browserInstance
|
||||
.bidiSession()
|
||||
.sendCommand(sessionOptions.sessionNewBody);
|
||||
await sessionCreated;
|
||||
browserInstance.bidiSession().off('message', sessionResponseListener);
|
||||
// Forward messages from BiDi Mapper to the client unconditionally.
|
||||
browserInstance.bidiSession().on('message', (message) => {
|
||||
this.#sendClientMessageString(message, connection);
|
||||
});
|
||||
debugInfo('Browser is launched!');
|
||||
return browserInstance;
|
||||
}
|
||||
#sendClientMessageString(message, connection) {
|
||||
if (debugSend.enabled) {
|
||||
try {
|
||||
debugSend(JSON.parse(message));
|
||||
}
|
||||
catch {
|
||||
debugSend(message);
|
||||
}
|
||||
}
|
||||
connection.sendUTF(message);
|
||||
}
|
||||
#sendClientMessage(object, connection) {
|
||||
const json = JSON.stringify(object);
|
||||
return this.#sendClientMessageString(json, connection);
|
||||
}
|
||||
#respondWithError(connection, plainCommandData, errorCode, errorMessage) {
|
||||
const errorResponse = this.#getErrorResponse(plainCommandData, errorCode, errorMessage);
|
||||
void this.#sendClientMessage(errorResponse, connection);
|
||||
}
|
||||
#getErrorResponse(plainCommandData, errorCode, errorMessage) {
|
||||
// XXX: this is bizarre per spec. We reparse the payload and
|
||||
// extract the ID, regardless of what kind of value it was.
|
||||
let commandId;
|
||||
try {
|
||||
const commandData = JSON.parse(plainCommandData);
|
||||
if ('id' in commandData) {
|
||||
commandId = commandData.id;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return {
|
||||
type: 'error',
|
||||
id: commandId,
|
||||
error: errorCode,
|
||||
message: errorMessage,
|
||||
// XXX: optional stacktrace field.
|
||||
};
|
||||
}
|
||||
#getHttpRequestPayload(request) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let data = '';
|
||||
request.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
request.on('end', () => {
|
||||
resolve(data);
|
||||
});
|
||||
request.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=WebSocketServer.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/WebSocketServer.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/WebSocketServer.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
23
node_modules/chromium-bidi/lib/esm/bidiServer/index.d.ts
generated
vendored
Normal file
23
node_modules/chromium-bidi/lib/esm/bidiServer/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
export declare function parseCommandLineArgs(): {
|
||||
[x: string]: unknown;
|
||||
port: number;
|
||||
verbose: boolean;
|
||||
_: (string | number)[];
|
||||
$0: string;
|
||||
};
|
||||
49
node_modules/chromium-bidi/lib/esm/bidiServer/index.js
generated
vendored
Normal file
49
node_modules/chromium-bidi/lib/esm/bidiServer/index.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import { debugInfo, WebSocketServer } from './WebSocketServer.js';
|
||||
export function parseCommandLineArgs() {
|
||||
return yargs(hideBin(process.argv))
|
||||
.usage(`$0`, `[PORT=8080] [VERBOSE=8080]`)
|
||||
.option('port', {
|
||||
alias: 'p',
|
||||
describe: 'Port that BiDi server should listen to. Default is 8080.',
|
||||
type: 'number',
|
||||
default: process.env['PORT'] ? Number(process.env['PORT']) : 8080,
|
||||
})
|
||||
.option('verbose', {
|
||||
alias: 'v',
|
||||
describe: 'If present, the Mapper debug log, including CDP commands and events will be logged into the server output.',
|
||||
type: 'boolean',
|
||||
default: process.env['VERBOSE'] === 'true' || false,
|
||||
})
|
||||
.parseSync();
|
||||
}
|
||||
(() => {
|
||||
try {
|
||||
const argv = parseCommandLineArgs();
|
||||
const { port, verbose } = argv;
|
||||
debugInfo('Launching BiDi server...');
|
||||
new WebSocketServer(port, verbose);
|
||||
debugInfo('BiDi server launched');
|
||||
}
|
||||
catch (e) {
|
||||
debugInfo('Error launching BiDi server', e);
|
||||
}
|
||||
})();
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/index.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bidiServer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAEhE,MAAM,UAAU,oBAAoB;IAClC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;SAChC,KAAK,CAAC,IAAI,EAAE,4BAA4B,CAAC;SACzC,MAAM,CAAC,MAAM,EAAE;QACd,KAAK,EAAE,GAAG;QACV,QAAQ,EAAE,0DAA0D;QACpE,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;KAClE,CAAC;SACD,MAAM,CAAC,SAAS,EAAE;QACjB,KAAK,EAAE,GAAG;QACV,QAAQ,EACN,4GAA4G;QAC9G,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,KAAK;KACpD,CAAC;SACD,SAAS,EAAE,CAAC;AACjB,CAAC;AAED,CAAC,GAAG,EAAE;IACJ,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC;QAEpC,MAAM,EAAC,IAAI,EAAE,OAAO,EAAC,GAAG,IAAI,CAAC;QAE7B,SAAS,CAAC,0BAA0B,CAAC,CAAC;QAEtC,IAAI,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACnC,SAAS,CAAC,sBAAsB,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,SAAS,CAAC,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC,EAAE,CAAC"}
|
||||
17
node_modules/chromium-bidi/lib/esm/bidiServer/reader.d.ts
generated
vendored
Normal file
17
node_modules/chromium-bidi/lib/esm/bidiServer/reader.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
export declare function getMapperTabSource(): Promise<string>;
|
||||
25
node_modules/chromium-bidi/lib/esm/bidiServer/reader.js
generated
vendored
Normal file
25
node_modules/chromium-bidi/lib/esm/bidiServer/reader.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright 2021 Google LLC.
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import url from 'url';
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
export async function getMapperTabSource() {
|
||||
return await fs.readFile(path.join(__dirname, '../../iife/mapperTab.js'), 'utf8');
|
||||
}
|
||||
//
|
||||
//# sourceMappingURL=reader.js.map
|
||||
1
node_modules/chromium-bidi/lib/esm/bidiServer/reader.js.map
generated
vendored
Normal file
1
node_modules/chromium-bidi/lib/esm/bidiServer/reader.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/bidiServer/reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,MAAM,SAAS,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEnE,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,OAAO,MAAM,EAAE,CAAC,QAAQ,CACtB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,yBAAyB,CAAC,EAC/C,MAAM,CACP,CAAC;AACJ,CAAC;AACD,EAAE"}
|
||||
Reference in New Issue
Block a user