A big commit with a bunch of node modules so I could run puppeteer for Walmart. Added some todos and Headway's templates.

This commit is contained in:
Norm Rasmussen
2024-02-28 17:13:10 -05:00
parent dbcdfc8472
commit 1184fe0cd1
1107 changed files with 76526 additions and 8934 deletions

View File

@ -1,6 +1,6 @@
import { type ChromeReleaseChannel, type Process } from '@puppeteer/browsers';
import type { MapperOptions } from '../bidiMapper/BidiServer.js';
import { MapperCdpConnection } from './MapperCdpConnection.js';
import { MapperServerCdpConnection } from './MapperCdpConnection.js';
import type { SimpleTransport } from './SimpleTransport.js';
type ChromeOptions = {
chromeArgs: string[];
@ -20,7 +20,7 @@ type ChromeOptions = {
export declare class BrowserInstance {
#private;
static run(chromeOptions: ChromeOptions, mapperOptions: MapperOptions, verbose: boolean): Promise<BrowserInstance>;
constructor(mapperCdpConnection: MapperCdpConnection, browserProcess: Process);
constructor(mapperCdpConnection: MapperServerCdpConnection, browserProcess: Process);
close(): Promise<void>;
bidiSession(): SimpleTransport;
}

View File

@ -83,6 +83,7 @@ class BrowserInstance {
const browserProcess = (0, browsers_1.launch)({
executablePath,
args: chromeArguments,
env: process.env,
});
const cdpEndpoint = await browserProcess.waitForLineOutput(browsers_1.CDP_WEBSOCKET_ENDPOINT_REGEX);
// There is a conflict between prettier and eslint here.
@ -91,7 +92,7 @@ class BrowserInstance {
// 2. Get `BiDi-CDP` mapper JS binaries.
const mapperTabSource = await (0, reader_js_1.getMapperTabSource)();
// 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`.
const mapperCdpConnection = await MapperCdpConnection_js_1.MapperCdpConnection.create(cdpConnection, mapperTabSource, verbose, mapperOptions);
const mapperCdpConnection = await MapperCdpConnection_js_1.MapperServerCdpConnection.create(cdpConnection, mapperTabSource, verbose, mapperOptions);
return new BrowserInstance(mapperCdpConnection, browserProcess);
}
constructor(mapperCdpConnection, browserProcess) {
@ -115,7 +116,7 @@ class BrowserInstance {
ws.on('open', () => {
debugInternal('Session established.');
const transport = new WebsocketTransport_js_1.WebSocketTransport(ws);
const connection = new CdpConnection_js_1.CdpConnection(transport);
const connection = new CdpConnection_js_1.MapperCdpConnection(transport);
resolve(connection);
});
});

View File

@ -1 +1 @@
{"version":3,"file":"BrowserInstance.js","sourceRoot":"","sources":["../../../src/bidiServer/BrowserInstance.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;AAEH,0CAAoC;AACpC,4CAAoB;AACpB,gDAAwB;AAExB,kDAO6B;AAC7B,kDAA0B;AAC1B,4CAA2B;AAG3B,8DAAsD;AACtD,0EAAkE;AAElE,qEAA6D;AAC7D,2CAA+C;AAG/C,MAAM,aAAa,GAAG,IAAA,eAAK,EAAC,sBAAsB,CAAC,CAAC;AASpD;;;;;;;;GAQG;AACH,MAAa,eAAe;IAC1B,oBAAoB,CAAsB;IAC1C,eAAe,CAAU;IAEzB,MAAM,CAAC,KAAK,CAAC,GAAG,CACd,aAA4B,EAC5B,aAA4B,EAC5B,OAAgB;QAEhB,MAAM,UAAU,GAAG,MAAM,IAAA,kBAAO,EAC9B,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAClD,CAAC;QACF,+FAA+F;QAC/F,MAAM,eAAe,GAAG;YACtB,GAAG,CAAC,aAAa,CAAC,QAAQ;gBACxB,CAAC,CAAC,CAAC,YAAY,EAAE,mBAAmB,EAAE,cAAc,CAAC;gBACrD,CAAC,CAAC,EAAE,CAAC;YACP,oBAAoB;YACpB,8BAA8B;YAC9B,4BAA4B;YAC5B,wBAAwB;YACxB,kEAAkE;YAClE,oBAAoB;YACpB,yBAAyB;YACzB,0BAA0B;YAC1B,uCAAuC;YACvC,qBAAqB;YACrB,4BAA4B;YAC5B,gBAAgB;YAChB,wBAAwB;YACxB,8BAA8B;YAC9B,qBAAqB;YACrB,mBAAmB,UAAU,EAAE;YAC/B,kBAAkB;YAClB,GAAG,aAAa,CAAC,UAAU,CAAC,MAAM,CAChC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,CACvC;YACD,aAAa;SACd,CAAC;QAEF,MAAM,cAAc,GAClB,aAAa,CAAC,YAAY;YAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YAC1B,IAAA,sCAA2B,EAAC;gBAC1B,OAAO,EAAE,kBAAO,CAAC,MAAM;gBACvB,OAAO,EAAE,aAAa,CAAC,OAAO;aAC/B,CAAC,CAAC;QAEL,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,cAAc,GAAG,IAAA,iBAAM,EAAC;YAC5B,cAAc;YACd,IAAI,EAAE,eAAe;SACtB,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,iBAAiB,CACxD,uCAA4B,CAC7B,CAAC;QAEF,wDAAwD;QACxD,kBAAkB;QAClB,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,uBAAuB,CACtD,WAAW,CACZ,CAAC;QAEF,wCAAwC;QACxC,MAAM,eAAe,GAAG,MAAM,IAAA,8BAAkB,GAAE,CAAC;QAEnD,qEAAqE;QACrE,MAAM,mBAAmB,GAAG,MAAM,4CAAmB,CAAC,MAAM,CAC1D,aAAa,EACb,eAAe,EACf,OAAO,EACP,aAAa,CACd,CAAC;QAEF,OAAO,IAAI,eAAe,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;IAClE,CAAC;IAED,YACE,mBAAwC,EACxC,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,uBAAuB,CAAC,MAAc;QAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,aAAa,CAAC,oCAAoC,EAAE,MAAM,CAAC,CAAC;YAE5D,MAAM,EAAE,GAAG,IAAI,YAAS,CAAC,MAAM,CAAC,CAAC;YAEjC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAEzB,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBACjB,aAAa,CAAC,sBAAsB,CAAC,CAAC;gBAEtC,MAAM,SAAS,GAAG,IAAI,0CAAkB,CAAC,EAAE,CAAC,CAAC;gBAC7C,MAAM,UAAU,GAAG,IAAI,gCAAa,CAAC,SAAS,CAAC,CAAC;gBAChD,OAAO,CAAC,UAAU,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAtHD,0CAsHC"}
{"version":3,"file":"BrowserInstance.js","sourceRoot":"","sources":["../../../src/bidiServer/BrowserInstance.ts"],"names":[],"mappings":"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"}

View File

@ -15,11 +15,11 @@
* limitations under the License.
*/
import type { MapperOptions } from '../bidiMapper/BidiServer.js';
import type { CdpConnection } from '../cdp/CdpConnection.js';
import type { MapperCdpConnection } from '../cdp/CdpConnection.js';
import { SimpleTransport } from './SimpleTransport.js';
export declare class MapperCdpConnection {
export declare class MapperServerCdpConnection {
#private;
static create(cdpConnection: CdpConnection, mapperTabSource: string, verbose: boolean, mapperOptions: MapperOptions): Promise<MapperCdpConnection>;
static create(cdpConnection: MapperCdpConnection, mapperTabSource: string, verbose: boolean, mapperOptions: MapperOptions): Promise<MapperServerCdpConnection>;
private constructor();
close(): void;
bidiSession(): SimpleTransport;

View File

@ -19,7 +19,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapperCdpConnection = void 0;
exports.MapperServerCdpConnection = void 0;
const debug_1 = __importDefault(require("debug"));
const SimpleTransport_js_1 = require("./SimpleTransport.js");
const debugInternal = (0, debug_1.default)('bidi:mapper:internal');
@ -36,32 +36,26 @@ const getLogger = (type) => {
}
return logger;
};
class MapperCdpConnection {
class MapperServerCdpConnection {
#cdpConnection;
#mapperCdpClient;
#bidiSession;
static async create(cdpConnection, mapperTabSource, verbose, mapperOptions) {
try {
const mapperCdpClient = await this.#initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions);
return new MapperCdpConnection(cdpConnection, mapperCdpClient);
const bidiSession = await this.#initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions);
return new MapperServerCdpConnection(cdpConnection, bidiSession);
}
catch (e) {
cdpConnection.close();
throw e;
}
}
constructor(cdpConnection, mapperCdpClient) {
constructor(cdpConnection, bidiSession) {
this.#cdpConnection = cdpConnection;
this.#mapperCdpClient = mapperCdpClient;
this.#bidiSession = new SimpleTransport_js_1.SimpleTransport(async (message) => await this.#sendMessage(message));
this.#mapperCdpClient.on('Runtime.bindingCalled', this.#onBindingCalled);
this.#mapperCdpClient.on('Runtime.consoleAPICalled', this.#onConsoleAPICalled);
// Catch unhandled exceptions in the mapper.
this.#mapperCdpClient.on('Runtime.exceptionThrown', this.#onRuntimeExceptionThrown);
this.#bidiSession = bidiSession;
}
async #sendMessage(message) {
static async #sendMessage(mapperCdpClient, message) {
try {
await this.#mapperCdpClient.sendCommand('Runtime.evaluate', {
await mapperCdpClient.sendCommand('Runtime.evaluate', {
expression: `onBidiMessage(${JSON.stringify(message)})`,
});
}
@ -75,15 +69,15 @@ class MapperCdpConnection {
bidiSession() {
return this.#bidiSession;
}
#onBindingCalled = (params) => {
static #onBindingCalled = (params, bidiSession) => {
if (params.name === 'sendBidiResponse') {
this.#bidiSession.emit('message', params.payload);
bidiSession.emit('message', params.payload);
}
else if (params.name === 'sendDebugMessage') {
this.#onDebugMessage(params.payload);
}
};
#onDebugMessage = (json) => {
static #onDebugMessage = (json) => {
try {
const log = JSON.parse(json);
if (log.logType !== undefined && log.messages !== undefined) {
@ -96,10 +90,10 @@ class MapperCdpConnection {
debugOthers(json);
}
};
#onConsoleAPICalled = (params) => {
static #onConsoleAPICalled = (params) => {
debugInfo('consoleAPICalled: %s %O', params.type, params.args.map((arg) => arg.value));
};
#onRuntimeExceptionThrown = (params) => {
static #onRuntimeExceptionThrown = (params) => {
debugInfo('exceptionThrown:', params);
};
static async #initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions) {
@ -110,6 +104,13 @@ class MapperCdpConnection {
});
const { sessionId: mapperSessionId } = await browserClient.sendCommand('Target.attachToTarget', { targetId: mapperTabTargetId, flatten: true });
const mapperCdpClient = cdpConnection.getCdpClient(mapperSessionId);
const bidiSession = new SimpleTransport_js_1.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',
@ -133,8 +134,8 @@ class MapperCdpConnection {
awaitPromise: true,
});
debugInternal('Mapper is launched!');
return mapperCdpClient;
return bidiSession;
}
}
exports.MapperCdpConnection = MapperCdpConnection;
exports.MapperServerCdpConnection = MapperServerCdpConnection;
//# sourceMappingURL=MapperCdpConnection.js.map

View File

@ -1 +1 @@
{"version":3,"file":"MapperCdpConnection.js","sourceRoot":"","sources":["../../../src/bidiServer/MapperCdpConnection.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;AAEH,kDAA2C;AAQ3C,6DAAqD;AAErD,MAAM,aAAa,GAAG,IAAA,eAAK,EAAC,sBAAsB,CAAC,CAAC;AACpD,MAAM,SAAS,GAAG,IAAA,eAAK,EAAC,kBAAkB,CAAC,CAAC;AAC5C,MAAM,WAAW,GAAG,IAAA,eAAK,EAAC,0BAA0B,CAAC,CAAC;AACtD,6BAA6B;AAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;AAC5C,MAAM,SAAS,GAAG,CAAC,IAAe,EAAE,EAAE;IACpC,MAAM,MAAM,GAAG,eAAe,IAAI,EAAE,CAAC;IACrC,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAA,eAAK,EAAC,MAAM,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAa,mBAAmB;IAC9B,cAAc,CAAgB;IAC9B,gBAAgB,CAAY;IAC5B,YAAY,CAAkB;IAE9B,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,aAA4B,EAC5B,eAAuB,EACvB,OAAgB,EAChB,aAA4B;QAE5B,IAAI,CAAC;YACH,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,WAAW,CAC5C,aAAa,EACb,eAAe,EACf,OAAO,EACP,aAAa,CACd,CAAC;YACF,OAAO,IAAI,mBAAmB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,aAAa,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,YACE,aAA4B,EAC5B,eAA0B;QAE1B,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;QACpC,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;QACxC,IAAI,CAAC,YAAY,GAAG,IAAI,oCAAe,CACrC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CACpD,CAAC;QAEF,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,uBAAuB,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACzE,IAAI,CAAC,gBAAgB,CAAC,EAAE,CACtB,0BAA0B,EAC1B,IAAI,CAAC,mBAAmB,CACzB,CAAC;QACF,4CAA4C;QAC5C,IAAI,CAAC,gBAAgB,CAAC,EAAE,CACtB,yBAAyB,EACzB,IAAI,CAAC,yBAAyB,CAC/B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAe;QAChC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,kBAAkB,EAAE;gBAC1D,UAAU,EAAE,iBAAiB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG;aACxD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,gBAAgB,GAAG,CAAC,MAA2C,EAAE,EAAE;QACjE,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACvC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IAEF,eAAe,GAAG,CAAC,IAAY,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,GAGL,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAErB,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACtC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;YAC1C,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,mBAAmB,GAAG,CAAC,MAA8C,EAAE,EAAE;QACvE,SAAS,CACP,yBAAyB,EACzB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CACpC,CAAC;IACJ,CAAC,CAAC;IAEF,yBAAyB,GAAG,CAC1B,MAA6C,EAC7C,EAAE;QACF,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,WAAW,CACtB,aAA4B,EAC5B,eAAuB,EACvB,OAAgB,EAChB,aAA4B;QAE5B,aAAa,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QAErD,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,oBAAoB,EAAE,CAAC;QAEjE,MAAM,EAAC,QAAQ,EAAE,iBAAiB,EAAC,GAAG,MAAM,aAAa,CAAC,WAAW,CACnE,qBAAqB,EACrB;YACE,GAAG,EAAE,aAAa;SACnB,CACF,CAAC;QACF,MAAM,EAAC,SAAS,EAAE,eAAe,EAAC,GAAG,MAAM,aAAa,CAAC,WAAW,CAClE,uBAAuB,EACvB,EAAC,QAAQ,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAC,CAC7C,CAAC;QAEF,MAAM,eAAe,GAAG,aAAa,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;QAEpE,MAAM,eAAe,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAEpD,MAAM,aAAa,CAAC,WAAW,CAAC,+BAA+B,EAAE;YAC/D,WAAW,EAAE,KAAK;YAClB,QAAQ,EAAE,iBAAiB;SAC5B,CAAC,CAAC;QAEH,MAAM,eAAe,CAAC,WAAW,CAAC,oBAAoB,EAAE;YACtD,IAAI,EAAE,kBAAkB;SACzB,CAAC,CAAC;QAEH,IAAI,OAAO,EAAE,CAAC;YACZ,8CAA8C;YAC9C,MAAM,eAAe,CAAC,WAAW,CAAC,oBAAoB,EAAE;gBACtD,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;QACL,CAAC;QAED,0CAA0C;QAC1C,MAAM,eAAe,CAAC,WAAW,CAAC,kBAAkB,EAAE;YACpD,UAAU,EAAE,eAAe;SAC5B,CAAC,CAAC;QAEH,MAAM,eAAe,CAAC,WAAW,CAAC,kBAAkB,EAAE;YACpD,UAAU,EAAE,6BAA6B,iBAAiB,MAAM,IAAI,CAAC,SAAS,CAC5E,aAAa,CACd,GAAG;YACJ,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QAEH,aAAa,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,eAAe,CAAC;IACzB,CAAC;CACF;AAhKD,kDAgKC"}
{"version":3,"file":"MapperCdpConnection.js","sourceRoot":"","sources":["../../../src/bidiServer/MapperCdpConnection.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;AAEH,kDAA2C;AAQ3C,6DAAqD;AAErD,MAAM,aAAa,GAAG,IAAA,eAAK,EAAC,sBAAsB,CAAC,CAAC;AACpD,MAAM,SAAS,GAAG,IAAA,eAAK,EAAC,kBAAkB,CAAC,CAAC;AAC5C,MAAM,WAAW,GAAG,IAAA,eAAK,EAAC,0BAA0B,CAAC,CAAC;AACtD,6BAA6B;AAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;AAC5C,MAAM,SAAS,GAAG,CAAC,IAAe,EAAE,EAAE;IACpC,MAAM,MAAM,GAAG,eAAe,IAAI,EAAE,CAAC;IACrC,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAA,eAAK,EAAC,MAAM,CAAC,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAa,yBAAyB;IACpC,cAAc,CAAsB;IACpC,YAAY,CAAkB;IAE9B,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,aAAkC,EAClC,eAAuB,EACvB,OAAgB,EAChB,aAA4B;QAE5B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,CACxC,aAAa,EACb,eAAe,EACf,OAAO,EACP,aAAa,CACd,CAAC;YACF,OAAO,IAAI,yBAAyB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,aAAa,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IAED,YACE,aAAkC,EAClC,WAA4B;QAE5B,IAAI,CAAC,cAAc,GAAG,aAAa,CAAC;QACpC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;IAClC,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,YAAY,CACvB,eAAgC,EAChC,OAAe;QAEf,IAAI,CAAC;YACH,MAAM,eAAe,CAAC,WAAW,CAAC,kBAAkB,EAAE;gBACpD,UAAU,EAAE,iBAAiB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG;aACxD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,gBAAgB,GAAG,CACxB,MAA2C,EAC3C,WAA4B,EAC5B,EAAE;QACF,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACvC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,eAAe,GAAG,CAAC,IAAY,EAAE,EAAE;QACxC,IAAI,CAAC;YACH,MAAM,GAAG,GAGL,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAErB,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC5D,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACtC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;YAC1C,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,mBAAmB,GAAG,CAC3B,MAA8C,EAC9C,EAAE;QACF,SAAS,CACP,yBAAyB,EACzB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CACpC,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,CAAC,yBAAyB,GAAG,CACjC,MAA6C,EAC7C,EAAE;QACF,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,WAAW,CACtB,aAAkC,EAClC,eAAuB,EACvB,OAAgB,EAChB,aAA4B;QAE5B,aAAa,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAC;QAErD,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,oBAAoB,EAAE,CAAC;QAEjE,MAAM,EAAC,QAAQ,EAAE,iBAAiB,EAAC,GAAG,MAAM,aAAa,CAAC,WAAW,CACnE,qBAAqB,EACrB;YACE,GAAG,EAAE,aAAa;SACnB,CACF,CAAC;QACF,MAAM,EAAC,SAAS,EAAE,eAAe,EAAC,GAAG,MAAM,aAAa,CAAC,WAAW,CAClE,uBAAuB,EACvB,EAAC,QAAQ,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAC,CAC7C,CAAC;QAEF,MAAM,eAAe,GAAG,aAAa,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;QAEpE,MAAM,WAAW,GAAG,IAAI,oCAAe,CACrC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CACrE,CAAC;QAEF,yCAAyC;QACzC,eAAe,CAAC,EAAE,CAAC,uBAAuB,EAAE,CAAC,MAAM,EAAE,EAAE,CACrD,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC,CAC3C,CAAC;QACF,gDAAgD;QAChD,eAAe,CAAC,EAAE,CAAC,0BAA0B,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACzE,4CAA4C;QAC5C,eAAe,CAAC,EAAE,CAChB,yBAAyB,EACzB,IAAI,CAAC,yBAAyB,CAC/B,CAAC;QAEF,MAAM,eAAe,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAEpD,MAAM,aAAa,CAAC,WAAW,CAAC,+BAA+B,EAAE;YAC/D,WAAW,EAAE,KAAK;YAClB,QAAQ,EAAE,iBAAiB;SAC5B,CAAC,CAAC;QAEH,MAAM,eAAe,CAAC,WAAW,CAAC,oBAAoB,EAAE;YACtD,IAAI,EAAE,kBAAkB;SACzB,CAAC,CAAC;QAEH,IAAI,OAAO,EAAE,CAAC;YACZ,8CAA8C;YAC9C,MAAM,eAAe,CAAC,WAAW,CAAC,oBAAoB,EAAE;gBACtD,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;QACL,CAAC;QAED,0CAA0C;QAC1C,MAAM,eAAe,CAAC,WAAW,CAAC,kBAAkB,EAAE;YACpD,UAAU,EAAE,eAAe;SAC5B,CAAC,CAAC;QAEH,MAAM,eAAe,CAAC,WAAW,CAAC,kBAAkB,EAAE;YACpD,UAAU,EAAE,6BAA6B,iBAAiB,MAAM,IAAI,CAAC,SAAS,CAC5E,aAAa,CACd,GAAG;YACJ,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QAEH,aAAa,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,WAAW,CAAC;IACrB,CAAC;;AAxKH,8DAyKC"}

View File

@ -3,11 +3,5 @@ import debug from 'debug';
export declare const debugInfo: debug.Debugger;
export declare class WebSocketServer {
#private;
/**
* @param bidiPort Port to start ws server on.
* @param channel
* @param headless
* @param verbose
*/
static run(bidiPort: number, channel: ChromeReleaseChannel, headless: boolean, verbose: boolean): void;
constructor(port: number, channel: ChromeReleaseChannel, headless: boolean, verbose: boolean);
}

View File

@ -53,205 +53,212 @@ const debugInternal = (0, debug_1.default)('bidi:server:internal');
const debugSend = (0, debug_1.default)('bidi:server:SEND â–¸');
const debugRecv = (0, debug_1.default)('bidi:server:RECV â—‚');
class WebSocketServer {
static #sessions = new Map();
/**
* @param bidiPort Port to start ws server on.
* @param channel
* @param headless
* @param verbose
*/
static run(bidiPort, channel, headless, verbose) {
const server = http_1.default.createServer(async (request, response) => {
debugInternal(`${new Date().toString()} Received HTTP ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)}`);
if (!request.url) {
return response.end(404);
}
// https://w3c.github.io/webdriver-bidi/#transport, step 2.
if (request.url === '/session') {
const body = [];
request
.on('data', (chunk) => {
body.push(chunk);
})
.on('end', () => {
const jsonBody = JSON.parse(Buffer.concat(body).toString());
response.writeHead(200, {
'Content-Type': 'application/json;charset=utf-8',
'Cache-Control': 'no-cache',
});
const sessionId = (0, uuid_js_1.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, channel, headless),
mapperOptions: this.#getMapperOptions(jsonBody.capabilities),
verbose,
},
};
this.#sessions.set(sessionId, session);
const webSocketUrl = `ws://localhost:${bidiPort}/session/${sessionId}`;
debugInternal(`Session created. WebSocket URL: ${JSON.stringify(webSocketUrl)}.`);
response.write(JSON.stringify({
value: {
sessionId,
capabilities: {
webSocketUrl,
},
},
}));
return response.end();
});
return;
}
else if (request.url.startsWith('/session')) {
debugInternal(`Unknown session command ${request.method ?? 'UNKNOWN METHOD'} request for ${request.url} with payload ${await WebSocketServer.#getHttpRequestPayload(request)}. 200 returned.`);
response.writeHead(200, {
'Content-Type': 'application/json;charset=utf-8',
'Cache-Control': 'no-cache',
});
response.write(JSON.stringify({
value: {},
}));
}
else {
debugInternal(`Unknown ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)} with payload ${JSON.stringify(await WebSocketServer.#getHttpRequestPayload(request))}. 404 returned.`);
response.writeHead(404);
}
return response.end();
});
server.listen(bidiPort, () => {
(0, exports.debugInfo)('BiDi server is listening on port', bidiPort);
});
const wsServer = new websocket.server({
httpServer: server,
#sessions = new Map();
#port;
#channel;
#headless;
#verbose;
#server;
#wsServer;
constructor(port, channel, headless, verbose) {
this.#port = port;
this.#channel = channel;
this.#headless = headless;
this.#verbose = verbose;
this.#server = http_1.default.createServer(this.#onRequest.bind(this));
this.#wsServer = new websocket.server({
httpServer: this.#server,
autoAcceptConnections: false,
});
wsServer.on('request', (request) => {
// Session is set either by Classic or BiDi commands.
let session;
const 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) => {
(0, exports.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 (e) {
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `Cannot parse data as JSON`);
return;
}
// Handle creating new session.
if (parsedCommandData.method === 'session.new') {
if (session !== undefined) {
(0, exports.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, channel, headless),
mapperOptions: this.#getMapperOptions(parsedCommandData.params?.capabilities),
verbose,
};
const browserInstance = await this.#launchBrowserInstance(connection, sessionOptions);
const sessionId = (0, uuid_js_1.uuidv4)();
session = {
sessionId,
browserInstancePromise: Promise.resolve(browserInstance),
sessionOptions,
};
this.#sessions.set(sessionId, session);
}
catch (e) {
(0, exports.debugInfo)('Error while creating session', e);
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, e?.message ?? 'Unknown error');
return;
}
// TODO: extend with capabilities.
this.#sendClientMessage({
id: parsedCommandData.id,
type: 'success',
result: {
sessionId: session.sessionId,
capabilities: {},
},
}, connection);
return;
}
if (session === undefined) {
(0, exports.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) {
(0, exports.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(`${new Date().toString()} Peer ${connection.remoteAddress} disconnected.`);
// TODO: don't close Browser instance to allow re-connecting to the session.
await this.#closeBrowserInstanceIfLaunched(session);
});
this.#wsServer.on('request', this.#onWsRequest.bind(this));
this.#server.listen(this.#port, () => {
(0, exports.debugInfo)('BiDi server is listening on port', this.#port);
});
}
static async #closeBrowserInstanceIfLaunched(session) {
async #onRequest(request, response) {
debugInternal(`Received HTTP ${JSON.stringify(request.method)} request for ${JSON.stringify(request.url)}`);
if (!request.url) {
return response.end(404);
}
// 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));
});
});
// 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 = (0, uuid_js_1.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, this.#channel, this.#headless),
mapperOptions: this.#getMapperOptions(jsonBody.capabilities),
verbose: this.#verbose,
},
};
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();
}
debugInternal(`Unknown ${request.method} request for ${JSON.stringify(request.url)} with payload ${await this.#getHttpRequestPayload(request)}. 404 returned.`);
return response.end(404);
}
#onWsRequest(request) {
// Session is set either by Classic or BiDi commands.
let session;
const 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) => {
(0, exports.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 (e) {
this.#respondWithError(connection, {}, "invalid argument" /* ErrorCode.InvalidArgument */, `Cannot parse data as JSON`);
return;
}
// Handle creating new session.
if (parsedCommandData.method === 'session.new') {
if (session !== undefined) {
(0, exports.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, this.#channel, this.#headless),
mapperOptions: this.#getMapperOptions(parsedCommandData.params?.capabilities),
verbose: this.#verbose,
};
const browserInstance = await this.#launchBrowserInstance(connection, sessionOptions);
const sessionId = (0, uuid_js_1.uuidv4)();
session = {
sessionId,
browserInstancePromise: Promise.resolve(browserInstance),
sessionOptions,
};
this.#sessions.set(sessionId, session);
}
catch (e) {
(0, exports.debugInfo)('Error while creating session', e);
this.#respondWithError(connection, plainCommandData, "session not created" /* ErrorCode.SessionNotCreated */, e?.message ?? 'Unknown error');
return;
}
// TODO: extend with capabilities.
this.#sendClientMessage({
id: parsedCommandData.id,
type: 'success',
result: {
sessionId: session.sessionId,
capabilities: {},
},
}, connection);
return;
}
if (session === undefined) {
(0, exports.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) {
(0, exports.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;
}
@ -259,11 +266,12 @@ class WebSocketServer {
session.browserInstancePromise = undefined;
void browserInstance.close();
}
static #getMapperOptions(capabilities) {
#getMapperOptions(capabilities) {
const acceptInsecureCerts = capabilities?.alwaysMatch?.acceptInsecureCerts ?? false;
return { acceptInsecureCerts };
const sharedIdWithFrame = capabilities?.alwaysMatch?.sharedIdWithFrame ?? false;
return { acceptInsecureCerts, sharedIdWithFrame };
}
static #getChromeOptions(capabilities, channel, headless) {
#getChromeOptions(capabilities, channel, headless) {
const chromeCapabilities = capabilities?.alwaysMatch?.['goog:chromeOptions'];
return {
chromeArgs: chromeCapabilities?.args ?? [],
@ -272,7 +280,7 @@ class WebSocketServer {
chromeBinary: chromeCapabilities?.binary ?? undefined,
};
}
static async #launchBrowserInstance(connection, sessionOptions) {
async #launchBrowserInstance(connection, sessionOptions) {
(0, exports.debugInfo)('Scheduling browser launch...');
const browserInstance = await BrowserInstance_js_1.BrowserInstance.run(sessionOptions.chromeOptions, sessionOptions.mapperOptions, sessionOptions.verbose);
// Forward messages from BiDi Mapper to the client unconditionally.
@ -282,7 +290,7 @@ class WebSocketServer {
(0, exports.debugInfo)('Browser is launched!');
return browserInstance;
}
static #sendClientMessageString(message, connection) {
#sendClientMessageString(message, connection) {
if (debugSend.enabled) {
try {
debugSend(JSON.parse(message));
@ -293,15 +301,15 @@ class WebSocketServer {
}
connection.sendUTF(message);
}
static #sendClientMessage(object, connection) {
#sendClientMessage(object, connection) {
const json = JSON.stringify(object);
return this.#sendClientMessageString(json, connection);
}
static #respondWithError(connection, plainCommandData, errorCode, errorMessage) {
#respondWithError(connection, plainCommandData, errorCode, errorMessage) {
const errorResponse = this.#getErrorResponse(plainCommandData, errorCode, errorMessage);
void this.#sendClientMessage(errorResponse, connection);
}
static #getErrorResponse(plainCommandData, errorCode, errorMessage) {
#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;
@ -320,7 +328,7 @@ class WebSocketServer {
// XXX: optional stacktrace field.
};
}
static #getHttpRequestPayload(request) {
#getHttpRequestPayload(request) {
return new Promise((resolve, reject) => {
let data = '';
request.on('data', (chunk) => {

File diff suppressed because one or more lines are too long

View File

@ -53,7 +53,7 @@ function parseArguments() {
const headless = args.headless !== 'false';
const verbose = args.verbose === true;
(0, WebSocketServer_js_1.debugInfo)('Launching BiDi server...');
WebSocketServer_js_1.WebSocketServer.run(port, channel, headless, verbose);
new WebSocketServer_js_1.WebSocketServer(port, channel, headless, verbose);
(0, WebSocketServer_js_1.debugInfo)('BiDi server launched');
}
catch (e) {

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bidiServer/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,kDAAyD;AACzD,uCAAwC;AAExC,6DAAgE;AAEhE,SAAS,cAAc;IAMrB,MAAM,MAAM,GAAG,IAAI,yBAAc,CAAC;QAChC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE;QACrC,IAAI,EACF,kEAAkE;YAClE,6CAA6C;QAC/C,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,+BAAoB,CAAC;QAC5C,OAAO,EAAE,+BAAoB,CAAC,GAAG;KAClC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE;QAChC,IAAI,EAAE,0EAA0E;QAChF,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE;QAClC,IAAI,EAAE,0DAA0D;QAChE,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI;KACrC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE;QACrC,IAAI,EAAE,4GAA4G;QAClH,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,KAAK;KACpD,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,CAAC,GAAG,EAAE;IACJ,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAC9B,MAAM,EAAC,OAAO,EAAE,IAAI,EAAC,GAAG,IAAI,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;QAEtC,IAAA,8BAAS,EAAC,0BAA0B,CAAC,CAAC;QAEtC,oCAAe,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,IAAA,8BAAS,EAAC,sBAAsB,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAA,8BAAS,EAAC,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC,EAAE,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/bidiServer/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,kDAAyD;AACzD,uCAAwC;AAExC,6DAAgE;AAEhE,SAAS,cAAc;IAMrB,MAAM,MAAM,GAAG,IAAI,yBAAc,CAAC;QAChC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE;QACrC,IAAI,EACF,kEAAkE;YAClE,6CAA6C;QAC/C,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,+BAAoB,CAAC;QAC5C,OAAO,EAAE,+BAAoB,CAAC,GAAG;KAClC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE;QAChC,IAAI,EAAE,0EAA0E;QAChF,OAAO,EAAE,IAAI;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE;QAClC,IAAI,EAAE,0DAA0D;QAChE,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI;KACrC,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE;QACrC,IAAI,EAAE,4GAA4G;QAClH,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,KAAK;KACpD,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,CAAC,GAAG,EAAE;IACJ,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAC9B,MAAM,EAAC,OAAO,EAAE,IAAI,EAAC,GAAG,IAAI,CAAC;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,KAAK,OAAO,CAAC;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;QAEtC,IAAA,8BAAS,EAAC,0BAA0B,CAAC,CAAC;QAEtC,IAAI,oCAAe,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,IAAA,8BAAS,EAAC,sBAAsB,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAA,8BAAS,EAAC,6BAA6B,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC,EAAE,CAAC"}