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.
Files changed (180) hide show
  1. package/ThirdPartyNotices.txt +3134 -560
  2. package/bin/install_webkit_wsl.ps1 +1 -3
  3. package/browsers.json +21 -22
  4. package/lib/cli/program.js +16 -60
  5. package/lib/client/api.js +3 -3
  6. package/lib/client/browser.js +3 -5
  7. package/lib/client/browserContext.js +62 -8
  8. package/lib/client/browserType.js +4 -3
  9. package/lib/client/connection.js +4 -0
  10. package/lib/client/consoleMessage.js +5 -1
  11. package/lib/client/electron.js +1 -1
  12. package/lib/client/elementHandle.js +3 -0
  13. package/lib/client/events.js +5 -1
  14. package/lib/client/fetch.js +3 -4
  15. package/lib/client/frame.js +10 -1
  16. package/lib/client/locator.js +12 -1
  17. package/lib/client/network.js +5 -1
  18. package/lib/client/page.js +31 -6
  19. package/lib/client/pageAgent.js +64 -0
  20. package/lib/client/platform.js +3 -0
  21. package/lib/client/playwright.js +1 -5
  22. package/lib/client/tracing.js +7 -5
  23. package/lib/client/worker.js +22 -0
  24. package/lib/generated/clockSource.js +1 -1
  25. package/lib/generated/injectedScriptSource.js +1 -1
  26. package/lib/generated/pollingRecorderSource.js +1 -1
  27. package/lib/inProcessFactory.js +0 -2
  28. package/lib/mcpBundle.js +84 -0
  29. package/lib/mcpBundleImpl/index.js +147 -0
  30. package/lib/protocol/serializers.js +5 -0
  31. package/lib/protocol/validator.js +112 -50
  32. package/lib/remote/playwrightServer.js +1 -2
  33. package/lib/server/agent/actionRunner.js +335 -0
  34. package/lib/server/agent/actions.js +128 -0
  35. package/lib/server/agent/codegen.js +111 -0
  36. package/lib/server/agent/context.js +150 -0
  37. package/lib/server/agent/expectTools.js +156 -0
  38. package/lib/server/agent/pageAgent.js +204 -0
  39. package/lib/server/agent/performTools.js +262 -0
  40. package/lib/server/agent/tool.js +109 -0
  41. package/lib/server/android/android.js +1 -1
  42. package/lib/server/artifact.js +1 -1
  43. package/lib/server/bidi/bidiBrowser.js +81 -22
  44. package/lib/server/bidi/bidiChromium.js +9 -13
  45. package/lib/server/bidi/bidiConnection.js +1 -0
  46. package/lib/server/bidi/bidiDeserializer.js +116 -0
  47. package/lib/server/bidi/bidiExecutionContext.js +75 -29
  48. package/lib/server/bidi/bidiFirefox.js +7 -9
  49. package/lib/server/bidi/bidiNetworkManager.js +1 -1
  50. package/lib/server/bidi/bidiPage.js +61 -30
  51. package/lib/server/bidi/third_party/bidiProtocolCore.js +1 -0
  52. package/lib/server/browserContext.js +43 -36
  53. package/lib/server/browserType.js +12 -4
  54. package/lib/server/chromium/chromium.js +26 -21
  55. package/lib/server/chromium/chromiumSwitches.js +12 -3
  56. package/lib/server/chromium/crBrowser.js +30 -12
  57. package/lib/server/chromium/crConnection.js +0 -5
  58. package/lib/server/chromium/crCoverage.js +13 -1
  59. package/lib/server/chromium/crDevTools.js +0 -2
  60. package/lib/server/chromium/crNetworkManager.js +107 -18
  61. package/lib/server/chromium/crPage.js +68 -124
  62. package/lib/server/chromium/crServiceWorker.js +14 -1
  63. package/lib/server/codegen/javascript.js +6 -29
  64. package/lib/server/console.js +5 -1
  65. package/lib/server/deviceDescriptorsSource.json +56 -56
  66. package/lib/server/dispatchers/browserContextDispatcher.js +26 -8
  67. package/lib/server/dispatchers/dispatcher.js +6 -13
  68. package/lib/server/dispatchers/frameDispatcher.js +1 -1
  69. package/lib/server/dispatchers/jsHandleDispatcher.js +2 -2
  70. package/lib/server/dispatchers/pageAgentDispatcher.js +96 -0
  71. package/lib/server/dispatchers/pageDispatcher.js +14 -22
  72. package/lib/server/dispatchers/playwrightDispatcher.js +0 -4
  73. package/lib/server/dom.js +12 -3
  74. package/lib/server/electron/electron.js +6 -3
  75. package/lib/server/firefox/ffBrowser.js +10 -20
  76. package/lib/server/firefox/ffConnection.js +0 -5
  77. package/lib/server/firefox/ffNetworkManager.js +2 -2
  78. package/lib/server/firefox/ffPage.js +18 -24
  79. package/lib/server/firefox/firefox.js +18 -9
  80. package/lib/server/frameSelectors.js +18 -8
  81. package/lib/server/frames.js +257 -87
  82. package/lib/server/input.js +7 -3
  83. package/lib/server/instrumentation.js +3 -0
  84. package/lib/server/javascript.js +8 -4
  85. package/lib/server/launchApp.js +2 -1
  86. package/lib/server/localUtils.js +4 -8
  87. package/lib/server/network.js +50 -12
  88. package/lib/server/page.js +112 -126
  89. package/lib/server/playwright.js +2 -4
  90. package/lib/server/progress.js +26 -6
  91. package/lib/server/recorder/recorderApp.js +80 -101
  92. package/lib/server/recorder.js +3 -2
  93. package/lib/server/registry/browserFetcher.js +6 -4
  94. package/lib/server/registry/index.js +278 -189
  95. package/lib/server/registry/oopDownloadBrowserMain.js +9 -2
  96. package/lib/server/screencast.js +190 -0
  97. package/lib/server/screenshotter.js +6 -0
  98. package/lib/server/socksClientCertificatesInterceptor.js +1 -1
  99. package/lib/server/trace/recorder/snapshotter.js +17 -8
  100. package/lib/server/trace/recorder/snapshotterInjected.js +30 -72
  101. package/lib/server/trace/recorder/tracing.js +31 -21
  102. package/lib/server/trace/viewer/traceParser.js +72 -0
  103. package/lib/server/trace/viewer/traceViewer.js +45 -40
  104. package/lib/server/utils/comparators.js +3 -25
  105. package/lib/server/utils/expectUtils.js +87 -2
  106. package/lib/server/utils/hostPlatform.js +30 -3
  107. package/lib/server/utils/httpServer.js +5 -20
  108. package/lib/server/utils/imageUtils.js +141 -0
  109. package/lib/server/utils/network.js +55 -40
  110. package/lib/server/utils/nodePlatform.js +6 -0
  111. package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +35 -24
  112. package/lib/server/webkit/webkit.js +5 -16
  113. package/lib/server/webkit/wkBrowser.js +2 -6
  114. package/lib/server/webkit/wkConnection.js +1 -6
  115. package/lib/server/webkit/wkInterceptableRequest.js +29 -1
  116. package/lib/server/webkit/wkPage.js +76 -51
  117. package/lib/server/webkit/wkWorkers.js +2 -1
  118. package/lib/utils/isomorphic/ariaSnapshot.js +63 -0
  119. package/lib/utils/isomorphic/locatorGenerators.js +24 -8
  120. package/lib/utils/isomorphic/lruCache.js +51 -0
  121. package/lib/utils/isomorphic/mimeType.js +1 -1
  122. package/lib/utils/isomorphic/protocolFormatter.js +3 -0
  123. package/lib/utils/isomorphic/protocolMetainfo.js +11 -2
  124. package/lib/utils/isomorphic/stringUtils.js +49 -0
  125. package/lib/utils/isomorphic/trace/entries.js +16 -0
  126. package/lib/utils/isomorphic/trace/snapshotRenderer.js +499 -0
  127. package/lib/utils/isomorphic/trace/snapshotServer.js +120 -0
  128. package/lib/utils/isomorphic/trace/snapshotStorage.js +89 -0
  129. package/lib/utils/isomorphic/trace/traceLoader.js +131 -0
  130. package/lib/utils/isomorphic/trace/traceModel.js +365 -0
  131. package/lib/utils/isomorphic/trace/traceModernizer.js +400 -0
  132. package/lib/utils/isomorphic/trace/versions/traceV3.js +16 -0
  133. package/lib/utils/isomorphic/trace/versions/traceV4.js +16 -0
  134. package/lib/utils/isomorphic/trace/versions/traceV5.js +16 -0
  135. package/lib/utils/isomorphic/trace/versions/traceV6.js +16 -0
  136. package/lib/utils/isomorphic/trace/versions/traceV7.js +16 -0
  137. package/lib/utils/isomorphic/trace/versions/traceV8.js +16 -0
  138. package/lib/utils/isomorphic/urlMatch.js +19 -5
  139. package/lib/utils/isomorphic/yaml.js +84 -0
  140. package/lib/utils.js +4 -0
  141. package/lib/utilsBundle.js +1 -1
  142. package/lib/utilsBundleImpl/index.js +124 -124
  143. package/lib/vite/htmlReport/index.html +21 -21
  144. package/lib/vite/recorder/assets/codeMirrorModule-CFUTFUO7.js +32 -0
  145. package/lib/vite/recorder/assets/{codeMirrorModule-C3UTv-Ge.css → codeMirrorModule-DYBRYzYX.css} +1 -1
  146. package/lib/vite/recorder/assets/{index-Ri0uHF7I.css → index-BSjZa4pk.css} +1 -1
  147. package/lib/vite/recorder/assets/index-CVkBxsGf.js +193 -0
  148. package/lib/vite/recorder/index.html +2 -2
  149. package/lib/vite/traceViewer/assets/codeMirrorModule-BVA4h_ZY.js +32 -0
  150. package/lib/vite/traceViewer/assets/defaultSettingsView-CjfmcdOz.js +266 -0
  151. package/lib/vite/traceViewer/{codeMirrorModule.C3UTv-Ge.css → codeMirrorModule.DYBRYzYX.css} +1 -1
  152. package/lib/vite/traceViewer/defaultSettingsView.7ch9cixO.css +1 -0
  153. package/lib/vite/traceViewer/index.BVu7tZDe.css +1 -0
  154. package/lib/vite/traceViewer/index.BtyWtaE-.js +2 -0
  155. package/lib/vite/traceViewer/index.html +6 -6
  156. package/lib/vite/traceViewer/manifest.webmanifest +16 -0
  157. package/lib/vite/traceViewer/snapshot.html +3 -3
  158. package/lib/vite/traceViewer/sw.bundle.js +5 -3
  159. package/lib/vite/traceViewer/uiMode.fyrXARf2.js +5 -0
  160. package/lib/vite/traceViewer/uiMode.html +3 -3
  161. package/package.json +2 -1
  162. package/types/protocol.d.ts +939 -245
  163. package/types/types.d.ts +143 -153
  164. package/lib/client/accessibility.js +0 -49
  165. package/lib/server/accessibility.js +0 -69
  166. package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
  167. package/lib/server/chromium/crAccessibility.js +0 -263
  168. package/lib/server/firefox/ffAccessibility.js +0 -238
  169. package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
  170. package/lib/server/webkit/wkAccessibility.js +0 -237
  171. package/lib/server/webkit/wsl/webkit-wsl-transport-client.js +0 -74
  172. package/lib/server/webkit/wsl/webkit-wsl-transport-server.js +0 -113
  173. package/lib/vite/recorder/assets/codeMirrorModule-RJCXzfmE.js +0 -24
  174. package/lib/vite/recorder/assets/index-Y-X2TGJv.js +0 -193
  175. package/lib/vite/traceViewer/assets/codeMirrorModule-rbQPefq7.js +0 -24
  176. package/lib/vite/traceViewer/assets/defaultSettingsView-CLbol9XR.js +0 -265
  177. package/lib/vite/traceViewer/defaultSettingsView.TQ8_7ybu.css +0 -1
  178. package/lib/vite/traceViewer/index.I8N9v4jT.css +0 -1
  179. package/lib/vite/traceViewer/index.zIVi6mN9.js +0 -2
  180. package/lib/vite/traceViewer/uiMode.B_CpmIpF.js +0 -5
