playwright-core 1.56.0-alpha-2025-09-09 → 1.56.0-alpha-1757456950000
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/install_webkit_wsl.ps1 +35 -0
- package/lib/server/bidi/bidiChromium.js +1 -1
- package/lib/server/bidi/bidiFirefox.js +1 -1
- package/lib/server/bidi/bidiNetworkManager.js +2 -2
- package/lib/server/browserType.js +3 -3
- package/lib/server/chromium/chromium.js +1 -1
- package/lib/server/firefox/firefox.js +1 -1
- package/lib/server/registry/index.js +27 -0
- package/lib/server/webkit/webkit.js +24 -8
- package/lib/server/webkit/wkBrowser.js +3 -2
- package/lib/server/webkit/wkPage.js +4 -1
- package/lib/server/webkit/wsl/webkit-wsl-transport-client.js +74 -0
- package/lib/server/webkit/wsl/webkit-wsl-transport-server.js +113 -0
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
$ErrorActionPreference = 'Stop'
|
|
2
|
+
|
|
3
|
+
# WebKit WSL Installation Script
|
|
4
|
+
# See webkit-wsl-transport-server.ts for the complete architecture diagram.
|
|
5
|
+
# This script sets up a WSL distribution that will be used to run WebKit.
|
|
6
|
+
|
|
7
|
+
$Distribution = "playwright"
|
|
8
|
+
$Username = "pwuser"
|
|
9
|
+
|
|
10
|
+
$distributions = (wsl --list --quiet) -split "\r?\n"
|
|
11
|
+
if ($distributions -contains $Distribution) {
|
|
12
|
+
Write-Host "WSL distribution '$Distribution' already exists. Skipping installation."
|
|
13
|
+
} else {
|
|
14
|
+
Write-Host "Installing new WSL distribution '$Distribution'..."
|
|
15
|
+
$VhdSize = "10GB"
|
|
16
|
+
wsl --install -d Ubuntu-24.04 --name $Distribution --no-launch --vhd-size $VhdSize
|
|
17
|
+
wsl -d $Distribution -u root adduser --gecos GECOS --disabled-password $Username
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
$pwshDirname = (Resolve-Path -Path $PSScriptRoot).Path;
|
|
21
|
+
$playwrightCoreRoot = Resolve-Path (Join-Path $pwshDirname "..")
|
|
22
|
+
|
|
23
|
+
$initScript = @"
|
|
24
|
+
if [ ! -f "/home/$Username/node/bin/node" ]; then
|
|
25
|
+
mkdir -p /home/$Username/node
|
|
26
|
+
curl -fsSL https://nodejs.org/dist/v22.17.0/node-v22.17.0-linux-x64.tar.xz -o /home/$Username/node/node-v22.17.0-linux-x64.tar.xz
|
|
27
|
+
tar -xJf /home/$Username/node/node-v22.17.0-linux-x64.tar.xz -C /home/$Username/node --strip-components=1
|
|
28
|
+
fi
|
|
29
|
+
/home/$Username/node/bin/node cli.js install-deps webkit
|
|
30
|
+
cp lib/server/webkit/wsl/webkit-wsl-transport-client.js /home/$Username/
|
|
31
|
+
sudo -u $Username PLAYWRIGHT_SKIP_BROWSER_GC=1 /home/$Username/node/bin/node cli.js install webkit
|
|
32
|
+
"@ -replace "\r\n", "`n"
|
|
33
|
+
|
|
34
|
+
wsl -d $Distribution --cd $playwrightCoreRoot -u root -- bash -c "$initScript"
|
|
35
|
+
Write-Host "Done!"
|
|
@@ -86,7 +86,7 @@ class BidiChromium extends import_browserType.BrowserType {
|
|
|
86
86
|
supportsPipeTransport() {
|
|
87
87
|
return false;
|
|
88
88
|
}
|
|
89
|
-
defaultArgs(options, isPersistent, userDataDir) {
|
|
89
|
+
async defaultArgs(options, isPersistent, userDataDir) {
|
|
90
90
|
const chromeArguments = this._innerDefaultArgs(options);
|
|
91
91
|
chromeArguments.push(`--user-data-dir=${userDataDir}`);
|
|
92
92
|
chromeArguments.push("--remote-debugging-port=0");
|
|
@@ -85,7 +85,7 @@ Workaround: Set the HOME=/root environment variable${process.env.GITHUB_ACTION ?
|
|
|
85
85
|
preferences: options.firefoxUserPrefs || {}
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
|
-
defaultArgs(options, isPersistent, userDataDir) {
|
|
88
|
+
async defaultArgs(options, isPersistent, userDataDir) {
|
|
89
89
|
const { args = [], headless } = options;
|
|
90
90
|
const userDataDirArg = args.find((arg) => arg.startsWith("-profile") || arg.startsWith("--profile"));
|
|
91
91
|
if (userDataDirArg)
|
|
@@ -148,7 +148,7 @@ class BidiNetworkManager {
|
|
|
148
148
|
_onAuthRequired(params) {
|
|
149
149
|
const isBasic = params.response.authChallenges?.some((challenge) => challenge.scheme.startsWith("Basic"));
|
|
150
150
|
const credentials = this._page.browserContext._options.httpCredentials;
|
|
151
|
-
if (isBasic && credentials) {
|
|
151
|
+
if (isBasic && credentials && (!credentials.origin || new URL(params.request.url).origin.toLowerCase() === credentials.origin.toLowerCase())) {
|
|
152
152
|
if (this._attemptedAuthentications.has(params.request.request)) {
|
|
153
153
|
this._session.sendMayFail("network.continueWithAuth", {
|
|
154
154
|
request: params.request.request,
|
|
@@ -169,7 +169,7 @@ class BidiNetworkManager {
|
|
|
169
169
|
} else {
|
|
170
170
|
this._session.sendMayFail("network.continueWithAuth", {
|
|
171
171
|
request: params.request.request,
|
|
172
|
-
action: "
|
|
172
|
+
action: "cancel"
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
}
|
|
@@ -169,9 +169,9 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
169
169
|
if (ignoreAllDefaultArgs)
|
|
170
170
|
browserArguments.push(...args);
|
|
171
171
|
else if (ignoreDefaultArgs)
|
|
172
|
-
browserArguments.push(...this.defaultArgs(options, isPersistent, userDataDir).filter((arg) => ignoreDefaultArgs.indexOf(arg) === -1));
|
|
172
|
+
browserArguments.push(...(await this.defaultArgs(options, isPersistent, userDataDir)).filter((arg) => ignoreDefaultArgs.indexOf(arg) === -1));
|
|
173
173
|
else
|
|
174
|
-
browserArguments.push(...this.defaultArgs(options, isPersistent, userDataDir));
|
|
174
|
+
browserArguments.push(...await this.defaultArgs(options, isPersistent, userDataDir));
|
|
175
175
|
let executable;
|
|
176
176
|
if (executablePath) {
|
|
177
177
|
if (!await (0, import_fileUtils.existsAsync)(executablePath))
|
|
@@ -200,7 +200,7 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
200
200
|
const { launchedProcess, gracefullyClose, kill } = await (0, import_processLauncher.launchProcess)({
|
|
201
201
|
command: prepared.executable,
|
|
202
202
|
args: prepared.browserArguments,
|
|
203
|
-
env: this.amendEnvironment(env, prepared.userDataDir, isPersistent),
|
|
203
|
+
env: this.amendEnvironment(env, prepared.userDataDir, isPersistent, options),
|
|
204
204
|
handleSIGINT,
|
|
205
205
|
handleSIGTERM,
|
|
206
206
|
handleSIGHUP,
|
|
@@ -250,7 +250,7 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
250
250
|
throw e;
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
-
defaultArgs(options, isPersistent, userDataDir) {
|
|
253
|
+
async defaultArgs(options, isPersistent, userDataDir) {
|
|
254
254
|
const chromeArguments = this._innerDefaultArgs(options);
|
|
255
255
|
chromeArguments.push(`--user-data-dir=${userDataDir}`);
|
|
256
256
|
if (options.cdpPort !== void 0)
|
|
@@ -67,7 +67,7 @@ Workaround: Set the HOME=/root environment variable${process.env.GITHUB_ACTION ?
|
|
|
67
67
|
const message = { method: "Browser.close", params: {}, id: import_ffConnection.kBrowserCloseMessageId };
|
|
68
68
|
transport.send(message);
|
|
69
69
|
}
|
|
70
|
-
defaultArgs(options, isPersistent, userDataDir) {
|
|
70
|
+
async defaultArgs(options, isPersistent, userDataDir) {
|
|
71
71
|
const { args = [], headless } = options;
|
|
72
72
|
const userDataDirArg = args.find((arg) => arg.startsWith("-profile") || arg.startsWith("--profile"));
|
|
73
73
|
if (userDataDirArg)
|
|
@@ -749,6 +749,33 @@ ${(0, import_ascii.wrapInASCIIBox)(prettyMessage, 1)}`);
|
|
|
749
749
|
_dependencyGroup: "webkit",
|
|
750
750
|
_isHermeticInstallation: true
|
|
751
751
|
});
|
|
752
|
+
this._executables.push({
|
|
753
|
+
type: "channel",
|
|
754
|
+
name: "webkit-wsl",
|
|
755
|
+
browserName: "webkit",
|
|
756
|
+
directory: webkit.dir,
|
|
757
|
+
executablePath: () => process.execPath,
|
|
758
|
+
executablePathOrDie: () => process.execPath,
|
|
759
|
+
wslExecutablePath: `/home/pwuser/.cache/ms-playwright/webkit-${webkit.revision}/pw_run.sh`,
|
|
760
|
+
installType: "download-on-demand",
|
|
761
|
+
_validateHostRequirements: (sdkLanguage) => Promise.resolve(),
|
|
762
|
+
_isHermeticInstallation: true,
|
|
763
|
+
_install: async () => {
|
|
764
|
+
if (process.platform !== "win32")
|
|
765
|
+
throw new Error(`WebKit via WSL is only supported on Windows`);
|
|
766
|
+
const script = import_path.default.join(BIN_PATH, "install_webkit_wsl.ps1");
|
|
767
|
+
const { code } = await (0, import_spawnAsync.spawnAsync)("powershell.exe", [
|
|
768
|
+
"-ExecutionPolicy",
|
|
769
|
+
"Bypass",
|
|
770
|
+
"-File",
|
|
771
|
+
script
|
|
772
|
+
], {
|
|
773
|
+
stdio: "inherit"
|
|
774
|
+
});
|
|
775
|
+
if (code !== 0)
|
|
776
|
+
throw new Error(`Failed to install WebKit via WSL`);
|
|
777
|
+
}
|
|
778
|
+
});
|
|
752
779
|
const ffmpeg = descriptors.find((d) => d.name === "ffmpeg");
|
|
753
780
|
const ffmpegExecutable = findExecutablePath(ffmpeg.dir, "ffmpeg");
|
|
754
781
|
this._executables.push({
|
|
@@ -28,7 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var webkit_exports = {};
|
|
30
30
|
__export(webkit_exports, {
|
|
31
|
-
WebKit: () => WebKit
|
|
31
|
+
WebKit: () => WebKit,
|
|
32
|
+
translatePathToWSL: () => translatePathToWSL
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(webkit_exports);
|
|
34
35
|
var import_path = __toESM(require("path"));
|
|
@@ -36,6 +37,8 @@ var import_wkConnection = require("./wkConnection");
|
|
|
36
37
|
var import_ascii = require("../utils/ascii");
|
|
37
38
|
var import_browserType = require("../browserType");
|
|
38
39
|
var import_wkBrowser = require("../webkit/wkBrowser");
|
|
40
|
+
var import_spawnAsync = require("../utils/spawnAsync");
|
|
41
|
+
var import_registry = require("../registry");
|
|
39
42
|
class WebKit extends import_browserType.BrowserType {
|
|
40
43
|
constructor(parent) {
|
|
41
44
|
super(parent, "webkit");
|
|
@@ -43,10 +46,11 @@ class WebKit extends import_browserType.BrowserType {
|
|
|
43
46
|
connectToTransport(transport, options) {
|
|
44
47
|
return import_wkBrowser.WKBrowser.connect(this.attribution.playwright, transport, options);
|
|
45
48
|
}
|
|
46
|
-
amendEnvironment(env, userDataDir, isPersistent) {
|
|
49
|
+
amendEnvironment(env, userDataDir, isPersistent, options) {
|
|
47
50
|
return {
|
|
48
51
|
...env,
|
|
49
|
-
CURL_COOKIE_JAR_PATH: process.platform === "win32" && isPersistent ? import_path.default.join(userDataDir, "cookiejar.db") : void 0
|
|
52
|
+
CURL_COOKIE_JAR_PATH: process.platform === "win32" && isPersistent ? import_path.default.join(userDataDir, "cookiejar.db") : void 0,
|
|
53
|
+
WEBKIT_EXECUTABLE: options.channel === "webkit-wsl" ? import_registry.registry.findExecutable("webkit-wsl").wslExecutablePath : void 0
|
|
50
54
|
};
|
|
51
55
|
}
|
|
52
56
|
doRewriteStartupLog(error) {
|
|
@@ -59,7 +63,7 @@ class WebKit extends import_browserType.BrowserType {
|
|
|
59
63
|
attemptToGracefullyCloseBrowser(transport) {
|
|
60
64
|
transport.send({ method: "Playwright.close", params: {}, id: import_wkConnection.kBrowserCloseMessageId });
|
|
61
65
|
}
|
|
62
|
-
defaultArgs(options, isPersistent, userDataDir) {
|
|
66
|
+
async defaultArgs(options, isPersistent, userDataDir) {
|
|
63
67
|
const { args = [], headless } = options;
|
|
64
68
|
const userDataDirArg = args.find((arg) => arg.startsWith("--user-data-dir"));
|
|
65
69
|
if (userDataDirArg)
|
|
@@ -67,12 +71,19 @@ class WebKit extends import_browserType.BrowserType {
|
|
|
67
71
|
if (args.find((arg) => !arg.startsWith("-")))
|
|
68
72
|
throw new Error("Arguments can not specify page to be opened");
|
|
69
73
|
const webkitArguments = ["--inspector-pipe"];
|
|
70
|
-
if (
|
|
74
|
+
if (options.channel === "webkit-wsl") {
|
|
75
|
+
if (options.executablePath)
|
|
76
|
+
throw new Error('Cannot specify executablePath when using the "webkit-wsl" channel.');
|
|
77
|
+
webkitArguments.unshift(
|
|
78
|
+
import_path.default.join(__dirname, "wsl/webkit-wsl-transport-server.js")
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (process.platform === "win32" && options.channel !== "webkit-wsl")
|
|
71
82
|
webkitArguments.push("--disable-accelerated-compositing");
|
|
72
83
|
if (headless)
|
|
73
84
|
webkitArguments.push("--headless");
|
|
74
85
|
if (isPersistent)
|
|
75
|
-
webkitArguments.push(`--user-data-dir=${userDataDir}`);
|
|
86
|
+
webkitArguments.push(`--user-data-dir=${options.channel === "webkit-wsl" ? await translatePathToWSL(userDataDir) : userDataDir}`);
|
|
76
87
|
else
|
|
77
88
|
webkitArguments.push(`--no-startup-window`);
|
|
78
89
|
const proxy = options.proxyOverride || options.proxy;
|
|
@@ -81,7 +92,7 @@ class WebKit extends import_browserType.BrowserType {
|
|
|
81
92
|
webkitArguments.push(`--proxy=${proxy.server}`);
|
|
82
93
|
if (proxy.bypass)
|
|
83
94
|
webkitArguments.push(`--proxy-bypass-list=${proxy.bypass}`);
|
|
84
|
-
} else if (process.platform === "linux") {
|
|
95
|
+
} else if (process.platform === "linux" || process.platform === "win32" && options.channel === "webkit-wsl") {
|
|
85
96
|
webkitArguments.push(`--proxy=${proxy.server}`);
|
|
86
97
|
if (proxy.bypass)
|
|
87
98
|
webkitArguments.push(...proxy.bypass.split(",").map((t) => `--ignore-host=${t}`));
|
|
@@ -97,7 +108,12 @@ class WebKit extends import_browserType.BrowserType {
|
|
|
97
108
|
return webkitArguments;
|
|
98
109
|
}
|
|
99
110
|
}
|
|
111
|
+
async function translatePathToWSL(path2) {
|
|
112
|
+
const { stdout } = await (0, import_spawnAsync.spawnAsync)("wsl.exe", ["-d", "playwright", "--cd", "/home/pwuser", "wslpath", path2.replace(/\\/g, "\\\\")]);
|
|
113
|
+
return stdout.toString().trim();
|
|
114
|
+
}
|
|
100
115
|
// Annotate the CommonJS export names for ESM import in node:
|
|
101
116
|
0 && (module.exports = {
|
|
102
|
-
WebKit
|
|
117
|
+
WebKit,
|
|
118
|
+
translatePathToWSL
|
|
103
119
|
});
|
|
@@ -39,6 +39,7 @@ var network = __toESM(require("../network"));
|
|
|
39
39
|
var import_wkConnection = require("./wkConnection");
|
|
40
40
|
var import_wkPage = require("./wkPage");
|
|
41
41
|
var import_errors = require("../errors");
|
|
42
|
+
var import_webkit = require("./webkit");
|
|
42
43
|
const BROWSER_VERSION = "26.0";
|
|
43
44
|
const DEFAULT_USER_AGENT = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/${BROWSER_VERSION} Safari/605.1.15`;
|
|
44
45
|
class WKBrowser extends import_browser.Browser {
|
|
@@ -87,7 +88,7 @@ class WKBrowser extends import_browser.Browser {
|
|
|
87
88
|
const createOptions = proxy ? {
|
|
88
89
|
// Enable socks5 hostname resolution on Windows.
|
|
89
90
|
// See https://github.com/microsoft/playwright/issues/20451
|
|
90
|
-
proxyServer: process.platform === "win32" ? proxy.server.replace(/^socks5:\/\//, "socks5h://") : proxy.server,
|
|
91
|
+
proxyServer: process.platform === "win32" && this.attribution.browser?.options.channel !== "webkit-wsl" ? proxy.server.replace(/^socks5:\/\//, "socks5h://") : proxy.server,
|
|
91
92
|
proxyBypassList: proxy.bypass
|
|
92
93
|
} : void 0;
|
|
93
94
|
const { browserContextId } = await this._browserSession.send("Playwright.createContext", createOptions);
|
|
@@ -192,7 +193,7 @@ class WKBrowserContext extends import_browserContext.BrowserContext {
|
|
|
192
193
|
const promises = [super._initialize()];
|
|
193
194
|
promises.push(this._browser._browserSession.send("Playwright.setDownloadBehavior", {
|
|
194
195
|
behavior: this._options.acceptDownloads === "accept" ? "allow" : "deny",
|
|
195
|
-
downloadPath: this._browser.options.downloadsPath,
|
|
196
|
+
downloadPath: this._browser.options.channel === "webkit-wsl" ? await (0, import_webkit.translatePathToWSL)(this._browser.options.downloadsPath) : this._browser.options.downloadsPath,
|
|
196
197
|
browserContextId
|
|
197
198
|
}));
|
|
198
199
|
if (this._options.ignoreHTTPSErrors || this._options.internalIgnoreHTTPSErrors)
|
|
@@ -54,6 +54,7 @@ var import_wkInterceptableRequest = require("./wkInterceptableRequest");
|
|
|
54
54
|
var import_wkProvisionalPage = require("./wkProvisionalPage");
|
|
55
55
|
var import_wkWorkers = require("./wkWorkers");
|
|
56
56
|
var import_debugLogger = require("../utils/debugLogger");
|
|
57
|
+
var import_webkit = require("./webkit");
|
|
57
58
|
const UTILITY_WORLD_NAME = "__playwright_utility_world__";
|
|
58
59
|
class WKPage {
|
|
59
60
|
constructor(browserContext, pageProxySession, opener) {
|
|
@@ -769,7 +770,7 @@ class WKPage {
|
|
|
769
770
|
async _startVideo(options) {
|
|
770
771
|
(0, import_utils.assert)(!this._recordingVideoFile);
|
|
771
772
|
const { screencastId } = await this._pageProxySession.send("Screencast.startVideo", {
|
|
772
|
-
file: options.outputFile,
|
|
773
|
+
file: this._browserContext._browser.options.channel === "webkit-wsl" ? await (0, import_webkit.translatePathToWSL)(options.outputFile) : options.outputFile,
|
|
773
774
|
width: options.width,
|
|
774
775
|
height: options.height,
|
|
775
776
|
toolbarHeight: this._toolbarHeight()
|
|
@@ -889,6 +890,8 @@ class WKPage {
|
|
|
889
890
|
async setInputFilePaths(handle, paths) {
|
|
890
891
|
const pageProxyId = this._pageProxySession.sessionId;
|
|
891
892
|
const objectId = handle._objectId;
|
|
893
|
+
if (this._browserContext._browser?.options.channel === "webkit-wsl")
|
|
894
|
+
paths = await Promise.all(paths.map((path2) => (0, import_webkit.translatePathToWSL)(path2)));
|
|
892
895
|
await Promise.all([
|
|
893
896
|
this._pageProxySession.connection.browserSession.send("Playwright.grantFileReadAccess", { pageProxyId, paths }),
|
|
894
897
|
this._session.send("DOM.setInputFiles", { objectId, paths })
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_net = __toESM(require("net"));
|
|
25
|
+
var import_fs = __toESM(require("fs"));
|
|
26
|
+
var import_child_process = require("child_process");
|
|
27
|
+
(async () => {
|
|
28
|
+
const { PW_WSL_BRIDGE_PORT: socketPort, ...childEnv } = process.env;
|
|
29
|
+
if (!socketPort)
|
|
30
|
+
throw new Error("PW_WSL_BRIDGE_PORT env var is not set");
|
|
31
|
+
const [executable, ...args] = process.argv.slice(2);
|
|
32
|
+
if (!(await import_fs.default.promises.stat(executable)).isFile())
|
|
33
|
+
throw new Error(`Executable does not exist. Did you update Playwright recently? Make sure to run npx playwright install webkit-wsl`);
|
|
34
|
+
const address = (() => {
|
|
35
|
+
const res = (0, import_child_process.spawnSync)("/usr/bin/wslinfo", ["--networking-mode"], { encoding: "utf8" });
|
|
36
|
+
if (res.error || res.status !== 0)
|
|
37
|
+
throw new Error(`Failed to run /usr/bin/wslinfo --networking-mode: ${res.error?.message || res.stderr || res.status}`);
|
|
38
|
+
if (res.stdout.trim() === "nat") {
|
|
39
|
+
const ipRes = (0, import_child_process.spawnSync)("/usr/sbin/ip", ["route", "show"], { encoding: "utf8" });
|
|
40
|
+
if (ipRes.error || ipRes.status !== 0)
|
|
41
|
+
throw new Error(`Failed to run ip route show: ${ipRes.error?.message || ipRes.stderr || ipRes.status}`);
|
|
42
|
+
const ip = ipRes.stdout.trim().split("\n").find((line) => line.includes("default"))?.split(" ")[2];
|
|
43
|
+
if (!ip)
|
|
44
|
+
throw new Error("Could not determine WSL IP address (NAT mode).");
|
|
45
|
+
return ip;
|
|
46
|
+
}
|
|
47
|
+
return "127.0.0.1";
|
|
48
|
+
})();
|
|
49
|
+
const socket = import_net.default.createConnection(parseInt(socketPort, 10), address);
|
|
50
|
+
socket.setNoDelay(true);
|
|
51
|
+
await new Promise((resolve, reject) => {
|
|
52
|
+
socket.on("connect", resolve);
|
|
53
|
+
socket.on("error", reject);
|
|
54
|
+
});
|
|
55
|
+
const child = (0, import_child_process.spawn)(executable, args, {
|
|
56
|
+
stdio: ["inherit", "inherit", "inherit", "pipe", "pipe"],
|
|
57
|
+
env: childEnv
|
|
58
|
+
});
|
|
59
|
+
const [childOutput, childInput] = [child.stdio[3], child.stdio[4]];
|
|
60
|
+
socket.pipe(childOutput);
|
|
61
|
+
childInput.pipe(socket);
|
|
62
|
+
socket.on("end", () => child.kill());
|
|
63
|
+
child.on("exit", (exitCode) => {
|
|
64
|
+
socket.end();
|
|
65
|
+
process.exit(exitCode || 0);
|
|
66
|
+
});
|
|
67
|
+
await new Promise((resolve, reject) => {
|
|
68
|
+
child.on("exit", resolve);
|
|
69
|
+
child.on("error", reject);
|
|
70
|
+
});
|
|
71
|
+
})().catch((error) => {
|
|
72
|
+
console.error("Error occurred:", error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (let key of __getOwnPropNames(from))
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
12
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
13
|
+
}
|
|
14
|
+
return to;
|
|
15
|
+
};
|
|
16
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
17
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
18
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
19
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
20
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var import_net = __toESM(require("net"));
|
|
25
|
+
var import_path = __toESM(require("path"));
|
|
26
|
+
var import_child_process = require("child_process");
|
|
27
|
+
(async () => {
|
|
28
|
+
const argv = process.argv.slice(2);
|
|
29
|
+
if (!argv.length) {
|
|
30
|
+
console.error(`Usage: node ${import_path.default.basename(__filename)} <executable> [args...]`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const parentIn = new import_net.default.Socket({ fd: 3, readable: true, writable: false });
|
|
34
|
+
const parentOut = new import_net.default.Socket({ fd: 4, readable: false, writable: true });
|
|
35
|
+
const server = import_net.default.createServer();
|
|
36
|
+
let socket = null;
|
|
37
|
+
server.on("connection", (s) => {
|
|
38
|
+
if (socket) {
|
|
39
|
+
log("Extra connection received, destroying.");
|
|
40
|
+
socket.destroy();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
socket = s;
|
|
44
|
+
socket.setNoDelay(true);
|
|
45
|
+
log("Client connected, wiring pipes.");
|
|
46
|
+
socket.pipe(parentOut);
|
|
47
|
+
parentIn.pipe(socket);
|
|
48
|
+
socket.on("close", () => {
|
|
49
|
+
log("Socket closed");
|
|
50
|
+
socket = null;
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
await new Promise((resolve, reject) => {
|
|
54
|
+
server.once("error", reject);
|
|
55
|
+
server.listen(0, () => resolve(null));
|
|
56
|
+
});
|
|
57
|
+
const address = server.address();
|
|
58
|
+
if (!address || typeof address === "string") {
|
|
59
|
+
console.error("Failed to obtain listening address");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const port = address.port;
|
|
63
|
+
log("Server listening on", port);
|
|
64
|
+
const env = {
|
|
65
|
+
...process.env,
|
|
66
|
+
// WSLENV is a colon-delimited list of environment variables that should be included when launching WSL processes from Win32 or Win32 processes from WSL
|
|
67
|
+
WSLENV: "PW_WSL_BRIDGE_PORT",
|
|
68
|
+
PW_WSL_BRIDGE_PORT: String(port)
|
|
69
|
+
};
|
|
70
|
+
let shuttingDown = false;
|
|
71
|
+
const child = (0, import_child_process.spawn)("wsl.exe", [
|
|
72
|
+
"-d",
|
|
73
|
+
"playwright",
|
|
74
|
+
"--cd",
|
|
75
|
+
"/home/pwuser",
|
|
76
|
+
"/home/pwuser/node/bin/node",
|
|
77
|
+
"/home/pwuser/webkit-wsl-transport-client.js",
|
|
78
|
+
process.env.WEBKIT_EXECUTABLE || "",
|
|
79
|
+
...argv
|
|
80
|
+
], {
|
|
81
|
+
env,
|
|
82
|
+
stdio: ["inherit", "inherit", "inherit"]
|
|
83
|
+
// no fd3/fd4 here; they stay only in this wrapper
|
|
84
|
+
});
|
|
85
|
+
log("Spawned child pid", child.pid);
|
|
86
|
+
child.on("close", (code, signal) => {
|
|
87
|
+
log("Child exit", { code, signal });
|
|
88
|
+
const exitCode = code ?? (signal ? 128 : 0);
|
|
89
|
+
shutdown(exitCode);
|
|
90
|
+
});
|
|
91
|
+
child.on("error", (err) => {
|
|
92
|
+
console.error("Child process failed to start:", err);
|
|
93
|
+
shutdown(1);
|
|
94
|
+
});
|
|
95
|
+
await new Promise((resolve) => child.once("close", resolve));
|
|
96
|
+
async function shutdown(code = 0) {
|
|
97
|
+
if (shuttingDown)
|
|
98
|
+
return;
|
|
99
|
+
shuttingDown = true;
|
|
100
|
+
server.close();
|
|
101
|
+
parentIn.destroy();
|
|
102
|
+
parentOut.destroy();
|
|
103
|
+
socket?.destroy();
|
|
104
|
+
await new Promise((resolve) => server.once("close", resolve));
|
|
105
|
+
process.exit(code);
|
|
106
|
+
}
|
|
107
|
+
function log(...args) {
|
|
108
|
+
console.error(/* @__PURE__ */ new Date(), `[${import_path.default.basename(__filename)}]`, ...args);
|
|
109
|
+
}
|
|
110
|
+
})().catch((error) => {
|
|
111
|
+
console.error("Error occurred:", error);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
});
|