@rushstack/playwright-browser-tunnel 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.rush/temp/chunked-rush-logs/playwright-browser-tunnel._phase_build.chunks.jsonl +8 -0
  2. package/.rush/temp/operation/_phase_build/all.log +8 -0
  3. package/.rush/temp/operation/_phase_build/log-chunks.jsonl +8 -0
  4. package/.rush/temp/operation/_phase_build/state.json +3 -0
  5. package/.rush/temp/rushstack+playwright-browser-tunnel-_phase_build-83a085f61cdc0a4bb81c20aa939830fc5b5cff2f.tar.log +42 -0
  6. package/.rush/temp/shrinkwrap-deps.json +104 -0
  7. package/CHANGELOG.json +17 -0
  8. package/CHANGELOG.md +11 -0
  9. package/README.md +128 -0
  10. package/config/api-extractor.json +19 -0
  11. package/config/rig.json +7 -0
  12. package/dist/playwright-browser-tunnel.d.ts +276 -0
  13. package/eslint.config.js +18 -0
  14. package/lib/HttpServer.d.ts +20 -0
  15. package/lib/HttpServer.d.ts.map +1 -0
  16. package/lib/HttpServer.js +77 -0
  17. package/lib/HttpServer.js.map +1 -0
  18. package/lib/LaunchOptionsValidator.d.ts +93 -0
  19. package/lib/LaunchOptionsValidator.d.ts.map +1 -0
  20. package/lib/LaunchOptionsValidator.js +163 -0
  21. package/lib/LaunchOptionsValidator.js.map +1 -0
  22. package/lib/PlaywrightBrowserTunnel.d.ts +92 -0
  23. package/lib/PlaywrightBrowserTunnel.d.ts.map +1 -0
  24. package/lib/PlaywrightBrowserTunnel.js +468 -0
  25. package/lib/PlaywrightBrowserTunnel.js.map +1 -0
  26. package/lib/index.d.ts +23 -0
  27. package/lib/index.d.ts.map +1 -0
  28. package/lib/index.js +33 -0
  29. package/lib/index.js.map +1 -0
  30. package/lib/tsdoc-metadata.json +11 -0
  31. package/lib/tunneledBrowserConnection.d.ts +48 -0
  32. package/lib/tunneledBrowserConnection.d.ts.map +1 -0
  33. package/lib/tunneledBrowserConnection.js +216 -0
  34. package/lib/tunneledBrowserConnection.js.map +1 -0
  35. package/lib/utilities.d.ts +17 -0
  36. package/lib/utilities.d.ts.map +1 -0
  37. package/lib/utilities.js +41 -0
  38. package/lib/utilities.js.map +1 -0
  39. package/package.json +44 -0
  40. package/playwright.config.ts +45 -0
  41. package/rush-logs/playwright-browser-tunnel._phase_build.cache.log +3 -0
  42. package/rush-logs/playwright-browser-tunnel._phase_build.log +8 -0
  43. package/src/HttpServer.ts +87 -0
  44. package/src/LaunchOptionsValidator.ts +234 -0
  45. package/src/PlaywrightBrowserTunnel.ts +590 -0
  46. package/src/index.ts +38 -0
  47. package/src/tunneledBrowserConnection.ts +284 -0
  48. package/src/utilities.ts +42 -0
  49. package/temp/build/lint/_eslint-5eVG3S6w.json +30 -0
  50. package/temp/build/lint/lint.sarif +233 -0
  51. package/temp/build/typescript/ts_l9Fw4VUO.json +1 -0
  52. package/temp/playwright-browser-tunnel.api.md +120 -0
  53. package/tests/demo.spec.ts +10 -0
  54. package/tests/testFixture.ts +22 -0
  55. package/tsconfig.json +6 -0
