patchright-core 1.56.1 → 1.58.2
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/ThirdPartyNotices.txt +3134 -560
- package/bin/install_webkit_wsl.ps1 +1 -3
- package/browsers.json +21 -22
- package/lib/cli/program.js +16 -60
- package/lib/client/api.js +3 -3
- package/lib/client/browser.js +3 -5
- package/lib/client/browserContext.js +62 -8
- package/lib/client/browserType.js +4 -3
- package/lib/client/connection.js +4 -0
- package/lib/client/consoleMessage.js +5 -1
- package/lib/client/electron.js +1 -1
- package/lib/client/elementHandle.js +3 -0
- package/lib/client/events.js +5 -1
- package/lib/client/fetch.js +3 -4
- package/lib/client/frame.js +10 -1
- package/lib/client/locator.js +12 -1
- package/lib/client/network.js +5 -1
- package/lib/client/page.js +31 -6
- package/lib/client/pageAgent.js +64 -0
- package/lib/client/platform.js +3 -0
- package/lib/client/playwright.js +1 -5
- package/lib/client/tracing.js +7 -5
- package/lib/client/worker.js +22 -0
- package/lib/generated/clockSource.js +1 -1
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- package/lib/inProcessFactory.js +0 -2
- package/lib/mcpBundle.js +84 -0
- package/lib/mcpBundleImpl/index.js +147 -0
- package/lib/protocol/serializers.js +5 -0
- package/lib/protocol/validator.js +112 -50
- package/lib/remote/playwrightServer.js +1 -2
- package/lib/server/agent/actionRunner.js +335 -0
- package/lib/server/agent/actions.js +128 -0
- package/lib/server/agent/codegen.js +111 -0
- package/lib/server/agent/context.js +150 -0
- package/lib/server/agent/expectTools.js +156 -0
- package/lib/server/agent/pageAgent.js +204 -0
- package/lib/server/agent/performTools.js +262 -0
- package/lib/server/agent/tool.js +109 -0
- package/lib/server/android/android.js +1 -1
- package/lib/server/artifact.js +1 -1
- package/lib/server/bidi/bidiBrowser.js +81 -22
- package/lib/server/bidi/bidiChromium.js +9 -13
- package/lib/server/bidi/bidiConnection.js +1 -0
- package/lib/server/bidi/bidiDeserializer.js +116 -0
- package/lib/server/bidi/bidiExecutionContext.js +75 -29
- package/lib/server/bidi/bidiFirefox.js +7 -9
- package/lib/server/bidi/bidiNetworkManager.js +1 -1
- package/lib/server/bidi/bidiPage.js +61 -30
- package/lib/server/bidi/third_party/bidiProtocolCore.js +1 -0
- package/lib/server/browserContext.js +43 -36
- package/lib/server/browserType.js +12 -4
- package/lib/server/chromium/chromium.js +26 -21
- package/lib/server/chromium/chromiumSwitches.js +12 -3
- package/lib/server/chromium/crBrowser.js +30 -12
- package/lib/server/chromium/crConnection.js +0 -5
- package/lib/server/chromium/crCoverage.js +13 -1
- package/lib/server/chromium/crDevTools.js +0 -2
- package/lib/server/chromium/crNetworkManager.js +107 -18
- package/lib/server/chromium/crPage.js +68 -124
- package/lib/server/chromium/crServiceWorker.js +14 -1
- package/lib/server/codegen/javascript.js +6 -29
- package/lib/server/console.js +5 -1
- package/lib/server/deviceDescriptorsSource.json +56 -56
- package/lib/server/dispatchers/browserContextDispatcher.js +26 -8
- package/lib/server/dispatchers/dispatcher.js +6 -13
- package/lib/server/dispatchers/frameDispatcher.js +1 -1
- package/lib/server/dispatchers/jsHandleDispatcher.js +2 -2
- package/lib/server/dispatchers/pageAgentDispatcher.js +96 -0
- package/lib/server/dispatchers/pageDispatcher.js +14 -22
- package/lib/server/dispatchers/playwrightDispatcher.js +0 -4
- package/lib/server/dom.js +12 -3
- package/lib/server/electron/electron.js +6 -3
- package/lib/server/firefox/ffBrowser.js +10 -20
- package/lib/server/firefox/ffConnection.js +0 -5
- package/lib/server/firefox/ffNetworkManager.js +2 -2
- package/lib/server/firefox/ffPage.js +18 -24
- package/lib/server/firefox/firefox.js +18 -9
- package/lib/server/frameSelectors.js +18 -8
- package/lib/server/frames.js +257 -87
- package/lib/server/input.js +7 -3
- package/lib/server/instrumentation.js +3 -0
- package/lib/server/javascript.js +8 -4
- package/lib/server/launchApp.js +2 -1
- package/lib/server/localUtils.js +4 -8
- package/lib/server/network.js +50 -12
- package/lib/server/page.js +112 -126
- package/lib/server/playwright.js +2 -4
- package/lib/server/progress.js +26 -6
- package/lib/server/recorder/recorderApp.js +80 -101
- package/lib/server/recorder.js +3 -2
- package/lib/server/registry/browserFetcher.js +6 -4
- package/lib/server/registry/index.js +278 -189
- package/lib/server/registry/oopDownloadBrowserMain.js +9 -2
- package/lib/server/screencast.js +190 -0
- package/lib/server/screenshotter.js +6 -0
- package/lib/server/socksClientCertificatesInterceptor.js +1 -1
- package/lib/server/trace/recorder/snapshotter.js +17 -8
- package/lib/server/trace/recorder/snapshotterInjected.js +30 -72
- package/lib/server/trace/recorder/tracing.js +31 -21
- package/lib/server/trace/viewer/traceParser.js +72 -0
- package/lib/server/trace/viewer/traceViewer.js +45 -40
- package/lib/server/utils/comparators.js +3 -25
- package/lib/server/utils/expectUtils.js +87 -2
- package/lib/server/utils/hostPlatform.js +30 -3
- package/lib/server/utils/httpServer.js +5 -20
- package/lib/server/utils/imageUtils.js +141 -0
- package/lib/server/utils/network.js +55 -40
- package/lib/server/utils/nodePlatform.js +6 -0
- package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +35 -24
- package/lib/server/webkit/webkit.js +5 -16
- package/lib/server/webkit/wkBrowser.js +2 -6
- package/lib/server/webkit/wkConnection.js +1 -6
- package/lib/server/webkit/wkInterceptableRequest.js +29 -1
- package/lib/server/webkit/wkPage.js +76 -51
- package/lib/server/webkit/wkWorkers.js +2 -1
- package/lib/utils/isomorphic/ariaSnapshot.js +63 -0
- package/lib/utils/isomorphic/locatorGenerators.js +24 -8
- package/lib/utils/isomorphic/lruCache.js +51 -0
- package/lib/utils/isomorphic/mimeType.js +1 -1
- package/lib/utils/isomorphic/protocolFormatter.js +3 -0
- package/lib/utils/isomorphic/protocolMetainfo.js +11 -2
- package/lib/utils/isomorphic/stringUtils.js +49 -0
- package/lib/utils/isomorphic/trace/entries.js +16 -0
- package/lib/utils/isomorphic/trace/snapshotRenderer.js +499 -0
- package/lib/utils/isomorphic/trace/snapshotServer.js +120 -0
- package/lib/utils/isomorphic/trace/snapshotStorage.js +89 -0
- package/lib/utils/isomorphic/trace/traceLoader.js +131 -0
- package/lib/utils/isomorphic/trace/traceModel.js +365 -0
- package/lib/utils/isomorphic/trace/traceModernizer.js +400 -0
- package/lib/utils/isomorphic/trace/versions/traceV3.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV4.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV5.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV6.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV7.js +16 -0
- package/lib/utils/isomorphic/trace/versions/traceV8.js +16 -0
- package/lib/utils/isomorphic/urlMatch.js +19 -5
- package/lib/utils/isomorphic/yaml.js +84 -0
- package/lib/utils.js +4 -0
- package/lib/utilsBundle.js +1 -1
- package/lib/utilsBundleImpl/index.js +124 -124
- package/lib/vite/htmlReport/index.html +21 -21
- package/lib/vite/recorder/assets/codeMirrorModule-CFUTFUO7.js +32 -0
- package/lib/vite/recorder/assets/{codeMirrorModule-C3UTv-Ge.css → codeMirrorModule-DYBRYzYX.css} +1 -1
- package/lib/vite/recorder/assets/{index-Ri0uHF7I.css → index-BSjZa4pk.css} +1 -1
- package/lib/vite/recorder/assets/index-CVkBxsGf.js +193 -0
- package/lib/vite/recorder/index.html +2 -2
- package/lib/vite/traceViewer/assets/codeMirrorModule-BVA4h_ZY.js +32 -0
- package/lib/vite/traceViewer/assets/defaultSettingsView-CjfmcdOz.js +266 -0
- package/lib/vite/traceViewer/{codeMirrorModule.C3UTv-Ge.css → codeMirrorModule.DYBRYzYX.css} +1 -1
- package/lib/vite/traceViewer/defaultSettingsView.7ch9cixO.css +1 -0
- package/lib/vite/traceViewer/index.BVu7tZDe.css +1 -0
- package/lib/vite/traceViewer/index.BtyWtaE-.js +2 -0
- package/lib/vite/traceViewer/index.html +6 -6
- package/lib/vite/traceViewer/manifest.webmanifest +16 -0
- package/lib/vite/traceViewer/snapshot.html +3 -3
- package/lib/vite/traceViewer/sw.bundle.js +5 -3
- package/lib/vite/traceViewer/uiMode.fyrXARf2.js +5 -0
- package/lib/vite/traceViewer/uiMode.html +3 -3
- package/package.json +2 -1
- package/types/protocol.d.ts +939 -245
- package/types/types.d.ts +143 -153
- package/lib/client/accessibility.js +0 -49
- package/lib/server/accessibility.js +0 -69
- package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
- package/lib/server/chromium/crAccessibility.js +0 -263
- package/lib/server/firefox/ffAccessibility.js +0 -238
- package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
- package/lib/server/webkit/wkAccessibility.js +0 -237
- package/lib/server/webkit/wsl/webkit-wsl-transport-client.js +0 -74
- package/lib/server/webkit/wsl/webkit-wsl-transport-server.js +0 -113
- package/lib/vite/recorder/assets/codeMirrorModule-RJCXzfmE.js +0 -24
- package/lib/vite/recorder/assets/index-Y-X2TGJv.js +0 -193
- package/lib/vite/traceViewer/assets/codeMirrorModule-rbQPefq7.js +0 -24
- package/lib/vite/traceViewer/assets/defaultSettingsView-CLbol9XR.js +0 -265
- package/lib/vite/traceViewer/defaultSettingsView.TQ8_7ybu.css +0 -1
- package/lib/vite/traceViewer/index.I8N9v4jT.css +0 -1
- package/lib/vite/traceViewer/index.zIVi6mN9.js +0 -2
- package/lib/vite/traceViewer/uiMode.B_CpmIpF.js +0 -5
|
@@ -250,6 +250,13 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
250
250
|
this.waitForReadyState(options, browserLogsCollector),
|
|
251
251
|
exitPromise.then(() => ({ wsEndpoint: void 0 }))
|
|
252
252
|
]);
|
|
253
|
+
if (exitPromise.isDone()) {
|
|
254
|
+
const log = import_helper.helper.formatBrowserLogs(browserLogsCollector.recentLogs());
|
|
255
|
+
const updatedLog = this.doRewriteStartupLog(log);
|
|
256
|
+
throw new Error(`Failed to launch the browser process.
|
|
257
|
+
Browser logs:
|
|
258
|
+
${updatedLog}`);
|
|
259
|
+
}
|
|
253
260
|
if (options.cdpPort !== void 0 || !this.supportsPipeTransport()) {
|
|
254
261
|
transport = await import_transport.WebSocketTransport.connect(progress, wsEndpoint);
|
|
255
262
|
} else {
|
|
@@ -276,15 +283,14 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
276
283
|
throw new Error("Connecting to SELENIUM_REMOTE_URL is only supported by Chromium");
|
|
277
284
|
}
|
|
278
285
|
_validateLaunchOptions(options) {
|
|
279
|
-
|
|
280
|
-
let { headless = !devtools, downloadsPath, proxy } = options;
|
|
286
|
+
let { headless = true, downloadsPath, proxy } = options;
|
|
281
287
|
if ((0, import_debug.debugMode)() === "inspector")
|
|
282
288
|
headless = false;
|
|
283
289
|
if (downloadsPath && !import_path.default.isAbsolute(downloadsPath))
|
|
284
290
|
downloadsPath = import_path.default.join(process.cwd(), downloadsPath);
|
|
285
291
|
if (options.socksProxyPort)
|
|
286
292
|
proxy = { server: `socks5://127.0.0.1:${options.socksProxyPort}` };
|
|
287
|
-
return { ...options,
|
|
293
|
+
return { ...options, headless, downloadsPath, proxy };
|
|
288
294
|
}
|
|
289
295
|
_createUserDataDirArgMisuseError(userDataDirArg) {
|
|
290
296
|
switch (this.attribution.playwright.options.sdkLanguage) {
|
|
@@ -301,7 +307,9 @@ class BrowserType extends import_instrumentation.SdkObject {
|
|
|
301
307
|
_rewriteStartupLog(error) {
|
|
302
308
|
if (!(0, import_protocolError.isProtocolError)(error))
|
|
303
309
|
return error;
|
|
304
|
-
|
|
310
|
+
if (error.logs)
|
|
311
|
+
error.logs = this.doRewriteStartupLog(error.logs);
|
|
312
|
+
return error;
|
|
305
313
|
}
|
|
306
314
|
async waitForReadyState(options, browserLogsCollector) {
|
|
307
315
|
return {};
|
|
@@ -55,11 +55,22 @@ var import_fileUtils = require("../utils/fileUtils");
|
|
|
55
55
|
var import_processLauncher = require("../utils/processLauncher");
|
|
56
56
|
const ARTIFACTS_FOLDER = import_path.default.join(import_os.default.tmpdir(), "playwright-artifacts-");
|
|
57
57
|
class Chromium extends import_browserType.BrowserType {
|
|
58
|
-
constructor(parent) {
|
|
58
|
+
constructor(parent, bidiChromium) {
|
|
59
59
|
super(parent, "chromium");
|
|
60
|
+
this._bidiChromium = bidiChromium;
|
|
60
61
|
if ((0, import_utils.debugMode)() === "inspector")
|
|
61
62
|
this._devtools = this._createDevTools();
|
|
62
63
|
}
|
|
64
|
+
launch(progress, options, protocolLogger) {
|
|
65
|
+
if (options.channel?.startsWith("bidi-"))
|
|
66
|
+
return this._bidiChromium.launch(progress, options, protocolLogger);
|
|
67
|
+
return super.launch(progress, options, protocolLogger);
|
|
68
|
+
}
|
|
69
|
+
async launchPersistentContext(progress, userDataDir, options) {
|
|
70
|
+
if (options.channel?.startsWith("bidi-"))
|
|
71
|
+
return this._bidiChromium.launchPersistentContext(progress, userDataDir, options);
|
|
72
|
+
return super.launchPersistentContext(progress, userDataDir, options);
|
|
73
|
+
}
|
|
63
74
|
async connectOverCDP(progress, endpointURL, options) {
|
|
64
75
|
return await this._connectOverCDPInternal(progress, endpointURL, options);
|
|
65
76
|
}
|
|
@@ -103,7 +114,8 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
103
114
|
};
|
|
104
115
|
(0, import_browserContext.validateBrowserContextOptions)(persistent, browserOptions);
|
|
105
116
|
const browser = await progress.race(import_crBrowser.CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions));
|
|
106
|
-
|
|
117
|
+
if (!options.isLocal)
|
|
118
|
+
browser._isCollocatedWithServer = false;
|
|
107
119
|
browser.on(import_browser.Browser.Events.Disconnected, doCleanup);
|
|
108
120
|
return browser;
|
|
109
121
|
} catch (error) {
|
|
@@ -117,13 +129,8 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
117
129
|
return directory ? new import_crDevTools.CRDevTools(import_path.default.join(directory, "devtools-preferences.json")) : void 0;
|
|
118
130
|
}
|
|
119
131
|
async connectToTransport(transport, options, browserLogsCollector) {
|
|
120
|
-
let devtools = this._devtools;
|
|
121
|
-
if (options.__testHookForDevTools) {
|
|
122
|
-
devtools = this._createDevTools();
|
|
123
|
-
await options.__testHookForDevTools(devtools);
|
|
124
|
-
}
|
|
125
132
|
try {
|
|
126
|
-
return await import_crBrowser.CRBrowser.connect(this.attribution.playwright, transport, options,
|
|
133
|
+
return await import_crBrowser.CRBrowser.connect(this.attribution.playwright, transport, options, this._devtools);
|
|
127
134
|
} catch (e) {
|
|
128
135
|
if (browserLogsCollector.recentLogs().some((log) => log.includes("Failed to create a ProcessSingleton for your profile directory."))) {
|
|
129
136
|
throw new Error(
|
|
@@ -133,14 +140,12 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
133
140
|
throw e;
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
|
-
doRewriteStartupLog(
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return error;
|
|
143
|
-
error.logs = [
|
|
143
|
+
doRewriteStartupLog(logs) {
|
|
144
|
+
if (logs.includes("Missing X server"))
|
|
145
|
+
logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
|
|
146
|
+
if (!logs.includes("crbug.com/357670") && !logs.includes("No usable sandbox!") && !logs.includes("crbug.com/638180"))
|
|
147
|
+
return logs;
|
|
148
|
+
return [
|
|
144
149
|
`Chromium sandboxing failed!`,
|
|
145
150
|
`================================`,
|
|
146
151
|
`To avoid the sandboxing issue, do either of the following:`,
|
|
@@ -149,7 +154,6 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
149
154
|
`================================`,
|
|
150
155
|
``
|
|
151
156
|
].join("\n");
|
|
152
|
-
return error;
|
|
153
157
|
}
|
|
154
158
|
amendEnvironment(env) {
|
|
155
159
|
return env;
|
|
@@ -273,11 +277,8 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
273
277
|
if (args.find((arg) => !arg.startsWith("-")))
|
|
274
278
|
throw new Error("Arguments can not specify page to be opened");
|
|
275
279
|
const chromeArguments = [...(0, import_chromiumSwitches.chromiumSwitches)(options.assistantMode, options.channel)];
|
|
276
|
-
if (import_os.default.platform()
|
|
277
|
-
chromeArguments.push("--enable-unsafe-swiftshader");
|
|
280
|
+
if (import_os.default.platform() !== "darwin" || !(0, import_utils.hasGpuMac)()) {
|
|
278
281
|
}
|
|
279
|
-
if (options.devtools)
|
|
280
|
-
chromeArguments.push("--auto-open-devtools-for-tabs");
|
|
281
282
|
if (options.headless) {
|
|
282
283
|
chromeArguments.push("--headless");
|
|
283
284
|
chromeArguments.push(
|
|
@@ -313,6 +314,10 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
313
314
|
return waitForReadyState(options, browserLogsCollector);
|
|
314
315
|
}
|
|
315
316
|
getExecutableName(options) {
|
|
317
|
+
if (options.channel && import_registry.registry.isChromiumAlias(options.channel))
|
|
318
|
+
return "chromium";
|
|
319
|
+
if (options.channel === "chromium-tip-of-tree")
|
|
320
|
+
return options.headless ? "chromium-tip-of-tree-headless-shell" : "chromium-tip-of-tree";
|
|
316
321
|
if (options.channel)
|
|
317
322
|
return options.channel;
|
|
318
323
|
return options.headless ? "chromium-headless-shell" : "chromium";
|
|
@@ -22,10 +22,10 @@ __export(chromiumSwitches_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(chromiumSwitches_exports);
|
|
24
24
|
const disabledFeatures = (assistantMode) => [
|
|
25
|
-
// See https://github.com/microsoft/playwright/pull/10380
|
|
26
|
-
"AcceptCHFrame",
|
|
27
25
|
// See https://github.com/microsoft/playwright/issues/14047
|
|
28
26
|
"AvoidUnnecessaryBeforeUnloadCheckSync",
|
|
27
|
+
// See https://github.com/microsoft/playwright/issues/38568
|
|
28
|
+
"BoundaryEventDispatchTracksNodeRemoval",
|
|
29
29
|
"DestroyProfileOnBrowserClose",
|
|
30
30
|
// See https://github.com/microsoft/playwright/pull/13854
|
|
31
31
|
"DialMediaRouteProvider",
|
|
@@ -46,9 +46,11 @@ const disabledFeatures = (assistantMode) => [
|
|
|
46
46
|
"AutoDeElevate",
|
|
47
47
|
// See https://github.com/microsoft/playwright/issues/37714
|
|
48
48
|
"RenderDocument",
|
|
49
|
+
// Prevents downloading optimization hints on startup.
|
|
50
|
+
"OptimizationHints",
|
|
49
51
|
assistantMode ? "AutomationControlled" : ""
|
|
50
52
|
].filter(Boolean);
|
|
51
|
-
const chromiumSwitches = (assistantMode, channel) => [
|
|
53
|
+
const chromiumSwitches = (assistantMode, channel, android) => [
|
|
52
54
|
"--disable-field-trial-config",
|
|
53
55
|
// https://source.chromium.org/chromium/chromium/src/+/main:testing/variations/README.md
|
|
54
56
|
"--disable-background-networking",
|
|
@@ -75,6 +77,13 @@ const chromiumSwitches = (assistantMode, channel) => [
|
|
|
75
77
|
"--disable-search-engine-choice-screen",
|
|
76
78
|
// Edge can potentially restart on Windows (msRelaunchNoCompatLayer) which looses its file descriptors (stdout/stderr) and CDP (3/4). Disable until fixed upstream.
|
|
77
79
|
"--edge-skip-compat-layer-relaunch",
|
|
80
|
+
// This disables Chrome for Testing infobar that is visible in the persistent context.
|
|
81
|
+
// The switch is ignored everywhere else, including Chromium/Chrome/Edge.
|
|
82
|
+
"--disable-infobars",
|
|
83
|
+
// Less annoying popups.
|
|
84
|
+
"--disable-search-engine-choice-screen",
|
|
85
|
+
// Prevents the "three dots" menu crash in IdentityManager::HasPrimaryAccount for ephemeral contexts.
|
|
86
|
+
android ? "" : "--disable-sync",
|
|
78
87
|
"--disable-blink-features=AutomationControlled"
|
|
79
88
|
].filter(Boolean);
|
|
80
89
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -53,6 +53,7 @@ class CRBrowser extends import_browser.Browser {
|
|
|
53
53
|
this._crPages = /* @__PURE__ */ new Map();
|
|
54
54
|
this._serviceWorkers = /* @__PURE__ */ new Map();
|
|
55
55
|
this._version = "";
|
|
56
|
+
this._majorVersion = 0;
|
|
56
57
|
this._tracingRecording = false;
|
|
57
58
|
this._userAgent = "";
|
|
58
59
|
this._connection = connection;
|
|
@@ -75,6 +76,10 @@ class CRBrowser extends import_browser.Browser {
|
|
|
75
76
|
await options.__testHookOnConnectToBrowser();
|
|
76
77
|
const version = await session.send("Browser.getVersion");
|
|
77
78
|
browser._version = version.product.substring(version.product.indexOf("/") + 1);
|
|
79
|
+
try {
|
|
80
|
+
browser._majorVersion = +browser._version.split(".")[0];
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
78
83
|
browser._userAgent = version.userAgent;
|
|
79
84
|
browser.options.headful = !version.userAgent.includes("Headless");
|
|
80
85
|
if (!options.persistent) {
|
|
@@ -116,6 +121,9 @@ class CRBrowser extends import_browser.Browser {
|
|
|
116
121
|
version() {
|
|
117
122
|
return this._version;
|
|
118
123
|
}
|
|
124
|
+
majorVersion() {
|
|
125
|
+
return this._majorVersion;
|
|
126
|
+
}
|
|
119
127
|
userAgent() {
|
|
120
128
|
return this._userAgent;
|
|
121
129
|
}
|
|
@@ -276,11 +284,12 @@ class CRBrowser extends import_browser.Browser {
|
|
|
276
284
|
return this._clientRootSessionPromise;
|
|
277
285
|
}
|
|
278
286
|
}
|
|
287
|
+
const CREvents = {
|
|
288
|
+
ServiceWorker: "serviceworker"
|
|
289
|
+
};
|
|
279
290
|
class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
280
291
|
static {
|
|
281
|
-
this.CREvents =
|
|
282
|
-
ServiceWorker: "serviceworker"
|
|
283
|
-
};
|
|
292
|
+
this.CREvents = CREvents;
|
|
284
293
|
}
|
|
285
294
|
constructor(browser, browserContextId, options) {
|
|
286
295
|
super(browser, options, browserContextId);
|
|
@@ -380,15 +389,24 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
|
380
389
|
["midi-sysex", "midiSysex"],
|
|
381
390
|
["storage-access", "storageAccess"],
|
|
382
391
|
["local-fonts", "localFonts"],
|
|
383
|
-
["local-network-access", "localNetworkAccess"]
|
|
392
|
+
["local-network-access", ["localNetworkAccess", "localNetwork", "loopbackNetwork"]]
|
|
384
393
|
]);
|
|
385
|
-
const
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
394
|
+
const grantPermissions = async (mapping) => {
|
|
395
|
+
const filtered = permissions.flatMap((permission) => {
|
|
396
|
+
const protocolPermission = mapping.get(permission);
|
|
397
|
+
if (!protocolPermission)
|
|
398
|
+
throw new Error("Unknown permission: " + permission);
|
|
399
|
+
return typeof protocolPermission === "string" ? [protocolPermission] : protocolPermission;
|
|
400
|
+
});
|
|
401
|
+
await this._browser._session.send("Browser.grantPermissions", { origin: origin === "*" ? void 0 : origin, browserContextId: this._browserContextId, permissions: filtered });
|
|
402
|
+
};
|
|
403
|
+
try {
|
|
404
|
+
await grantPermissions(webPermissionToProtocol);
|
|
405
|
+
} catch (e) {
|
|
406
|
+
const fallbackMapping = new Map(webPermissionToProtocol);
|
|
407
|
+
fallbackMapping.set("local-network-access", ["localNetworkAccess"]);
|
|
408
|
+
await grantPermissions(fallbackMapping);
|
|
409
|
+
}
|
|
392
410
|
}
|
|
393
411
|
async doClearPermissions() {
|
|
394
412
|
await this._browser._session.send("Browser.resetPermissions", { browserContextId: this._browserContextId });
|
|
@@ -461,7 +479,7 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
|
461
479
|
}
|
|
462
480
|
}
|
|
463
481
|
async stopVideoRecording() {
|
|
464
|
-
await Promise.all(this._crPages().map((crPage) => crPage.
|
|
482
|
+
await Promise.all(this._crPages().map((crPage) => crPage._page.screencast.stopVideoRecording()));
|
|
465
483
|
}
|
|
466
484
|
onClosePersistent() {
|
|
467
485
|
}
|
|
@@ -94,11 +94,6 @@ class CRSession extends import_instrumentation.SdkObject {
|
|
|
94
94
|
this._parentSession = parentSession;
|
|
95
95
|
this._sessionId = sessionId;
|
|
96
96
|
this._eventListener = eventListener;
|
|
97
|
-
this.on = super.on;
|
|
98
|
-
this.addListener = super.addListener;
|
|
99
|
-
this.off = super.removeListener;
|
|
100
|
-
this.removeListener = super.removeListener;
|
|
101
|
-
this.once = super.once;
|
|
102
97
|
}
|
|
103
98
|
_markAsCrashed() {
|
|
104
99
|
this._crashed = true;
|
|
@@ -66,6 +66,7 @@ class JSCoverage {
|
|
|
66
66
|
this._eventListeners = [
|
|
67
67
|
import_eventsHelper.eventsHelper.addEventListener(this._client, "Debugger.scriptParsed", this._onScriptParsed.bind(this)),
|
|
68
68
|
import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextsCleared", this._onExecutionContextsCleared.bind(this)),
|
|
69
|
+
import_eventsHelper.eventsHelper.addEventListener(this._client, "Page.frameNavigated", this._onFrameNavigated.bind(this)),
|
|
69
70
|
import_eventsHelper.eventsHelper.addEventListener(this._client, "Debugger.paused", this._onDebuggerPaused.bind(this))
|
|
70
71
|
];
|
|
71
72
|
await Promise.all([
|
|
@@ -117,6 +118,11 @@ class JSCoverage {
|
|
|
117
118
|
}
|
|
118
119
|
return coverage;
|
|
119
120
|
}
|
|
121
|
+
_onFrameNavigated(event) {
|
|
122
|
+
if (event.frame.parentId)
|
|
123
|
+
return;
|
|
124
|
+
this._onExecutionContextsCleared();
|
|
125
|
+
}
|
|
120
126
|
}
|
|
121
127
|
class CSSCoverage {
|
|
122
128
|
constructor(client) {
|
|
@@ -136,7 +142,8 @@ class CSSCoverage {
|
|
|
136
142
|
this._stylesheetSources.clear();
|
|
137
143
|
this._eventListeners = [
|
|
138
144
|
import_eventsHelper.eventsHelper.addEventListener(this._client, "CSS.styleSheetAdded", this._onStyleSheet.bind(this)),
|
|
139
|
-
import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextsCleared", this._onExecutionContextsCleared.bind(this))
|
|
145
|
+
import_eventsHelper.eventsHelper.addEventListener(this._client, "Runtime.executionContextsCleared", this._onExecutionContextsCleared.bind(this)),
|
|
146
|
+
import_eventsHelper.eventsHelper.addEventListener(this._client, "Page.frameNavigated", this._onFrameNavigated.bind(this))
|
|
140
147
|
];
|
|
141
148
|
await Promise.all([
|
|
142
149
|
this._client.send("DOM.enable"),
|
|
@@ -192,6 +199,11 @@ class CSSCoverage {
|
|
|
192
199
|
}
|
|
193
200
|
return coverage;
|
|
194
201
|
}
|
|
202
|
+
_onFrameNavigated(event) {
|
|
203
|
+
if (event.frame.parentId)
|
|
204
|
+
return;
|
|
205
|
+
this._onExecutionContextsCleared();
|
|
206
|
+
}
|
|
195
207
|
}
|
|
196
208
|
function convertToDisjointRanges(nestedRanges) {
|
|
197
209
|
const points = [];
|
|
@@ -141,6 +141,8 @@ class CRNetworkManager {
|
|
|
141
141
|
async setRequestInterception(value) {
|
|
142
142
|
this._userRequestInterceptionEnabled = value;
|
|
143
143
|
await this._updateProtocolRequestInterception();
|
|
144
|
+
if (this._page)
|
|
145
|
+
await this._forEachSession((info) => info.session.send("Network.setCacheDisabled", { cacheDisabled: this._page.needsRequestInterception() }));
|
|
144
146
|
}
|
|
145
147
|
async _updateProtocolRequestInterception() {
|
|
146
148
|
const enabled = this._userRequestInterceptionEnabled || !!this._credentials;
|
|
@@ -153,7 +155,9 @@ class CRNetworkManager {
|
|
|
153
155
|
const enabled = this._protocolRequestInterceptionEnabled;
|
|
154
156
|
if (initial && !enabled)
|
|
155
157
|
return;
|
|
156
|
-
const
|
|
158
|
+
const hasHarRecorders = !!this._page?.browserContext?._harRecorders?.size;
|
|
159
|
+
const userInterception = this._page ? this._page.needsRequestInterception() : false;
|
|
160
|
+
const cachePromise = info.session.send("Network.setCacheDisabled", { cacheDisabled: userInterception || hasHarRecorders });
|
|
157
161
|
let fetchPromise = Promise.resolve(void 0);
|
|
158
162
|
if (!info.workerFrame) {
|
|
159
163
|
if (enabled)
|
|
@@ -265,13 +269,17 @@ class CRNetworkManager {
|
|
|
265
269
|
redirectedFrom = request2;
|
|
266
270
|
}
|
|
267
271
|
}
|
|
272
|
+
const isInterceptedOptionsPreflight = !!requestPausedEvent && requestPausedEvent.request.method === "OPTIONS" && requestWillBeSentEvent.initiator.type === "preflight";
|
|
273
|
+
if (isInterceptedOptionsPreflight && !(this._page || this._serviceWorker).needsRequestInterception()) {
|
|
274
|
+
requestPausedSessionInfo.session._sendMayFail("Fetch.continueRequest", { requestId: requestPausedEvent.requestId });
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
268
277
|
let frame = requestWillBeSentEvent.frameId ? this._page?.frameManager.frame(requestWillBeSentEvent.frameId) : requestWillBeSentSessionInfo.workerFrame;
|
|
269
278
|
if (!frame && this._page && requestPausedEvent && requestPausedEvent.frameId)
|
|
270
279
|
frame = this._page.frameManager.frame(requestPausedEvent.frameId);
|
|
271
280
|
if (!frame && this._page && requestWillBeSentEvent.frameId === (this._page?.delegate)._targetId) {
|
|
272
281
|
frame = this._page.frameManager.frameAttached(requestWillBeSentEvent.frameId, null);
|
|
273
282
|
}
|
|
274
|
-
const isInterceptedOptionsPreflight = !!requestPausedEvent && requestPausedEvent.request.method === "OPTIONS" && requestWillBeSentEvent.initiator.type === "preflight";
|
|
275
283
|
if (isInterceptedOptionsPreflight && (this._page || this._serviceWorker).needsRequestInterception()) {
|
|
276
284
|
const requestHeaders = requestPausedEvent.request.headers;
|
|
277
285
|
const responseHeaders = [
|
|
@@ -300,6 +308,10 @@ class CRNetworkManager {
|
|
|
300
308
|
if (requestPausedEvent) {
|
|
301
309
|
if (redirectedFrom || !this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
|
|
302
310
|
headersOverride = redirectedFrom?._originalRequestRoute?._alreadyContinuedParams?.headers;
|
|
311
|
+
if (headersOverride) {
|
|
312
|
+
const originalHeaders = Object.entries(requestPausedEvent.request.headers).map(([name, value]) => ({ name, value }));
|
|
313
|
+
headersOverride = network.applyHeadersOverrides(originalHeaders, headersOverride);
|
|
314
|
+
}
|
|
303
315
|
requestPausedSessionInfo.session._sendMayFail("Fetch.continueRequest", { requestId: requestPausedEvent.requestId, headers: headersOverride });
|
|
304
316
|
} else {
|
|
305
317
|
route = new RouteImpl(requestPausedSessionInfo.session, requestPausedEvent.requestId, this._page, requestPausedEvent.networkId, this);
|
|
@@ -486,12 +498,11 @@ class InterceptableRequest {
|
|
|
486
498
|
url,
|
|
487
499
|
postDataEntries = null
|
|
488
500
|
} = requestPausedEvent ? requestPausedEvent.request : requestWillBeSentEvent.request;
|
|
489
|
-
const type = (requestWillBeSentEvent.type || "").toLowerCase();
|
|
490
501
|
let postDataBuffer = null;
|
|
491
502
|
const entries = postDataEntries?.filter((entry) => entry.bytes);
|
|
492
503
|
if (entries && entries.length)
|
|
493
504
|
postDataBuffer = Buffer.concat(entries.map((entry) => Buffer.from(entry.bytes, "base64")));
|
|
494
|
-
this.request = new network.Request(context, frame, serviceWorker, redirectedFrom?.request || null, documentId, url, type, method, postDataBuffer, headersOverride || (0, import_utils.headersObjectToArray)(headers));
|
|
505
|
+
this.request = new network.Request(context, frame, serviceWorker, redirectedFrom?.request || null, documentId, url, toResourceType(requestWillBeSentEvent.type || "Other"), method, postDataBuffer, headersOverride || (0, import_utils.headersObjectToArray)(headers));
|
|
495
506
|
}
|
|
496
507
|
}
|
|
497
508
|
class RouteImpl {
|
|
@@ -528,11 +539,12 @@ class RouteImpl {
|
|
|
528
539
|
}
|
|
529
540
|
async fulfill(response) {
|
|
530
541
|
const isTextHtml = response.headers.some((header) => header.name.toLowerCase() === "content-type" && header.value.includes("text/html"));
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
542
|
+
const pageDelegate = this._page?.delegate || null;
|
|
543
|
+
const initScriptTag = pageDelegate?.initScriptTag || "";
|
|
544
|
+
let allInjections = [];
|
|
545
|
+
if (pageDelegate)
|
|
546
|
+
allInjections = [...pageDelegate._mainFrameSession._evaluateOnNewDocumentScripts];
|
|
547
|
+
if (isTextHtml && allInjections.length && initScriptTag) {
|
|
536
548
|
let useNonce = false;
|
|
537
549
|
let scriptNonce = null;
|
|
538
550
|
if (response.isBase64) {
|
|
@@ -583,7 +595,7 @@ class RouteImpl {
|
|
|
583
595
|
let scriptId = import_crypto.default.randomBytes(22).toString("hex");
|
|
584
596
|
let scriptSource = script.source || script;
|
|
585
597
|
const nonceAttr = useNonce ? `nonce="${scriptNonce}"` : "";
|
|
586
|
-
injectionHTML += `<script class="${
|
|
598
|
+
injectionHTML += `<script class="${initScriptTag}" ${nonceAttr} id="${scriptId}" type="text/javascript">document.getElementById("${scriptId}")?.remove();${scriptSource}</script>`;
|
|
587
599
|
});
|
|
588
600
|
const lower = response.body.toLowerCase();
|
|
589
601
|
const headStartIndex = lower.indexOf("<head");
|
|
@@ -593,7 +605,27 @@ class RouteImpl {
|
|
|
593
605
|
const headOpenEnd = response.body.indexOf(">", headStartIndex) + 1;
|
|
594
606
|
const headContent = response.body.slice(headOpenEnd, headEndTagIndex);
|
|
595
607
|
const headContentLower = headContent.toLowerCase();
|
|
596
|
-
|
|
608
|
+
let firstScriptIndex = -1;
|
|
609
|
+
let searchPos = 0;
|
|
610
|
+
const endSearchPos = headContentLower.length;
|
|
611
|
+
while (searchPos < endSearchPos) {
|
|
612
|
+
const commentStart = headContentLower.indexOf("<!--", searchPos);
|
|
613
|
+
const scriptStart = headContentLower.indexOf("<script", searchPos);
|
|
614
|
+
if (scriptStart === -1 || scriptStart >= endSearchPos) {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
if (commentStart !== -1 && commentStart < scriptStart) {
|
|
618
|
+
const commentEnd = headContentLower.indexOf("-->", commentStart);
|
|
619
|
+
if (commentEnd !== -1) {
|
|
620
|
+
searchPos = commentEnd + 3;
|
|
621
|
+
continue;
|
|
622
|
+
} else {
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
firstScriptIndex = scriptStart;
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
597
629
|
if (firstScriptIndex !== -1) {
|
|
598
630
|
const insertPosition = headOpenEnd + firstScriptIndex;
|
|
599
631
|
response.body = response.body.slice(0, insertPosition) + injectionHTML + response.body.slice(insertPosition);
|
|
@@ -650,10 +682,13 @@ class RouteImpl {
|
|
|
650
682
|
let hasScriptSrc = false;
|
|
651
683
|
for (let directive of directives) {
|
|
652
684
|
if (!directive.trim()) continue;
|
|
653
|
-
const
|
|
654
|
-
if (
|
|
655
|
-
|
|
656
|
-
|
|
685
|
+
const directiveMatch = directive.match(/^([a-zA-Z-]+)\s+(.*)$/);
|
|
686
|
+
if (!directiveMatch) {
|
|
687
|
+
fixedDirectives.push(directive);
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
const directiveName = directiveMatch[1].toLowerCase();
|
|
691
|
+
const directiveValues = directiveMatch[2].split(/\s+/).filter((v) => v.length > 0);
|
|
657
692
|
switch (directiveName) {
|
|
658
693
|
case "script-src":
|
|
659
694
|
hasScriptSrc = true;
|
|
@@ -664,6 +699,12 @@ class RouteImpl {
|
|
|
664
699
|
if (!values.includes("'unsafe-eval'")) {
|
|
665
700
|
values.push("'unsafe-eval'");
|
|
666
701
|
}
|
|
702
|
+
if (!values.includes("'unsafe-inline'") && !scriptNonce) {
|
|
703
|
+
values.push("'unsafe-inline'");
|
|
704
|
+
}
|
|
705
|
+
if (!values.includes("*") && !values.includes("'self'") && !values.some((v) => v.includes("https:"))) {
|
|
706
|
+
values.push("*");
|
|
707
|
+
}
|
|
667
708
|
fixedDirectives.push(`script-src ${values.join(" ")}`);
|
|
668
709
|
break;
|
|
669
710
|
case "style-src":
|
|
@@ -709,9 +750,9 @@ class RouteImpl {
|
|
|
709
750
|
}
|
|
710
751
|
if (!hasScriptSrc) {
|
|
711
752
|
if (scriptNonce) {
|
|
712
|
-
fixedDirectives.push(`script-src 'self' 'unsafe-eval' 'nonce-${scriptNonce}'
|
|
753
|
+
fixedDirectives.push(`script-src 'self' 'unsafe-eval' 'nonce-${scriptNonce}' *`);
|
|
713
754
|
} else {
|
|
714
|
-
fixedDirectives.push(`script-src 'self' 'unsafe-eval'
|
|
755
|
+
fixedDirectives.push(`script-src 'self' 'unsafe-eval' 'unsafe-inline' *`);
|
|
715
756
|
}
|
|
716
757
|
}
|
|
717
758
|
return fixedDirectives.join("; ");
|
|
@@ -722,6 +763,12 @@ class RouteImpl {
|
|
|
722
763
|
}
|
|
723
764
|
if (this._networkId != event.networkId || !this._sessionManager._alreadyTrackedNetworkIds.has(event.networkId)) return;
|
|
724
765
|
try {
|
|
766
|
+
const url = event.request?.url || "";
|
|
767
|
+
const isPrivilegePage = url.startsWith("https://ntp.msn");
|
|
768
|
+
if (isPrivilegePage) {
|
|
769
|
+
await this._session._sendMayFail("Fetch.continueRequest", { requestId: event.requestId });
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
725
772
|
if (event.responseStatusCode >= 301 && event.responseStatusCode <= 308 || event.redirectedRequestId && !event.responseStatusCode) {
|
|
726
773
|
await this._session.send("Fetch.continueRequest", { requestId: event.requestId, interceptResponse: true });
|
|
727
774
|
} else {
|
|
@@ -736,7 +783,11 @@ class RouteImpl {
|
|
|
736
783
|
});
|
|
737
784
|
}
|
|
738
785
|
} catch (error) {
|
|
739
|
-
|
|
786
|
+
if (error.message.includes("Can only get response body on HeadersReceived pattern matched requests.")) {
|
|
787
|
+
await this._session.send("Fetch.continueRequest", { requestId: event.requestId, interceptResponse: true });
|
|
788
|
+
} else {
|
|
789
|
+
await this._session._sendMayFail("Fetch.continueRequest", { requestId: event.requestId });
|
|
790
|
+
}
|
|
740
791
|
}
|
|
741
792
|
}
|
|
742
793
|
}
|
|
@@ -867,6 +918,44 @@ class ResponseExtraInfoTracker {
|
|
|
867
918
|
this._requests.delete(requestId);
|
|
868
919
|
}
|
|
869
920
|
}
|
|
921
|
+
function toResourceType(type) {
|
|
922
|
+
switch (type) {
|
|
923
|
+
case "Document":
|
|
924
|
+
return "document";
|
|
925
|
+
case "Stylesheet":
|
|
926
|
+
return "stylesheet";
|
|
927
|
+
case "Image":
|
|
928
|
+
return "image";
|
|
929
|
+
case "Media":
|
|
930
|
+
return "media";
|
|
931
|
+
case "Font":
|
|
932
|
+
return "font";
|
|
933
|
+
case "Script":
|
|
934
|
+
return "script";
|
|
935
|
+
case "TextTrack":
|
|
936
|
+
return "texttrack";
|
|
937
|
+
case "XHR":
|
|
938
|
+
return "xhr";
|
|
939
|
+
case "Fetch":
|
|
940
|
+
return "fetch";
|
|
941
|
+
case "EventSource":
|
|
942
|
+
return "eventsource";
|
|
943
|
+
case "WebSocket":
|
|
944
|
+
return "websocket";
|
|
945
|
+
case "Manifest":
|
|
946
|
+
return "manifest";
|
|
947
|
+
case "Ping":
|
|
948
|
+
return "ping";
|
|
949
|
+
case "CSPViolationReport":
|
|
950
|
+
return "cspreport";
|
|
951
|
+
case "Prefetch":
|
|
952
|
+
case "SignedExchange":
|
|
953
|
+
case "Preflight":
|
|
954
|
+
case "FedCM":
|
|
955
|
+
default:
|
|
956
|
+
return "other";
|
|
957
|
+
}
|
|
958
|
+
}
|
|
870
959
|
// Annotate the CommonJS export names for ESM import in node:
|
|
871
960
|
0 && (module.exports = {
|
|
872
961
|
CRNetworkManager
|