patchright-core 1.57.0 → 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 +3223 -308
- package/browsers.json +21 -22
- package/lib/cli/program.js +4 -5
- package/lib/client/api.js +3 -0
- package/lib/client/browser.js +3 -5
- package/lib/client/browserContext.js +40 -4
- package/lib/client/browserType.js +4 -3
- package/lib/client/connection.js +4 -0
- package/lib/client/elementHandle.js +3 -0
- package/lib/client/events.js +3 -0
- package/lib/client/fetch.js +3 -4
- package/lib/client/frame.js +10 -1
- package/lib/client/locator.js +8 -0
- package/lib/client/network.js +5 -1
- package/lib/client/page.js +29 -1
- package/lib/client/pageAgent.js +64 -0
- package/lib/client/platform.js +3 -0
- package/lib/client/tracing.js +1 -1
- package/lib/generated/injectedScriptSource.js +1 -1
- package/lib/generated/pollingRecorderSource.js +1 -1
- 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 +88 -4
- 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/artifact.js +1 -1
- package/lib/server/bidi/bidiBrowser.js +56 -12
- package/lib/server/bidi/bidiChromium.js +8 -12
- 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 +6 -8
- package/lib/server/bidi/bidiNetworkManager.js +1 -1
- package/lib/server/bidi/bidiPage.js +39 -28
- package/lib/server/bidi/third_party/bidiProtocolCore.js +1 -0
- package/lib/server/browserContext.js +34 -26
- package/lib/server/browserType.js +12 -4
- package/lib/server/chromium/chromium.js +14 -20
- package/lib/server/chromium/chromiumSwitches.js +2 -2
- package/lib/server/chromium/crBrowser.js +22 -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 +92 -12
- package/lib/server/chromium/crPage.js +62 -116
- package/lib/server/codegen/javascript.js +6 -29
- package/lib/server/deviceDescriptorsSource.json +56 -56
- package/lib/server/dispatchers/browserContextDispatcher.js +3 -2
- 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 +4 -0
- package/lib/server/dom.js +12 -3
- package/lib/server/electron/electron.js +5 -2
- 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 +15 -18
- package/lib/server/firefox/firefox.js +6 -8
- package/lib/server/frameSelectors.js +16 -4
- package/lib/server/frames.js +251 -86
- package/lib/server/instrumentation.js +3 -0
- package/lib/server/javascript.js +8 -4
- package/lib/server/launchApp.js +2 -1
- package/lib/server/network.js +50 -12
- package/lib/server/page.js +61 -91
- package/lib/server/progress.js +26 -6
- package/lib/server/recorder/recorderApp.js +79 -100
- package/lib/server/registry/browserFetcher.js +6 -4
- package/lib/server/registry/index.js +172 -149
- package/lib/server/registry/oopDownloadBrowserMain.js +3 -0
- package/lib/server/screencast.js +190 -0
- package/lib/server/screenshotter.js +6 -0
- 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 +29 -21
- package/lib/server/trace/viewer/traceParser.js +72 -0
- package/lib/server/trace/viewer/traceViewer.js +21 -17
- package/lib/server/utils/expectUtils.js +87 -2
- package/lib/server/utils/hostPlatform.js +15 -0
- package/lib/server/utils/httpServer.js +5 -20
- package/lib/server/utils/network.js +37 -28
- package/lib/server/utils/nodePlatform.js +6 -0
- package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +22 -13
- package/lib/server/webkit/webkit.js +4 -6
- 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 +75 -46
- package/lib/utils/isomorphic/ariaSnapshot.js +60 -2
- package/lib/utils/isomorphic/lruCache.js +51 -0
- package/lib/utils/isomorphic/protocolMetainfo.js +9 -1
- 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/yaml.js +84 -0
- package/lib/utils.js +2 -0
- package/lib/utilsBundle.js +2 -5
- package/lib/utilsBundleImpl/index.js +165 -165
- package/lib/vite/htmlReport/index.html +21 -21
- package/lib/vite/recorder/assets/codeMirrorModule-CFUTFUO7.js +32 -0
- package/lib/vite/{traceViewer/codeMirrorModule.C3UTv-Ge.css → recorder/assets/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/{recorder/assets/codeMirrorModule-C3UTv-Ge.css → traceViewer/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 +4 -4
- 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 +738 -159
- package/types/types.d.ts +25 -38
- package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
- package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
- package/lib/vite/recorder/assets/codeMirrorModule-CBbSe-ZI.js +0 -25
- package/lib/vite/recorder/assets/index-CpZVd2nA.js +0 -193
- package/lib/vite/traceViewer/assets/codeMirrorModule-DHz0wP2C.js +0 -25
- package/lib/vite/traceViewer/assets/defaultSettingsView-WsZP88O6.js +0 -266
- package/lib/vite/traceViewer/defaultSettingsView.ConWv5KN.css +0 -1
- package/lib/vite/traceViewer/index.C4Y3Aw8n.css +0 -1
- package/lib/vite/traceViewer/index.C8xAeo93.js +0 -2
- package/lib/vite/traceViewer/uiMode.BltraIJB.js +0 -5
|
@@ -55,6 +55,24 @@ var import_recorderApp = require("./recorder/recorderApp");
|
|
|
55
55
|
var import_selectors = require("./selectors");
|
|
56
56
|
var import_tracing = require("./trace/recorder/tracing");
|
|
57
57
|
var rawStorageSource = __toESM(require("../generated/storageScriptSource"));
|
|
58
|
+
const BrowserContextEvent = {
|
|
59
|
+
Console: "console",
|
|
60
|
+
Close: "close",
|
|
61
|
+
Page: "page",
|
|
62
|
+
// Can't use just 'error' due to node.js special treatment of error events.
|
|
63
|
+
// @see https://nodejs.org/api/events.html#events_error_events
|
|
64
|
+
PageError: "pageerror",
|
|
65
|
+
Request: "request",
|
|
66
|
+
Response: "response",
|
|
67
|
+
RequestFailed: "requestfailed",
|
|
68
|
+
RequestFinished: "requestfinished",
|
|
69
|
+
RequestAborted: "requestaborted",
|
|
70
|
+
RequestFulfilled: "requestfulfilled",
|
|
71
|
+
RequestContinued: "requestcontinued",
|
|
72
|
+
BeforeClose: "beforeclose",
|
|
73
|
+
VideoStarted: "videostarted",
|
|
74
|
+
RecorderEvent: "recorderevent"
|
|
75
|
+
};
|
|
58
76
|
class BrowserContext extends import_instrumentation.SdkObject {
|
|
59
77
|
constructor(browser, options, browserContextId) {
|
|
60
78
|
super(browser, "browser-context");
|
|
@@ -69,6 +87,7 @@ class BrowserContext extends import_instrumentation.SdkObject {
|
|
|
69
87
|
this._creatingStorageStatePage = false;
|
|
70
88
|
this.initScripts = [];
|
|
71
89
|
this._routesInFlight = /* @__PURE__ */ new Set();
|
|
90
|
+
this._consoleApiExposed = false;
|
|
72
91
|
this.attribution.context = this;
|
|
73
92
|
this._browser = browser;
|
|
74
93
|
this._options = options;
|
|
@@ -82,24 +101,7 @@ class BrowserContext extends import_instrumentation.SdkObject {
|
|
|
82
101
|
this.dialogManager = new import_dialog.DialogManager(this.instrumentation);
|
|
83
102
|
}
|
|
84
103
|
static {
|
|
85
|
-
this.Events =
|
|
86
|
-
Console: "console",
|
|
87
|
-
Close: "close",
|
|
88
|
-
Page: "page",
|
|
89
|
-
// Can't use just 'error' due to node.js special treatment of error events.
|
|
90
|
-
// @see https://nodejs.org/api/events.html#events_error_events
|
|
91
|
-
PageError: "pageerror",
|
|
92
|
-
Request: "request",
|
|
93
|
-
Response: "response",
|
|
94
|
-
RequestFailed: "requestfailed",
|
|
95
|
-
RequestFinished: "requestfinished",
|
|
96
|
-
RequestAborted: "requestaborted",
|
|
97
|
-
RequestFulfilled: "requestfulfilled",
|
|
98
|
-
RequestContinued: "requestcontinued",
|
|
99
|
-
BeforeClose: "beforeclose",
|
|
100
|
-
VideoStarted: "videostarted",
|
|
101
|
-
RecorderEvent: "recorderevent"
|
|
102
|
-
};
|
|
104
|
+
this.Events = BrowserContextEvent;
|
|
103
105
|
}
|
|
104
106
|
isPersistentContext() {
|
|
105
107
|
return this._isPersistentContext;
|
|
@@ -119,12 +121,8 @@ class BrowserContext extends import_instrumentation.SdkObject {
|
|
|
119
121
|
if (this._debugger.isPaused())
|
|
120
122
|
import_recorderApp.RecorderApp.showInspectorNoReply(this);
|
|
121
123
|
});
|
|
122
|
-
if ((0, import_debug.debugMode)() === "console")
|
|
123
|
-
await this.
|
|
124
|
-
function installConsoleApi(injectedScript) { injectedScript.consoleApi.install(); }
|
|
125
|
-
module.exports = { default: () => installConsoleApi };
|
|
126
|
-
`);
|
|
127
|
-
}
|
|
124
|
+
if ((0, import_debug.debugMode)() === "console")
|
|
125
|
+
await this.exposeConsoleApi();
|
|
128
126
|
if (this._options.serviceWorkers === "block")
|
|
129
127
|
await this.addInitScript(void 0, `navigator.serviceWorker.register = async () => { };`);
|
|
130
128
|
if (this._options.permissions)
|
|
@@ -133,6 +131,15 @@ class BrowserContext extends import_instrumentation.SdkObject {
|
|
|
133
131
|
debugger() {
|
|
134
132
|
return this._debugger;
|
|
135
133
|
}
|
|
134
|
+
async exposeConsoleApi() {
|
|
135
|
+
if (this._consoleApiExposed)
|
|
136
|
+
return;
|
|
137
|
+
this._consoleApiExposed = true;
|
|
138
|
+
await this.extendInjectedScript(`
|
|
139
|
+
function installConsoleApi(injectedScript) { injectedScript.consoleApi.install(); }
|
|
140
|
+
module.exports = { default: () => installConsoleApi };
|
|
141
|
+
`);
|
|
142
|
+
}
|
|
136
143
|
async _ensureVideosPath() {
|
|
137
144
|
if (this._options.recordVideo)
|
|
138
145
|
await (0, import_fileUtils.mkdirIfNeeded)(import_path.default.join(this._options.recordVideo.dir, "dummy"));
|
|
@@ -309,7 +316,7 @@ class BrowserContext extends import_instrumentation.SdkObject {
|
|
|
309
316
|
const pageOrError = await progress.race(page.waitForInitializedOrError());
|
|
310
317
|
if (pageOrError instanceof Error)
|
|
311
318
|
throw pageOrError;
|
|
312
|
-
await page.mainFrame().
|
|
319
|
+
await page.mainFrame().waitForLoadState(progress, "load");
|
|
313
320
|
return page;
|
|
314
321
|
}
|
|
315
322
|
async _loadDefaultContext(progress) {
|
|
@@ -669,7 +676,8 @@ const defaultNewContextParamValues = {
|
|
|
669
676
|
acceptDownloads: "accept",
|
|
670
677
|
strictSelectors: false,
|
|
671
678
|
serviceWorkers: "allow",
|
|
672
|
-
locale: "en-US"
|
|
679
|
+
locale: "en-US",
|
|
680
|
+
focusControl: false
|
|
673
681
|
};
|
|
674
682
|
// Annotate the CommonJS export names for ESM import in node:
|
|
675
683
|
0 && (module.exports = {
|
|
@@ -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 {};
|
|
@@ -114,7 +114,8 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
114
114
|
};
|
|
115
115
|
(0, import_browserContext.validateBrowserContextOptions)(persistent, browserOptions);
|
|
116
116
|
const browser = await progress.race(import_crBrowser.CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions));
|
|
117
|
-
|
|
117
|
+
if (!options.isLocal)
|
|
118
|
+
browser._isCollocatedWithServer = false;
|
|
118
119
|
browser.on(import_browser.Browser.Events.Disconnected, doCleanup);
|
|
119
120
|
return browser;
|
|
120
121
|
} catch (error) {
|
|
@@ -128,13 +129,8 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
128
129
|
return directory ? new import_crDevTools.CRDevTools(import_path.default.join(directory, "devtools-preferences.json")) : void 0;
|
|
129
130
|
}
|
|
130
131
|
async connectToTransport(transport, options, browserLogsCollector) {
|
|
131
|
-
let devtools = this._devtools;
|
|
132
|
-
if (options.__testHookForDevTools) {
|
|
133
|
-
devtools = this._createDevTools();
|
|
134
|
-
await options.__testHookForDevTools(devtools);
|
|
135
|
-
}
|
|
136
132
|
try {
|
|
137
|
-
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);
|
|
138
134
|
} catch (e) {
|
|
139
135
|
if (browserLogsCollector.recentLogs().some((log) => log.includes("Failed to create a ProcessSingleton for your profile directory."))) {
|
|
140
136
|
throw new Error(
|
|
@@ -144,14 +140,12 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
144
140
|
throw e;
|
|
145
141
|
}
|
|
146
142
|
}
|
|
147
|
-
doRewriteStartupLog(
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return error;
|
|
154
|
-
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 [
|
|
155
149
|
`Chromium sandboxing failed!`,
|
|
156
150
|
`================================`,
|
|
157
151
|
`To avoid the sandboxing issue, do either of the following:`,
|
|
@@ -160,7 +154,6 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
160
154
|
`================================`,
|
|
161
155
|
``
|
|
162
156
|
].join("\n");
|
|
163
|
-
return error;
|
|
164
157
|
}
|
|
165
158
|
amendEnvironment(env) {
|
|
166
159
|
return env;
|
|
@@ -284,11 +277,8 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
284
277
|
if (args.find((arg) => !arg.startsWith("-")))
|
|
285
278
|
throw new Error("Arguments can not specify page to be opened");
|
|
286
279
|
const chromeArguments = [...(0, import_chromiumSwitches.chromiumSwitches)(options.assistantMode, options.channel)];
|
|
287
|
-
if (import_os.default.platform()
|
|
288
|
-
chromeArguments.push("--enable-unsafe-swiftshader");
|
|
280
|
+
if (import_os.default.platform() !== "darwin" || !(0, import_utils.hasGpuMac)()) {
|
|
289
281
|
}
|
|
290
|
-
if (options.devtools)
|
|
291
|
-
chromeArguments.push("--auto-open-devtools-for-tabs");
|
|
292
282
|
if (options.headless) {
|
|
293
283
|
chromeArguments.push("--headless");
|
|
294
284
|
chromeArguments.push(
|
|
@@ -324,6 +314,10 @@ class Chromium extends import_browserType.BrowserType {
|
|
|
324
314
|
return waitForReadyState(options, browserLogsCollector);
|
|
325
315
|
}
|
|
326
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";
|
|
327
321
|
if (options.channel)
|
|
328
322
|
return options.channel;
|
|
329
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",
|
|
@@ -284,11 +284,12 @@ class CRBrowser extends import_browser.Browser {
|
|
|
284
284
|
return this._clientRootSessionPromise;
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
|
+
const CREvents = {
|
|
288
|
+
ServiceWorker: "serviceworker"
|
|
289
|
+
};
|
|
287
290
|
class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
288
291
|
static {
|
|
289
|
-
this.CREvents =
|
|
290
|
-
ServiceWorker: "serviceworker"
|
|
291
|
-
};
|
|
292
|
+
this.CREvents = CREvents;
|
|
292
293
|
}
|
|
293
294
|
constructor(browser, browserContextId, options) {
|
|
294
295
|
super(browser, options, browserContextId);
|
|
@@ -388,15 +389,24 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
|
388
389
|
["midi-sysex", "midiSysex"],
|
|
389
390
|
["storage-access", "storageAccess"],
|
|
390
391
|
["local-fonts", "localFonts"],
|
|
391
|
-
["local-network-access", "localNetworkAccess"]
|
|
392
|
+
["local-network-access", ["localNetworkAccess", "localNetwork", "loopbackNetwork"]]
|
|
392
393
|
]);
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
+
}
|
|
400
410
|
}
|
|
401
411
|
async doClearPermissions() {
|
|
402
412
|
await this._browser._session.send("Browser.resetPermissions", { browserContextId: this._browserContextId });
|
|
@@ -469,7 +479,7 @@ class CRBrowserContext extends import_browserContext.BrowserContext {
|
|
|
469
479
|
}
|
|
470
480
|
}
|
|
471
481
|
async stopVideoRecording() {
|
|
472
|
-
await Promise.all(this._crPages().map((crPage) => crPage.
|
|
482
|
+
await Promise.all(this._crPages().map((crPage) => crPage._page.screencast.stopVideoRecording()));
|
|
473
483
|
}
|
|
474
484
|
onClosePersistent() {
|
|
475
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);
|
|
@@ -731,6 +763,12 @@ class RouteImpl {
|
|
|
731
763
|
}
|
|
732
764
|
if (this._networkId != event.networkId || !this._sessionManager._alreadyTrackedNetworkIds.has(event.networkId)) return;
|
|
733
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
|
+
}
|
|
734
772
|
if (event.responseStatusCode >= 301 && event.responseStatusCode <= 308 || event.redirectedRequestId && !event.responseStatusCode) {
|
|
735
773
|
await this._session.send("Fetch.continueRequest", { requestId: event.requestId, interceptResponse: true });
|
|
736
774
|
} else {
|
|
@@ -745,7 +783,11 @@ class RouteImpl {
|
|
|
745
783
|
});
|
|
746
784
|
}
|
|
747
785
|
} catch (error) {
|
|
748
|
-
|
|
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
|
+
}
|
|
749
791
|
}
|
|
750
792
|
}
|
|
751
793
|
}
|
|
@@ -876,6 +918,44 @@ class ResponseExtraInfoTracker {
|
|
|
876
918
|
this._requests.delete(requestId);
|
|
877
919
|
}
|
|
878
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
|
+
}
|
|
879
959
|
// Annotate the CommonJS export names for ESM import in node:
|
|
880
960
|
0 && (module.exports = {
|
|
881
961
|
CRNetworkManager
|