@@ -0,0 +1,20 @@
1
+ import { URL } from 'node:url';
2
+ import { WebSocketServer } from 'ws';
3
+ import type { ITerminal } from '@rushstack/terminal';
4
+ /**
5
+ * This HttpServer is used for the localProxyWs WebSocketServer.
6
+ * The purpose is to parse the query params and path for the websocket url to get the
7
+ * browserName and launchOptions.
8
+ */
9
+ export declare class HttpServer {
10
+ private readonly _server;
11
+ private readonly _wsServer;
12
+ private _listeningAddress;
13
+ private _logger;
14
+ constructor(logger: ITerminal);
15
+ listenAsync(): Promise<URL>;
16
+ get endpoint(): string;
17
+ get wsServer(): WebSocketServer;
18
+ [Symbol.dispose](): void;
19
+ }
20
+ //# sourceMappingURL=HttpServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpServer.d.ts","sourceRoot":"","sources":["../src/HttpServer.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,OAAO,EAAE,eAAe,EAAkB,MAAM,IAAI,CAAC;AAErD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAerD;;;;GAIG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,OAAO,CAAY;gBAER,MAAM,EAAE,SAAS;IAevB,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC;IAqBxC,IAAW,QAAQ,IAAI,MAAM,CAK5B;IAED,IAAW,QAAQ,IAAI,eAAe,CAErC;IAEM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAIhC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
+ // See LICENSE in the project root for license information.
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.HttpServer = void 0;
9
+ const node_http_1 = __importDefault(require("node:http"));
10
+ const node_url_1 = require("node:url");
11
+ const ws_1 = require("ws");
12
+ const LOCALHOST = 'localhost';
13
+ /**
14
+ * Formats an address info object into a WebSocket-compatible address string.
15
+ * IPv6 addresses are formatted with brackets: [address]:port
16
+ * IPv4 addresses are formatted as: address:port
17
+ */
18
+ function formatAddress(addressInfo) {
19
+ return addressInfo.family === 'IPv6'
20
+ ? `[${addressInfo.address}]:${addressInfo.port}`
21
+ : `${addressInfo.address}:${addressInfo.port}`;
22
+ }
23
+ /**
24
+ * This HttpServer is used for the localProxyWs WebSocketServer.
25
+ * The purpose is to parse the query params and path for the websocket url to get the
26
+ * browserName and launchOptions.
27
+ */
28
+ class HttpServer {
29
+ constructor(logger) {
30
+ this._logger = logger;
31
+ // We'll create an HTTP server and attach a WebSocketServer in noServer mode so we can
32
+ // manually parse the URL and extract query parameters before upgrading.
33
+ this._server = node_http_1.default.createServer();
34
+ this._wsServer = new ws_1.WebSocketServer({ noServer: true });
35
+ this._server.on('upgrade', (request, socket, head) => {
36
+ // Accept all upgrades on the root path. We parse query string for browserName + launchOptions.
37
+ this._wsServer.handleUpgrade(request, socket, head, (ws) => {
38
+ this._wsServer.emit('connection', ws, request);
39
+ });
40
+ });
41
+ }
42
+ async listenAsync() {
43
+ return await new Promise((resolve) => {
44
+ // Bind to 'localhost' which resolves to IPv4 (127.0.0.1) or IPv6 (::1)
45
+ // depending on system configuration and DNS resolution
46
+ this._server.listen(0, LOCALHOST, () => {
47
+ const addressInfo = this._server.address();
48
+ if (!addressInfo) {
49
+ throw new Error('Server address is null - server may not be bound properly');
50
+ }
51
+ if (typeof addressInfo === 'string') {
52
+ throw new Error(`Server address is a pipe/socket path (${addressInfo}), expected an IP address`);
53
+ }
54
+ const formattedAddress = formatAddress(addressInfo);
55
+ this._listeningAddress = formattedAddress;
56
+ // This MUST be printed to terminal so VS Code can auto-port forward
57
+ this._logger.writeLine(`Local proxy HttpServer listening at ws://${formattedAddress}`);
58
+ resolve(new node_url_1.URL(`ws://${formattedAddress}`));
59
+ });
60
+ });
61
+ }
62
+ get endpoint() {
63
+ if (this._listeningAddress === undefined) {
64
+ throw new Error('HttpServer not listening yet');
65
+ }
66
+ return `ws://${this._listeningAddress}`;
67
+ }
68
+ get wsServer() {
69
+ return this._wsServer;
70
+ }
71
+ [Symbol.dispose]() {
72
+ this._wsServer.close();
73
+ this._server.close();
74
+ }
75
+ }
76
+ exports.HttpServer = HttpServer;
77
+ //# sourceMappingURL=HttpServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpServer.js","sourceRoot":"","sources":["../src/HttpServer.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;;;;AAE3D,0DAA6B;AAE7B,uCAA+B;AAE/B,2BAAqD;AAIrD,MAAM,SAAS,GAAW,WAAW,CAAC;AAEtC;;;;GAIG;AACH,SAAS,aAAa,CAAC,WAAwB;IAC7C,OAAO,WAAW,CAAC,MAAM,KAAK,MAAM;QAClC,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,KAAK,WAAW,CAAC,IAAI,EAAE;QAChD,CAAC,CAAC,GAAG,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAa,UAAU;IAMrB,YAAmB,MAAiB;QAClC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,sFAAsF;QACtF,wEAAwE;QACxE,IAAI,CAAC,OAAO,GAAG,mBAAI,CAAC,YAAY,EAAE,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,IAAI,oBAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzD,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;YACnD,+FAA+F;YAC/F,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAa,EAAE,EAAE;gBACpE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;YACjD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,WAAW;QACtB,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACnC,uEAAuE;YACvE,uDAAuD;YACvD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;gBACrC,MAAM,WAAW,GAAgC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACxE,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;gBAC/E,CAAC;gBACD,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;oBACpC,MAAM,IAAI,KAAK,CAAC,yCAAyC,WAAW,2BAA2B,CAAC,CAAC;gBACnG,CAAC;gBACD,MAAM,gBAAgB,GAAW,aAAa,CAAC,WAAW,CAAC,CAAC;gBAC5D,IAAI,CAAC,iBAAiB,GAAG,gBAAgB,CAAC;gBAC1C,oEAAoE;gBACpE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,4CAA4C,gBAAgB,EAAE,CAAC,CAAC;gBACvF,OAAO,CAAC,IAAI,cAAG,CAAC,QAAQ,gBAAgB,EAAE,CAAC,CAAC,CAAC;YAC/C,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAW,QAAQ;QACjB,IAAI,IAAI,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,QAAQ,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC1C,CAAC;IAED,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAEM,CAAC,MAAM,CAAC,OAAO,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF;AAzDD,gCAyDC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport http from 'node:http';\nimport type { AddressInfo } from 'node:net';\nimport { URL } from 'node:url';\n\nimport { WebSocketServer, type WebSocket } from 'ws';\n\nimport type { ITerminal } from '@rushstack/terminal';\n\nconst LOCALHOST: string = 'localhost';\n\n/**\n * Formats an address info object into a WebSocket-compatible address string.\n * IPv6 addresses are formatted with brackets: [address]:port\n * IPv4 addresses are formatted as: address:port\n */\nfunction formatAddress(addressInfo: AddressInfo): string {\n return addressInfo.family === 'IPv6'\n ? `[${addressInfo.address}]:${addressInfo.port}`\n : `${addressInfo.address}:${addressInfo.port}`;\n}\n\n/**\n * This HttpServer is used for the localProxyWs WebSocketServer.\n * The purpose is to parse the query params and path for the websocket url to get the\n * browserName and launchOptions.\n */\nexport class HttpServer {\n private readonly _server: http.Server;\n private readonly _wsServer: WebSocketServer; // local proxy websocket server accepting browser clients\n private _listeningAddress: string | undefined;\n private _logger: ITerminal;\n\n public constructor(logger: ITerminal) {\n this._logger = logger;\n // We'll create an HTTP server and attach a WebSocketServer in noServer mode so we can\n // manually parse the URL and extract query parameters before upgrading.\n this._server = http.createServer();\n this._wsServer = new WebSocketServer({ noServer: true });\n\n this._server.on('upgrade', (request, socket, head) => {\n // Accept all upgrades on the root path. We parse query string for browserName + launchOptions.\n this._wsServer.handleUpgrade(request, socket, head, (ws: WebSocket) => {\n this._wsServer.emit('connection', ws, request);\n });\n });\n }\n\n public async listenAsync(): Promise<URL> {\n return await new Promise((resolve) => {\n // Bind to 'localhost' which resolves to IPv4 (127.0.0.1) or IPv6 (::1)\n // depending on system configuration and DNS resolution\n this._server.listen(0, LOCALHOST, () => {\n const addressInfo: AddressInfo | string | null = this._server.address();\n if (!addressInfo) {\n throw new Error('Server address is null - server may not be bound properly');\n }\n if (typeof addressInfo === 'string') {\n throw new Error(`Server address is a pipe/socket path (${addressInfo}), expected an IP address`);\n }\n const formattedAddress: string = formatAddress(addressInfo);\n this._listeningAddress = formattedAddress;\n // This MUST be printed to terminal so VS Code can auto-port forward\n this._logger.writeLine(`Local proxy HttpServer listening at ws://${formattedAddress}`);\n resolve(new URL(`ws://${formattedAddress}`));\n });\n });\n }\n\n public get endpoint(): string {\n if (this._listeningAddress === undefined) {\n throw new Error('HttpServer not listening yet');\n }\n return `ws://${this._listeningAddress}`;\n }\n\n public get wsServer(): WebSocketServer {\n return this._wsServer;\n }\n\n public [Symbol.dispose](): void {\n this._wsServer.close();\n this._server.close();\n }\n}\n"]}
@@ -0,0 +1,93 @@
1
+ import type { LaunchOptions } from 'playwright-core';
2
+ import type { ITerminal } from '@rushstack/terminal';
3
+ /**
4
+ * The filename used to store the launch options allowlist.
5
+ * Stored in the user's home directory/.playwright-browser-tunnel folder.
6
+ * @beta
7
+ */
8
+ export declare const LAUNCH_OPTIONS_ALLOWLIST_FILENAME: string;
9
+ /**
10
+ * Interface for the allowlist configuration stored in the user's local file system.
11
+ * @beta
12
+ */
13
+ export interface ILaunchOptionsAllowlist {
14
+ /**
15
+ * Set of launch option keys that the user has explicitly allowed.
16
+ * These bypass the default security restrictions.
17
+ */
18
+ allowedOptions: string[];
19
+ /**
20
+ * Version of the allowlist format, for future compatibility.
21
+ */
22
+ version: number;
23
+ }
24
+ /**
25
+ * Result of validating launch options against the allowlist.
26
+ * @beta
27
+ */
28
+ export interface ILaunchOptionsValidationResult {
29
+ /**
30
+ * Whether the launch options are valid and allowed.
31
+ */
32
+ isValid: boolean;
33
+ /**
34
+ * Launch options that were denied due to security restrictions.
35
+ */
36
+ deniedOptions: Array<keyof LaunchOptions>;
37
+ /**
38
+ * Filtered launch options with denied properties removed.
39
+ */
40
+ filteredOptions: LaunchOptions;
41
+ /**
42
+ * Warning messages about denied options.
43
+ */
44
+ warnings: string[];
45
+ }
46
+ /**
47
+ * Validates Playwright launch options against security allowlists.
48
+ * Provides utilities for managing client-side allowlist configuration.
49
+ * @beta
50
+ */
51
+ export declare class LaunchOptionsValidator {
52
+ private static readonly _allowlistVersion;
53
+ /**
54
+ * Gets the path to the allowlist file in the user's local preferences folder.
55
+ * This follows the pattern of playwright-browser-installed.txt but stores in user's home directory.
56
+ */
57
+ static getAllowlistFilePath(): string;
58
+ /**
59
+ * Reads the allowlist from the user's local file system.
60
+ * Returns an empty allowlist if the file doesn't exist or is invalid.
61
+ */
62
+ static readAllowlistAsync(): Promise<ILaunchOptionsAllowlist>;
63
+ /**
64
+ * Writes the allowlist to the user's local file system.
65
+ */
66
+ static writeAllowlistAsync(allowlist: ILaunchOptionsAllowlist): Promise<void>;
67
+ /**
68
+ * Validates launch options against the security allowlist.
69
+ * All launch options are denied by default unless explicitly allowed by the user.
70
+ *
71
+ * @param launchOptions - The launch options to validate
72
+ * @param terminal - Optional terminal for logging warnings
73
+ * @returns Validation result with filtered options and warnings
74
+ */
75
+ static validateLaunchOptionsAsync(launchOptions: LaunchOptions, terminal?: ITerminal): Promise<ILaunchOptionsValidationResult>;
76
+ /**
77
+ * Adds an option to the allowlist.
78
+ */
79
+ static addToAllowlistAsync(option: keyof LaunchOptions): Promise<void>;
80
+ /**
81
+ * Removes an option from the allowlist.
82
+ */
83
+ static removeFromAllowlistAsync(option: keyof LaunchOptions): Promise<void>;
84
+ /**
85
+ * Clears the entire allowlist.
86
+ */
87
+ static clearAllowlistAsync(): Promise<void>;
88
+ /**
89
+ * Gets a human-readable description of the allowlist security model.
90
+ */
91
+ static getAllowlistDescription(): string;
92
+ }
93
+ //# sourceMappingURL=LaunchOptionsValidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaunchOptionsValidator.d.ts","sourceRoot":"","sources":["../src/LaunchOptionsValidator.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAAoD,CAAC;AAErG;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,aAAa,EAAE,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC;IAE1C;;OAEG;IACH,eAAe,EAAE,aAAa,CAAC;IAE/B;;OAEG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAa;IAEtD;;;OAGG;WACW,oBAAoB,IAAI,MAAM;IAO5C;;;OAGG;WACiB,kBAAkB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAuC1E;;OAEG;WACiB,mBAAmB,CAAC,SAAS,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAW1F;;;;;;;OAOG;WACiB,0BAA0B,CAC5C,aAAa,EAAE,aAAa,EAC5B,QAAQ,CAAC,EAAE,SAAS,GACnB,OAAO,CAAC,8BAA8B,CAAC;IA4C1C;;OAEG;WACiB,mBAAmB,CAAC,MAAM,EAAE,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IASnF;;OAEG;WACiB,wBAAwB,CAAC,MAAM,EAAE,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxF;;OAEG;WACiB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxD;;OAEG;WACW,uBAAuB,IAAI,MAAM;CAOhD"}
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3
+ // See LICENSE in the project root for license information.
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.LaunchOptionsValidator = exports.LAUNCH_OPTIONS_ALLOWLIST_FILENAME = void 0;
9
+ const node_os_1 = __importDefault(require("node:os"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const node_core_library_1 = require("@rushstack/node-core-library");
12
+ /**
13
+ * The filename used to store the launch options allowlist.
14
+ * Stored in the user's home directory/.playwright-browser-tunnel folder.
15
+ * @beta
16
+ */
17
+ exports.LAUNCH_OPTIONS_ALLOWLIST_FILENAME = '.playwright-launch-options-allowlist.json';
18
+ /**
19
+ * Validates Playwright launch options against security allowlists.
20
+ * Provides utilities for managing client-side allowlist configuration.
21
+ * @beta
22
+ */
23
+ class LaunchOptionsValidator {
24
+ /**
25
+ * Gets the path to the allowlist file in the user's local preferences folder.
26
+ * This follows the pattern of playwright-browser-installed.txt but stores in user's home directory.
27
+ */
28
+ static getAllowlistFilePath() {
29
+ // Store in user's home directory under .playwright-browser-tunnel
30
+ const homeDir = node_os_1.default.homedir();
31
+ const configDir = node_path_1.default.join(homeDir, '.playwright-browser-tunnel');
32
+ return node_path_1.default.join(configDir, exports.LAUNCH_OPTIONS_ALLOWLIST_FILENAME);
33
+ }
34
+ /**
35
+ * Reads the allowlist from the user's local file system.
36
+ * Returns an empty allowlist if the file doesn't exist or is invalid.
37
+ */
38
+ static async readAllowlistAsync() {
39
+ const allowlistPath = this.getAllowlistFilePath();
40
+ try {
41
+ if (!node_core_library_1.FileSystem.exists(allowlistPath)) {
42
+ return {
43
+ allowedOptions: [],
44
+ version: this._allowlistVersion
45
+ };
46
+ }
47
+ const content = await node_core_library_1.FileSystem.readFileAsync(allowlistPath);
48
+ const parsed = JSON.parse(content);
49
+ if (typeof parsed === 'object' &&
50
+ parsed !== null &&
51
+ 'allowedOptions' in parsed &&
52
+ Array.isArray(parsed.allowedOptions) &&
53
+ 'version' in parsed &&
54
+ typeof parsed.version === 'number') {
55
+ return parsed;
56
+ }
57
+ // Invalid format, return empty allowlist
58
+ return {
59
+ allowedOptions: [],
60
+ version: this._allowlistVersion
61
+ };
62
+ }
63
+ catch (error) {
64
+ // If we can't read the file, return empty allowlist
65
+ return {
66
+ allowedOptions: [],
67
+ version: this._allowlistVersion
68
+ };
69
+ }
70
+ }
71
+ /**
72
+ * Writes the allowlist to the user's local file system.
73
+ */
74
+ static async writeAllowlistAsync(allowlist) {
75
+ const allowlistPath = this.getAllowlistFilePath();
76
+ const configDir = node_path_1.default.dirname(allowlistPath);
77
+ // Ensure the config directory exists
78
+ await node_core_library_1.FileSystem.ensureFolderAsync(configDir);
79
+ const content = JSON.stringify(allowlist, null, 2);
80
+ await node_core_library_1.FileSystem.writeFileAsync(allowlistPath, content, { ensureFolderExists: true });
81
+ }
82
+ /**
83
+ * Validates launch options against the security allowlist.
84
+ * All launch options are denied by default unless explicitly allowed by the user.
85
+ *
86
+ * @param launchOptions - The launch options to validate
87
+ * @param terminal - Optional terminal for logging warnings
88
+ * @returns Validation result with filtered options and warnings
89
+ */
90
+ static async validateLaunchOptionsAsync(launchOptions, terminal) {
91
+ const allowlist = await this.readAllowlistAsync();
92
+ const allowedOptionsSet = new Set(allowlist.allowedOptions);
93
+ const deniedOptions = [];
94
+ const warnings = [];
95
+ const filteredOptions = {};
96
+ // Check each provided launch option - deny all unless explicitly allowed
97
+ for (const key of Object.keys(launchOptions)) {
98
+ if (allowedOptionsSet.has(key)) {
99
+ // Option is in the user's allowlist - permit it
100
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
+ filteredOptions[key] = launchOptions[key];
102
+ if (terminal) {
103
+ terminal.writeWarningLine(`Launch option '${key}' is allowed by user allowlist. ` +
104
+ `Value: ${JSON.stringify(launchOptions[key])}`);
105
+ }
106
+ }
107
+ else {
108
+ // Option is not in allowlist - deny it
109
+ deniedOptions.push(key);
110
+ const warning = `Launch option '${key}' was denied (not in allowlist). ` +
111
+ `To allow this option, add it to your local allowlist at: ${this.getAllowlistFilePath()}`;
112
+ warnings.push(warning);
113
+ if (terminal) {
114
+ terminal.writeWarningLine(warning);
115
+ }
116
+ }
117
+ }
118
+ return {
119
+ isValid: deniedOptions.length === 0,
120
+ deniedOptions,
121
+ filteredOptions,
122
+ warnings
123
+ };
124
+ }
125
+ /**
126
+ * Adds an option to the allowlist.
127
+ */
128
+ static async addToAllowlistAsync(option) {
129
+ const allowlist = await this.readAllowlistAsync();
130
+ if (!allowlist.allowedOptions.includes(option)) {
131
+ allowlist.allowedOptions.push(option);
132
+ await this.writeAllowlistAsync(allowlist);
133
+ }
134
+ }
135
+ /**
136
+ * Removes an option from the allowlist.
137
+ */
138
+ static async removeFromAllowlistAsync(option) {
139
+ const allowlist = await this.readAllowlistAsync();
140
+ allowlist.allowedOptions = allowlist.allowedOptions.filter((opt) => opt !== option);
141
+ await this.writeAllowlistAsync(allowlist);
142
+ }
143
+ /**
144
+ * Clears the entire allowlist.
145
+ */
146
+ static async clearAllowlistAsync() {
147
+ await this.writeAllowlistAsync({
148
+ allowedOptions: [],
149
+ version: this._allowlistVersion
150
+ });
151
+ }
152
+ /**
153
+ * Gets a human-readable description of the allowlist security model.
154
+ */
155
+ static getAllowlistDescription() {
156
+ return (`All launch options are denied by default for security.\n` +
157
+ `Only options explicitly added to your allowlist will be permitted.\n\n` +
158
+ `Allowlist location: ${this.getAllowlistFilePath()}`);
159
+ }
160
+ }
161
+ exports.LaunchOptionsValidator = LaunchOptionsValidator;
162
+ LaunchOptionsValidator._allowlistVersion = 1;
163
+ //# sourceMappingURL=LaunchOptionsValidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaunchOptionsValidator.js","sourceRoot":"","sources":["../src/LaunchOptionsValidator.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { LaunchOptions } from 'playwright-core';\n\nimport { FileSystem } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\n/**\n * The filename used to store the launch options allowlist.\n * Stored in the user's home directory/.playwright-browser-tunnel folder.\n * @beta\n */\nexport const LAUNCH_OPTIONS_ALLOWLIST_FILENAME: string = '.playwright-launch-options-allowlist.json';\n\n/**\n * Interface for the allowlist configuration stored in the user's local file system.\n * @beta\n */\nexport interface ILaunchOptionsAllowlist {\n /**\n * Set of launch option keys that the user has explicitly allowed.\n * These bypass the default security restrictions.\n */\n allowedOptions: string[];\n\n /**\n * Version of the allowlist format, for future compatibility.\n */\n version: number;\n}\n\n/**\n * Result of validating launch options against the allowlist.\n * @beta\n */\nexport interface ILaunchOptionsValidationResult {\n /**\n * Whether the launch options are valid and allowed.\n */\n isValid: boolean;\n\n /**\n * Launch options that were denied due to security restrictions.\n */\n deniedOptions: Array<keyof LaunchOptions>;\n\n /**\n * Filtered launch options with denied properties removed.\n */\n filteredOptions: LaunchOptions;\n\n /**\n * Warning messages about denied options.\n */\n warnings: string[];\n}\n\n/**\n * Validates Playwright launch options against security allowlists.\n * Provides utilities for managing client-side allowlist configuration.\n * @beta\n */\nexport class LaunchOptionsValidator {\n private static readonly _allowlistVersion: number = 1;\n\n /**\n * Gets the path to the allowlist file in the user's local preferences folder.\n * This follows the pattern of playwright-browser-installed.txt but stores in user's home directory.\n */\n public static getAllowlistFilePath(): string {\n // Store in user's home directory under .playwright-browser-tunnel\n const homeDir: string = os.homedir();\n const configDir: string = path.join(homeDir, '.playwright-browser-tunnel');\n return path.join(configDir, LAUNCH_OPTIONS_ALLOWLIST_FILENAME);\n }\n\n /**\n * Reads the allowlist from the user's local file system.\n * Returns an empty allowlist if the file doesn't exist or is invalid.\n */\n public static async readAllowlistAsync(): Promise<ILaunchOptionsAllowlist> {\n const allowlistPath: string = this.getAllowlistFilePath();\n\n try {\n if (!FileSystem.exists(allowlistPath)) {\n return {\n allowedOptions: [],\n version: this._allowlistVersion\n };\n }\n\n const content: string = await FileSystem.readFileAsync(allowlistPath);\n const parsed: unknown = JSON.parse(content);\n\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n 'allowedOptions' in parsed &&\n Array.isArray(parsed.allowedOptions) &&\n 'version' in parsed &&\n typeof parsed.version === 'number'\n ) {\n return parsed as ILaunchOptionsAllowlist;\n }\n\n // Invalid format, return empty allowlist\n return {\n allowedOptions: [],\n version: this._allowlistVersion\n };\n } catch (error) {\n // If we can't read the file, return empty allowlist\n return {\n allowedOptions: [],\n version: this._allowlistVersion\n };\n }\n }\n\n /**\n * Writes the allowlist to the user's local file system.\n */\n public static async writeAllowlistAsync(allowlist: ILaunchOptionsAllowlist): Promise<void> {\n const allowlistPath: string = this.getAllowlistFilePath();\n const configDir: string = path.dirname(allowlistPath);\n\n // Ensure the config directory exists\n await FileSystem.ensureFolderAsync(configDir);\n\n const content: string = JSON.stringify(allowlist, null, 2);\n await FileSystem.writeFileAsync(allowlistPath, content, { ensureFolderExists: true });\n }\n\n /**\n * Validates launch options against the security allowlist.\n * All launch options are denied by default unless explicitly allowed by the user.\n *\n * @param launchOptions - The launch options to validate\n * @param terminal - Optional terminal for logging warnings\n * @returns Validation result with filtered options and warnings\n */\n public static async validateLaunchOptionsAsync(\n launchOptions: LaunchOptions,\n terminal?: ITerminal\n ): Promise<ILaunchOptionsValidationResult> {\n const allowlist: ILaunchOptionsAllowlist = await this.readAllowlistAsync();\n const allowedOptionsSet: Set<string> = new Set(allowlist.allowedOptions);\n\n const deniedOptions: Array<keyof LaunchOptions> = [];\n const warnings: string[] = [];\n const filteredOptions: LaunchOptions = {};\n\n // Check each provided launch option - deny all unless explicitly allowed\n for (const key of Object.keys(launchOptions) as Array<keyof LaunchOptions>) {\n if (allowedOptionsSet.has(key)) {\n // Option is in the user's allowlist - permit it\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (filteredOptions as any)[key] = launchOptions[key];\n\n if (terminal) {\n terminal.writeWarningLine(\n `Launch option '${key}' is allowed by user allowlist. ` +\n `Value: ${JSON.stringify(launchOptions[key])}`\n );\n }\n } else {\n // Option is not in allowlist - deny it\n deniedOptions.push(key);\n\n const warning: string =\n `Launch option '${key}' was denied (not in allowlist). ` +\n `To allow this option, add it to your local allowlist at: ${this.getAllowlistFilePath()}`;\n warnings.push(warning);\n\n if (terminal) {\n terminal.writeWarningLine(warning);\n }\n }\n }\n\n return {\n isValid: deniedOptions.length === 0,\n deniedOptions,\n filteredOptions,\n warnings\n };\n }\n\n /**\n * Adds an option to the allowlist.\n */\n public static async addToAllowlistAsync(option: keyof LaunchOptions): Promise<void> {\n const allowlist: ILaunchOptionsAllowlist = await this.readAllowlistAsync();\n\n if (!allowlist.allowedOptions.includes(option)) {\n allowlist.allowedOptions.push(option);\n await this.writeAllowlistAsync(allowlist);\n }\n }\n\n /**\n * Removes an option from the allowlist.\n */\n public static async removeFromAllowlistAsync(option: keyof LaunchOptions): Promise<void> {\n const allowlist: ILaunchOptionsAllowlist = await this.readAllowlistAsync();\n allowlist.allowedOptions = allowlist.allowedOptions.filter((opt) => opt !== option);\n await this.writeAllowlistAsync(allowlist);\n }\n\n /**\n * Clears the entire allowlist.\n */\n public static async clearAllowlistAsync(): Promise<void> {\n await this.writeAllowlistAsync({\n allowedOptions: [],\n version: this._allowlistVersion\n });\n }\n\n /**\n * Gets a human-readable description of the allowlist security model.\n */\n public static getAllowlistDescription(): string {\n return (\n `All launch options are denied by default for security.\\n` +\n `Only options explicitly added to your allowlist will be permitted.\\n\\n` +\n `Allowlist location: ${this.getAllowlistFilePath()}`\n );\n }\n}\n"]}
@@ -0,0 +1,92 @@
1
+ import type { LaunchOptions } from 'playwright-core';
2
+ import semver from 'semver';
3
+ import { type ITerminal } from '@rushstack/terminal';
4
+ /**
5
+ * Allowed Playwright browser names.
6
+ * @beta
7
+ */
8
+ export type BrowserName = 'chromium' | 'firefox' | 'webkit';
9
+ /**
10
+ * Status values reported by {@link PlaywrightTunnel}.
11
+ * @beta
12
+ */
13
+ export type TunnelStatus = 'waiting-for-connection' | 'browser-server-running' | 'stopped' | 'setting-up-browser-server' | 'error';
14
+ /**
15
+ * Handshake data exchanged during the initial WebSocket connection.
16
+ * @beta
17
+ */
18
+ export interface IHandshake {
19
+ action: 'handshake';
20
+ browserName: BrowserName;
21
+ launchOptions: LaunchOptions;
22
+ playwrightVersion: semver.SemVer;
23
+ }
24
+ /**
25
+ * Options for configuring a {@link PlaywrightTunnel} instance.
26
+ * @beta
27
+ */
28
+ export type IPlaywrightTunnelOptions = {
29
+ terminal: ITerminal;
30
+ onStatusChange: (status: TunnelStatus) => void;
31
+ playwrightInstallPath: string;
32
+ /**
33
+ * Optional callback invoked before launching the browser server.
34
+ * Receives the handshake data including launch options.
35
+ * If the callback returns false, the browser server launch will be aborted.
36
+ * This allows the client to prompt the user for approval before starting.
37
+ */
38
+ onBeforeLaunch?: (handshake: IHandshake) => Promise<boolean> | boolean;
39
+ } & ({
40
+ mode: 'poll-connection';
41
+ wsEndpoint: string;
42
+ } | {
43
+ mode: 'wait-for-incoming-connection';
44
+ listenPort: number;
45
+ });
46
+ /**
47
+ * Hosts a Playwright browser server and forwards traffic over a WebSocket tunnel.
48
+ * @beta
49
+ */
50
+ export declare class PlaywrightTunnel {
51
+ private readonly _terminal;
52
+ private readonly _onStatusChange;
53
+ private readonly _onBeforeLaunch?;
54
+ private readonly _playwrightBrowsersInstalled;
55
+ private readonly _wsEndpoint;
56
+ private readonly _listenPort;
57
+ private readonly _playwrightInstallPath;
58
+ private _status;
59
+ private _initWsPromise?;
60
+ private _keepRunning;
61
+ private _ws?;
62
+ private _mode;
63
+ private _pendingConnectionAttempt?;
64
+ private _pollInterval?;
65
+ constructor(options: IPlaywrightTunnelOptions);
66
+ get status(): TunnelStatus;
67
+ private set status(value);
68
+ waitForCloseAsync(): Promise<void>;
69
+ startAsync(options?: {
70
+ keepRunning?: boolean;
71
+ }): Promise<void>;
72
+ stopAsync(): Promise<void>;
73
+ [Symbol.asyncDispose](): Promise<void>;
74
+ cleanTempFilesAsync(): Promise<void>;
75
+ private _runCommandAsync;
76
+ private _installPlaywrightCoreAsync;
77
+ private _installPlaywrightBrowsersAsync;
78
+ private _tryConnectAsync;
79
+ private _pollConnectionAsync;
80
+ private _waitForIncomingConnectionAsync;
81
+ private _setupPlaywrightAsync;
82
+ private _getPlaywrightBrowserServerProxyAsync;
83
+ private _validateHandshake;
84
+ private _setupForwardingAsync;
85
+ /**
86
+ * Initializes the Playwright browser tunnel by establishing a WebSocket connection
87
+ * and setting up the browser server.
88
+ * Returns when the handshake is complete and the browser server is running.
89
+ */
90
+ private _initPlaywrightBrowserTunnelAsync;
91
+ }
92
+ //# sourceMappingURL=PlaywrightBrowserTunnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlaywrightBrowserTunnel.d.ts","sourceRoot":"","sources":["../src/PlaywrightBrowserTunnel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAA8B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEjF,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAoD,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAMvG;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAM5D;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,wBAAwB,GACxB,wBAAwB,GACxB,SAAS,GACT,2BAA2B,GAC3B,OAAO,CAAC;AAEZ;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC;CAClC;AAID;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/C,qBAAqB,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACxE,GAAG,CACA;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,8BAA8B,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB,CACJ,CAAC;AAOF;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiC;IACjE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAwD;IACzF,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAA0B;IACvE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAqB;IAC5C,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,GAAG,CAAC,CAAY;IACxB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,yBAAyB,CAAC,CAAqB;IACvD,OAAO,CAAC,aAAa,CAAC,CAAiB;gBAEpB,OAAO,EAAE,wBAAwB;IA6BpD,IAAW,MAAM,IAAI,YAAY,CAEhC;IAGD,OAAO,KAAK,MAAM,QAGjB;IAEY,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAWlC,UAAU,CAAC,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAclE,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAW1B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;YAcnC,gBAAgB;YA8BhB,2BAA2B;YAU3B,+BAA+B;YAa/B,gBAAgB;YAmBhB,oBAAoB;YAyBpB,+BAA+B;YAwC/B,qBAAqB;YAkBrB,qCAAqC;IA0DnD,OAAO,CAAC,kBAAkB;YAwCZ,qBAAqB;IAoCnC;;;;OAIG;YACW,iCAAiC;CAoGhD"}