@@ -35,22 +35,20 @@ __export(network_exports, {
35
35
  createProxyAgent: () => createProxyAgent,
36
36
  fetchData: () => fetchData,
37
37
  httpRequest: () => httpRequest,
38
- isURLAvailable: () => isURLAvailable
38
+ isURLAvailable: () => isURLAvailable,
39
+ startHttpServer: () => startHttpServer
39
40
  });
40
41
  module.exports = __toCommonJS(network_exports);
41
42
  var import_http = __toESM(require("http"));
42
43
  var import_http2 = __toESM(require("http2"));
43
44
  var import_https = __toESM(require("https"));
44
- var import_url = __toESM(require("url"));
45
45
  var import_utilsBundle = require("../../utilsBundle");
46
46
  var import_happyEyeballs = require("./happyEyeballs");
47
47
  var import_manualPromise = require("../../utils/isomorphic/manualPromise");
48
48
  const NET_DEFAULT_TIMEOUT = 3e4;
49
49
  function httpRequest(params, onResponse, onError) {
50
- const parsedUrl = import_url.default.parse(params.url);
51
- let options = {
52
- ...parsedUrl,
53
- agent: parsedUrl.protocol === "https:" ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent,
50
+ let url = new URL(params.url);
51
+ const options = {
54
52
  method: params.method || "GET",
55
53
  headers: params.headers
56
54
  };
@@ -58,21 +56,16 @@ function httpRequest(params, onResponse, onError) {
58
56
  options.rejectUnauthorized = params.rejectUnauthorized;
59
57
  const proxyURL = (0, import_utilsBundle.getProxyForUrl)(params.url);
60
58
  if (proxyURL) {
61
- const parsedProxyURL = import_url.default.parse(proxyURL);
59
+ const parsedProxyURL = normalizeProxyURL(proxyURL);
62
60
  if (params.url.startsWith("http:")) {
63
- options = {
64
- path: parsedUrl.href,
65
- host: parsedProxyURL.hostname,
66
- port: parsedProxyURL.port,
67
- headers: options.headers,
68
- method: options.method
69
- };
61
+ parsedProxyURL.pathname = url.toString();
62
+ url = parsedProxyURL;
70
63
  } else {
71
- parsedProxyURL.secureProxy = parsedProxyURL.protocol === "https:";
72
64
  options.agent = new import_utilsBundle.HttpsProxyAgent(parsedProxyURL);
73
65
  options.rejectUnauthorized = false;
74
66
  }
75
67
  }
68
+ options.agent ??= url.protocol === "https:" ? import_happyEyeballs.httpsHappyEyeballsAgent : import_happyEyeballs.httpHappyEyeballsAgent;
76
69
  let cancelRequest;
77
70
  const requestCallback = (res) => {
78
71
  const statusCode = res.statusCode || 0;
@@ -83,7 +76,7 @@ function httpRequest(params, onResponse, onError) {
83
76
  onResponse(res);
84
77
  }
85
78
  };
86
- const request = options.protocol === "https:" ? import_https.default.request(options, requestCallback) : import_http.default.request(options, requestCallback);
79
+ const request = url.protocol === "https:" ? import_https.default.request(url, options, requestCallback) : import_http.default.request(url, options, requestCallback);
87
80
  request.on("error", onError);
88
81
  if (params.socketTimeout !== void 0) {
89
82
  request.setTimeout(params.socketTimeout, () => {
@@ -122,7 +115,7 @@ async function fetchData(progress, params, onError) {
122
115
  throw error;
123
116
  }
124
117
  }
125
- function shouldBypassProxy(url2, bypass) {
118
+ function shouldBypassProxy(url, bypass) {
126
119
  if (!bypass)
127
120
  return false;
128
121
  const domains = bypass.split(",").map((s) => {
@@ -131,30 +124,36 @@ function shouldBypassProxy(url2, bypass) {
131
124
  s = "." + s;
132
125
  return s;
133
126
  });
134
- const domain = "." + url2.hostname;
127
+ const domain = "." + url.hostname;
135
128
  return domains.some((d) => domain.endsWith(d));
136
129
  }
130
+ function normalizeProxyURL(proxy) {
131
+ proxy = proxy.trim();
132
+ if (!/^\w+:\/\//.test(proxy))
133
+ proxy = "http://" + proxy;
134
+ return new URL(proxy);
135
+ }
137
136
  function createProxyAgent(proxy, forUrl) {
138
137
  if (!proxy)
139
138
  return;
140
139
  if (forUrl && proxy.bypass && shouldBypassProxy(forUrl, proxy.bypass))
141
140
  return;
142
- let proxyServer = proxy.server.trim();
143
- if (!/^\w+:\/\//.test(proxyServer))
144
- proxyServer = "http://" + proxyServer;
145
- const proxyOpts = import_url.default.parse(proxyServer);
146
- if (proxyOpts.protocol?.startsWith("socks")) {
147
- return new import_utilsBundle.SocksProxyAgent({
148
- host: proxyOpts.hostname,
149
- port: proxyOpts.port || void 0
150
- });
141
+ const proxyURL = normalizeProxyURL(proxy.server);
142
+ if (proxyURL.protocol?.startsWith("socks")) {
143
+ if (proxyURL.protocol === "socks5:")
144
+ proxyURL.protocol = "socks5h:";
145
+ else if (proxyURL.protocol === "socks4:")
146
+ proxyURL.protocol = "socks4a:";
147
+ return new import_utilsBundle.SocksProxyAgent(proxyURL);
148
+ }
149
+ if (proxy.username) {
150
+ proxyURL.username = proxy.username;
151
+ proxyURL.password = proxy.password || "";
151
152
  }
152
- if (proxy.username)
153
- proxyOpts.auth = `${proxy.username}:${proxy.password || ""}`;
154
153
  if (forUrl && ["ws:", "wss:"].includes(forUrl.protocol)) {
155
- return new import_utilsBundle.HttpsProxyAgent(proxyOpts);
154
+ return new import_utilsBundle.HttpsProxyAgent(proxyURL);
156
155
  }
157
- return new import_utilsBundle.HttpsProxyAgent(proxyOpts);
156
+ return new import_utilsBundle.HttpsProxyAgent(proxyURL);
158
157
  }
159
158
  function createHttpServer(...args) {
160
159
  const server = import_http.default.createServer(...args);
@@ -171,20 +170,35 @@ function createHttp2Server(...args) {
171
170
  decorateServer(server);
172
171
  return server;
173
172
  }
174
- async function isURLAvailable(url2, ignoreHTTPSErrors, onLog, onStdErr) {
175
- let statusCode = await httpStatusCode(url2, ignoreHTTPSErrors, onLog, onStdErr);
176
- if (statusCode === 404 && url2.pathname === "/") {
177
- const indexUrl = new URL(url2);
173
+ async function startHttpServer(server, options) {
174
+ const { host = "localhost", port = 0 } = options;
175
+ const errorPromise = new import_manualPromise.ManualPromise();
176
+ const errorListener = (error) => errorPromise.reject(error);
177
+ server.on("error", errorListener);
178
+ try {
179
+ server.listen(port, host);
180
+ await Promise.race([
181
+ new Promise((cb) => server.once("listening", cb)),
182
+ errorPromise
183
+ ]);
184
+ } finally {
185
+ server.removeListener("error", errorListener);
186
+ }
187
+ }
188
+ async function isURLAvailable(url, ignoreHTTPSErrors, onLog, onStdErr) {
189
+ let statusCode = await httpStatusCode(url, ignoreHTTPSErrors, onLog, onStdErr);
190
+ if (statusCode === 404 && url.pathname === "/") {
191
+ const indexUrl = new URL(url);
178
192
  indexUrl.pathname = "/index.html";
179
193
  statusCode = await httpStatusCode(indexUrl, ignoreHTTPSErrors, onLog, onStdErr);
180
194
  }
181
195
  return statusCode >= 200 && statusCode < 404;
182
196
  }
183
- async function httpStatusCode(url2, ignoreHTTPSErrors, onLog, onStdErr) {
197
+ async function httpStatusCode(url, ignoreHTTPSErrors, onLog, onStdErr) {
184
198
  return new Promise((resolve) => {
185
- onLog?.(`HTTP GET: ${url2}`);
199
+ onLog?.(`HTTP GET: ${url}`);
186
200
  httpRequest({
187
- url: url2.toString(),
201
+ url: url.toString(),
188
202
  headers: { Accept: "*/*" },
189
203
  rejectUnauthorized: !ignoreHTTPSErrors
190
204
  }, (res) => {
@@ -195,7 +209,7 @@ async function httpStatusCode(url2, ignoreHTTPSErrors, onLog, onStdErr) {
195
209
  }, (error) => {
196
210
  if (error.code === "DEPTH_ZERO_SELF_SIGNED_CERT")
197
211
  onStdErr?.(`[WebServer] Self-signed certificate detected. Try adding ignoreHTTPSErrors: true to config.webServer.`);
198
- onLog?.(`Error while checking if ${url2} is available: ${error.message}`);
212
+ onLog?.(`Error while checking if ${url} is available: ${error.message}`);
199
213
  resolve(0);
200
214
  });
201
215
  });
@@ -223,5 +237,6 @@ function decorateServer(server) {
223
237
  createProxyAgent,
224
238
  fetchData,
225
239
  httpRequest,
226
- isURLAvailable
240
+ isURLAvailable,
241
+ startHttpServer
227
242
  });
@@ -42,6 +42,7 @@ var import_utilsBundle = require("../../utilsBundle");
42
42
  var import_debugLogger = require("./debugLogger");
43
43
  var import_zones = require("./zones");
44
44
  var import_debug = require("./debug");
45
+ var import_mcpBundle = require("../../mcpBundle");
45
46
  const pipelineAsync = util.promisify(import_stream.pipeline);
46
47
  class NodeZone {
47
48
  constructor(zone) {
@@ -105,6 +106,11 @@ const nodePlatform = {
105
106
  streamWritable: (channel) => {
106
107
  return new WritableStreamImpl(channel);
107
108
  },
109
+ zodToJsonSchema: (schema) => {
110
+ if ("_zod" in schema)
111
+ return import_mcpBundle.z.toJSONSchema(schema);
112
+ return (0, import_mcpBundle.zodToJsonSchema)(schema);
113
+ },
108
114
  zones: {
109
115
  current: () => new NodeZone((0, import_zones.currentZone)()),
110
116
  empty: new NodeZone(import_zones.emptyZone)
@@ -21,31 +21,26 @@ __export(videoRecorder_exports, {
21
21
  VideoRecorder: () => VideoRecorder
22
22
  });
23
23
  module.exports = __toCommonJS(videoRecorder_exports);
24
- var import_utils = require("../../utils");
25
- var import_page = require("../page");
26
- var import_processLauncher = require("../utils/processLauncher");
24
+ var import_utils = require("../utils");
25
+ var import_processLauncher = require("./utils/processLauncher");
27
26
  const fps = 25;
28
27
  class VideoRecorder {
29
- constructor(page, ffmpegPath) {
28
+ constructor(ffmpegPath, options) {
30
29
  this._process = null;
31
30
  this._gracefullyClose = null;
32
31
  this._lastWritePromise = Promise.resolve();
33
- this._lastFrameTimestamp = 0;
34
- this._lastFrameBuffer = null;
35
- this._lastWriteTimestamp = 0;
32
+ this._firstFrameTimestamp = 0;
33
+ this._lastFrame = null;
34
+ this._lastWriteNodeTime = 0;
36
35
  this._frameQueue = [];
37
36
  this._isStopped = false;
38
37
  this._ffmpegPath = ffmpegPath;
39
- page.on(import_page.Page.Events.ScreencastFrame, (frame) => this.writeFrame(frame.buffer, frame.frameSwapWallTime / 1e3));
40
- }
41
- static async launch(page, ffmpegPath, options) {
42
38
  if (!options.outputFile.endsWith(".webm"))
43
39
  throw new Error("File must have .webm extension");
44
- const recorder = new VideoRecorder(page, ffmpegPath);
45
- await recorder._launch(options);
46
- return recorder;
40
+ this._launchPromise = this._launch(options).catch((e) => e);
47
41
  }
48
42
  async _launch(options) {
43
+ await (0, import_utils.mkdirIfNeeded)(options.outputFile);
49
44
  const w = options.width;
50
45
  const h = options.height;
51
46
  const args = `-loglevel error -f image2pipe -avioflags direct -fpsprobesize 0 -probesize 32 -analyzeduration 0 -c:v mjpeg -i pipe:0 -y -an -r ${fps} -c:v vp8 -qmin 0 -qmax 50 -crf 8 -deadline realtime -speed 8 -b:v 1M -threads 1 -vf pad=${w}:${h}:0:0:gray,crop=${w}:${h}:0:0`.split(" ");
@@ -74,19 +69,27 @@ class VideoRecorder {
74
69
  this._gracefullyClose = gracefullyClose;
75
70
  }
76
71
  writeFrame(frame, timestamp) {
72
+ this._launchPromise.then((error) => {
73
+ if (error)
74
+ return;
75
+ this._writeFrame(frame, timestamp);
76
+ });
77
+ }
78
+ _writeFrame(frame, timestamp) {
77
79
  (0, import_utils.assert)(this._process);
78
80
  if (this._isStopped)
79
81
  return;
80
- if (this._lastFrameBuffer) {
81
- const durationSec = timestamp - this._lastFrameTimestamp;
82
- const repeatCount = Math.max(1, Math.round(fps * durationSec));
82
+ if (!this._firstFrameTimestamp)
83
+ this._firstFrameTimestamp = timestamp;
84
+ const frameNumber = Math.floor((timestamp - this._firstFrameTimestamp) * fps);
85
+ if (this._lastFrame) {
86
+ const repeatCount = frameNumber - this._lastFrame.frameNumber;
83
87
  for (let i = 0; i < repeatCount; ++i)
84
- this._frameQueue.push(this._lastFrameBuffer);
88
+ this._frameQueue.push(this._lastFrame.buffer);
85
89
  this._lastWritePromise = this._lastWritePromise.then(() => this._sendFrames());
86
90
  }
87
- this._lastFrameBuffer = frame;
88
- this._lastFrameTimestamp = timestamp;
89
- this._lastWriteTimestamp = (0, import_utils.monotonicTime)();
91
+ this._lastFrame = { buffer: frame, timestamp, frameNumber };
92
+ this._lastWriteNodeTime = (0, import_utils.monotonicTime)();
90
93
  }
91
94
  async _sendFrames() {
92
95
  while (this._frameQueue.length)
@@ -99,12 +102,20 @@ class VideoRecorder {
99
102
  });
100
103
  }
101
104
  async stop() {
102
- if (this._isStopped)
105
+ const error = await this._launchPromise;
106
+ if (error)
107
+ throw error;
108
+ if (this._isStopped || !this._lastFrame)
103
109
  return;
104
- this.writeFrame(Buffer.from([]), this._lastFrameTimestamp + ((0, import_utils.monotonicTime)() - this._lastWriteTimestamp) / 1e3);
110
+ const addTime = Math.max(((0, import_utils.monotonicTime)() - this._lastWriteNodeTime) / 1e3, 1);
111
+ this._writeFrame(Buffer.from([]), this._lastFrame.timestamp + addTime);
105
112
  this._isStopped = true;
106
- await this._lastWritePromise;
107
- await this._gracefullyClose();
113
+ try {
114
+ await this._lastWritePromise;
115
+ await this._gracefullyClose();
116
+ } catch (e) {
117
+ import_utils.debugLogger.log("error", `ffmpeg failed to stop: ${String(e)}`);
118
+ }
108
119
  }
109
120
  }
110
121
  // Annotate the CommonJS export names for ESM import in node:
@@ -38,7 +38,6 @@ var import_ascii = require("../utils/ascii");
38
38
  var import_browserType = require("../browserType");
39
39
  var import_wkBrowser = require("../webkit/wkBrowser");
40
40
  var import_spawnAsync = require("../utils/spawnAsync");
41
- var import_registry = require("../registry");
42
41
  class WebKit extends import_browserType.BrowserType {
43
42
  constructor(parent) {
44
43
  super(parent, "webkit");
@@ -49,16 +48,13 @@ class WebKit extends import_browserType.BrowserType {
49
48
  amendEnvironment(env, userDataDir, isPersistent, options) {
50
49
  return {
51
50
  ...env,
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
51
+ CURL_COOKIE_JAR_PATH: process.platform === "win32" && isPersistent ? import_path.default.join(userDataDir, "cookiejar.db") : void 0
54
52
  };
55
53
  }
56
- doRewriteStartupLog(error) {
57
- if (!error.logs)
58
- return error;
59
- if (error.logs.includes("Failed to open display") || error.logs.includes("cannot open display"))
60
- error.logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
61
- return error;
54
+ doRewriteStartupLog(logs) {
55
+ if (logs.includes("Failed to open display") || logs.includes("cannot open display"))
56
+ logs = "\n" + (0, import_ascii.wrapInASCIIBox)(import_browserType.kNoXServerRunningError, 1);
57
+ return logs;
62
58
  }
63
59
  attemptToGracefullyCloseBrowser(transport) {
64
60
  transport.send({ method: "Playwright.close", params: {}, id: import_wkConnection.kBrowserCloseMessageId });
@@ -71,13 +67,6 @@ class WebKit extends import_browserType.BrowserType {
71
67
  if (args.find((arg) => !arg.startsWith("-")))
72
68
  throw new Error("Arguments can not specify page to be opened");
73
69
  const webkitArguments = ["--inspector-pipe"];
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
70
  if (process.platform === "win32" && options.channel !== "webkit-wsl")
82
71
  webkitArguments.push("--disable-accelerated-compositing");
83
72
  if (headless)
@@ -56,7 +56,6 @@ class WKBrowser extends import_browser.Browser {
56
56
  this._browserSession.on("Playwright.downloadCreated", this._onDownloadCreated.bind(this));
57
57
  this._browserSession.on("Playwright.downloadFilenameSuggested", this._onDownloadFilenameSuggested.bind(this));
58
58
  this._browserSession.on("Playwright.downloadFinished", this._onDownloadFinished.bind(this));
59
- this._browserSession.on("Playwright.screencastFinished", this._onScreencastFinished.bind(this));
60
59
  this._browserSession.on(import_wkConnection.kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this));
61
60
  }
62
61
  static async connect(parent, transport, options) {
@@ -79,7 +78,7 @@ class WKBrowser extends import_browser.Browser {
79
78
  wkPage.didClose();
80
79
  this._wkPages.clear();
81
80
  for (const video of this._idToVideo.values())
82
- video.artifact.reportFinished(new import_errors.TargetClosedError());
81
+ video.artifact.reportFinished(new import_errors.TargetClosedError(this.closeReason()));
83
82
  this._idToVideo.clear();
84
83
  this._didClose();
85
84
  }
@@ -131,9 +130,6 @@ class WKBrowser extends import_browser.Browser {
131
130
  _onDownloadFinished(payload) {
132
131
  this._downloadFinished(payload.uuid, payload.error);
133
132
  }
134
- _onScreencastFinished(payload) {
135
- this._takeVideo(payload.screencastId)?.reportFinished();
136
- }
137
133
  _onPageProxyCreated(event) {
138
134
  const pageProxyId = event.pageProxyId;
139
135
  let context = null;
@@ -315,7 +311,7 @@ class WKBrowserContext extends import_browserContext.BrowserContext {
315
311
  }
316
312
  async doClose(reason) {
317
313
  if (!this._browserContextId) {
318
- await Promise.all(this._wkPages().map((wkPage) => wkPage._stopVideo()));
314
+ await Promise.all(this._wkPages().map((wkPage) => wkPage._page.screencast.stopVideoRecording()));
319
315
  await this._browser.close({ reason });
320
316
  } else {
321
317
  await this._browser._browserSession.send("Playwright.deleteContext", { browserContextId: this._browserContextId });
@@ -89,11 +89,6 @@ class WKSession extends import_events.EventEmitter {
89
89
  this.connection = connection;
90
90
  this.sessionId = sessionId;
91
91
  this._rawSend = rawSend;
92
- this.on = super.on;
93
- this.off = super.removeListener;
94
- this.addListener = super.addListener;
95
- this.removeListener = super.removeListener;
96
- this.once = super.once;
97
92
  }
98
93
  async send(method, params) {
99
94
  if (this._crashed || this._disposed || this.connection._browserDisconnectedLogs)
@@ -134,7 +129,7 @@ class WKSession extends import_events.EventEmitter {
134
129
  callback.resolve(object.result);
135
130
  }
136
131
  } else if (object.id && !object.error) {
137
- (0, import_utils.assert)(this.isDisposed());
132
+ (0, import_utils.assert)(this.isDisposed(), JSON.stringify(object));
138
133
  } else {
139
134
  Promise.resolve().then(() => this.emit(object.method, object.params));
140
135
  }
@@ -54,7 +54,7 @@ class WKInterceptableRequest {
54
54
  constructor(session, frame, event, redirectedFrom, documentId) {
55
55
  this._session = session;
56
56
  this._requestId = event.requestId;
57
- const resourceType = event.type ? event.type.toLowerCase() : redirectedFrom ? redirectedFrom.request.resourceType() : "other";
57
+ const resourceType = event.type ? toResourceType(event.type) : redirectedFrom ? redirectedFrom.request.resourceType() : "other";
58
58
  let postDataBuffer = null;
59
59
  this._timestamp = event.timestamp;
60
60
  this._wallTime = event.walltime * 1e3;
@@ -162,6 +162,34 @@ function wkMillisToRoundishMillis(value) {
162
162
  }
163
163
  return (value * 1e3 | 0) / 1e3;
164
164
  }
165
+ function toResourceType(type) {
166
+ switch (type) {
167
+ case "Document":
168
+ return "document";
169
+ case "StyleSheet":
170
+ return "stylesheet";
171
+ case "Image":
172
+ return "image";
173
+ case "Font":
174
+ return "font";
175
+ case "Script":
176
+ return "script";
177
+ case "XHR":
178
+ return "xhr";
179
+ case "Fetch":
180
+ return "fetch";
181
+ case "Ping":
182
+ return "ping";
183
+ case "Beacon":
184
+ return "beacon";
185
+ case "WebSocket":
186
+ return "websocket";
187
+ case "EventSource":
188
+ return "eventsource";
189
+ default:
190
+ return "other";
191
+ }
192
+ }
165
193
  // Annotate the CommonJS export names for ESM import in node:
166
194
  0 && (module.exports = {
167
195
  WKInterceptableRequest,