patchright-core 1.52.4 → 1.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/ThirdPartyNotices.txt +65 -123
  2. package/bin/reinstall_chrome_beta_mac.sh +1 -1
  3. package/bin/reinstall_chrome_stable_mac.sh +1 -1
  4. package/bin/reinstall_msedge_beta_mac.sh +1 -1
  5. package/bin/reinstall_msedge_dev_mac.sh +1 -1
  6. package/bin/reinstall_msedge_stable_mac.sh +1 -1
  7. package/browsers.json +14 -14
  8. package/index.js +1 -1
  9. package/lib/androidServerImpl.js +4 -2
  10. package/lib/browserServerImpl.js +47 -12
  11. package/lib/cli/program.js +116 -50
  12. package/lib/cli/programWithTestStub.js +1 -1
  13. package/lib/client/android.js +30 -34
  14. package/lib/client/browser.js +54 -17
  15. package/lib/client/browserContext.js +67 -71
  16. package/lib/client/browserType.js +25 -34
  17. package/lib/client/channelOwner.js +20 -24
  18. package/lib/client/connection.js +6 -10
  19. package/lib/client/electron.js +8 -3
  20. package/lib/client/elementHandle.js +18 -21
  21. package/lib/client/fetch.js +5 -3
  22. package/lib/client/frame.js +57 -35
  23. package/lib/client/input.js +3 -1
  24. package/lib/client/jsHandle.js +4 -0
  25. package/lib/client/localUtils.js +0 -1
  26. package/lib/client/locator.js +32 -28
  27. package/lib/client/network.js +5 -12
  28. package/lib/client/page.js +32 -32
  29. package/lib/client/playwright.js +6 -16
  30. package/lib/client/selectors.js +18 -38
  31. package/lib/client/timeoutSettings.js +12 -8
  32. package/lib/client/tracing.js +24 -20
  33. package/lib/client/waiter.js +2 -2
  34. package/lib/client/webSocket.js +4 -22
  35. package/lib/generated/bindingsControllerSource.js +28 -0
  36. package/lib/generated/clockSource.js +1 -1
  37. package/lib/generated/injectedScriptSource.js +1 -1
  38. package/lib/generated/pollingRecorderSource.js +1 -1
  39. package/lib/generated/storageScriptSource.js +28 -0
  40. package/lib/generated/utilityScriptSource.js +1 -1
  41. package/lib/generated/webSocketMockSource.js +12 -50
  42. package/lib/inProcessFactory.js +9 -6
  43. package/lib/outofprocess.js +0 -2
  44. package/lib/protocol/validator.js +423 -346
  45. package/lib/protocol/validatorPrimitives.js +18 -4
  46. package/lib/remote/playwrightConnection.js +29 -166
  47. package/lib/remote/playwrightServer.js +233 -35
  48. package/lib/server/android/android.js +97 -83
  49. package/lib/server/android/backendAdb.js +0 -2
  50. package/lib/server/bidi/bidiBrowser.js +139 -73
  51. package/lib/server/bidi/bidiChromium.js +23 -22
  52. package/lib/server/bidi/bidiExecutionContext.js +2 -1
  53. package/lib/server/bidi/bidiFirefox.js +17 -14
  54. package/lib/server/bidi/bidiInput.js +22 -22
  55. package/lib/server/bidi/bidiNetworkManager.js +8 -11
  56. package/lib/server/bidi/bidiPage.js +42 -86
  57. package/lib/server/bidi/third_party/bidiProtocol.js +5 -133
  58. package/lib/server/bidi/third_party/bidiProtocolCore.js +179 -0
  59. package/lib/server/{dispatchers/selectorsDispatcher.js → bidi/third_party/bidiProtocolPermissions.js} +20 -18
  60. package/lib/server/browser.js +30 -21
  61. package/lib/server/browserContext.js +203 -165
  62. package/lib/server/browserType.js +109 -107
  63. package/lib/server/chromium/chromium.js +84 -69
  64. package/lib/server/chromium/chromiumSwitches.js +13 -20
  65. package/lib/server/chromium/crBrowser.js +74 -40
  66. package/lib/server/chromium/crConnection.js +8 -9
  67. package/lib/server/chromium/crCoverage.js +11 -8
  68. package/lib/server/chromium/crDragDrop.js +25 -20
  69. package/lib/server/chromium/crExecutionContext.js +2 -1
  70. package/lib/server/chromium/crInput.js +32 -29
  71. package/lib/server/chromium/crNetworkManager.js +45 -33
  72. package/lib/server/chromium/crPage.js +98 -73
  73. package/lib/server/chromium/crServiceWorker.js +13 -18
  74. package/lib/server/chromium/videoRecorder.js +10 -18
  75. package/lib/server/clock.js +51 -39
  76. package/lib/server/codegen/csharp.js +10 -5
  77. package/lib/server/codegen/java.js +1 -1
  78. package/lib/server/codegen/javascript.js +1 -1
  79. package/lib/server/codegen/jsonl.js +2 -1
  80. package/lib/server/codegen/language.js +22 -1
  81. package/lib/server/codegen/languages.js +4 -4
  82. package/lib/server/codegen/python.js +1 -1
  83. package/lib/server/cookieStore.js +3 -1
  84. package/lib/server/debugController.js +105 -71
  85. package/lib/server/debugger.js +6 -23
  86. package/lib/server/deviceDescriptorsSource.json +237 -127
  87. package/lib/server/dialog.js +50 -6
  88. package/lib/server/dispatchers/androidDispatcher.js +77 -62
  89. package/lib/server/dispatchers/artifactDispatcher.js +18 -18
  90. package/lib/server/dispatchers/browserContextDispatcher.js +141 -91
  91. package/lib/server/dispatchers/browserDispatcher.js +55 -88
  92. package/lib/server/dispatchers/browserTypeDispatcher.js +18 -9
  93. package/lib/server/dispatchers/cdpSessionDispatcher.js +4 -4
  94. package/lib/server/dispatchers/debugControllerDispatcher.js +12 -21
  95. package/lib/server/dispatchers/dialogDispatcher.js +4 -4
  96. package/lib/server/dispatchers/dispatcher.js +78 -53
  97. package/lib/server/dispatchers/electronDispatcher.js +19 -20
  98. package/lib/server/dispatchers/elementHandlerDispatcher.js +83 -93
  99. package/lib/server/dispatchers/frameDispatcher.js +99 -102
  100. package/lib/server/dispatchers/jsHandleDispatcher.js +21 -16
  101. package/lib/server/dispatchers/jsonPipeDispatcher.js +4 -4
  102. package/lib/server/dispatchers/localUtilsDispatcher.js +53 -59
  103. package/lib/server/dispatchers/networkDispatchers.js +41 -35
  104. package/lib/server/dispatchers/pageDispatcher.js +156 -107
  105. package/lib/server/dispatchers/playwrightDispatcher.js +37 -25
  106. package/lib/server/dispatchers/streamDispatcher.js +15 -8
  107. package/lib/server/dispatchers/tracingDispatcher.js +22 -13
  108. package/lib/server/dispatchers/webSocketRouteDispatcher.js +46 -35
  109. package/lib/server/dispatchers/writableStreamDispatcher.js +16 -10
  110. package/lib/server/dom.js +198 -266
  111. package/lib/server/download.js +3 -3
  112. package/lib/server/electron/electron.js +96 -103
  113. package/lib/server/electron/loader.js +1 -1
  114. package/lib/server/fetch.js +22 -41
  115. package/lib/server/fileUploadUtils.js +1 -1
  116. package/lib/server/firefox/ffBrowser.js +79 -55
  117. package/lib/server/firefox/ffExecutionContext.js +2 -1
  118. package/lib/server/firefox/ffInput.js +23 -23
  119. package/lib/server/firefox/ffNetworkManager.js +8 -6
  120. package/lib/server/firefox/ffPage.js +39 -36
  121. package/lib/server/firefox/firefox.js +9 -10
  122. package/lib/server/frameSelectors.js +65 -22
  123. package/lib/server/frames.js +516 -544
  124. package/lib/server/har/harRecorder.js +1 -1
  125. package/lib/server/har/harTracer.js +4 -2
  126. package/lib/server/helper.js +3 -7
  127. package/lib/server/index.js +0 -3
  128. package/lib/server/input.js +47 -54
  129. package/lib/server/instrumentation.js +8 -14
  130. package/lib/server/javascript.js +9 -17
  131. package/lib/server/launchApp.js +48 -30
  132. package/lib/server/localUtils.js +45 -38
  133. package/lib/server/network.js +44 -10
  134. package/lib/server/page.js +233 -178
  135. package/lib/server/pageBinding.js +6 -7
  136. package/lib/server/playwright.js +4 -14
  137. package/lib/server/progress.js +57 -49
  138. package/lib/server/recorder/recorderApp.js +298 -95
  139. package/lib/server/recorder/recorderRunner.js +23 -24
  140. package/lib/server/recorder/recorderSignalProcessor.js +83 -0
  141. package/lib/server/recorder/recorderUtils.js +67 -10
  142. package/lib/server/recorder.js +284 -146
  143. package/lib/server/registry/index.js +83 -48
  144. package/lib/server/registry/nativeDeps.js +175 -0
  145. package/lib/server/registry/oopDownloadBrowserMain.js +1 -1
  146. package/lib/server/screenshotter.js +84 -83
  147. package/lib/server/selectors.js +12 -12
  148. package/lib/server/socksClientCertificatesInterceptor.js +198 -136
  149. package/lib/server/trace/recorder/snapshotter.js +12 -19
  150. package/lib/server/trace/recorder/tracing.js +36 -27
  151. package/lib/server/trace/viewer/traceViewer.js +11 -20
  152. package/lib/server/transport.js +20 -22
  153. package/lib/server/utils/comparators.js +2 -2
  154. package/lib/server/utils/debug.js +3 -8
  155. package/lib/server/utils/debugLogger.js +8 -0
  156. package/lib/server/utils/hostPlatform.js +3 -1
  157. package/lib/server/utils/network.js +35 -25
  158. package/lib/server/utils/nodePlatform.js +1 -1
  159. package/lib/server/utils/processLauncher.js +4 -1
  160. package/lib/server/utils/wsServer.js +11 -17
  161. package/lib/server/webkit/webkit.js +5 -2
  162. package/lib/server/webkit/wkBrowser.js +51 -28
  163. package/lib/server/webkit/wkExecutionContext.js +2 -1
  164. package/lib/server/webkit/wkInput.js +25 -25
  165. package/lib/server/webkit/wkInterceptableRequest.js +1 -1
  166. package/lib/server/webkit/wkPage.js +80 -59
  167. package/lib/server/webkit/wkProvisionalPage.js +1 -1
  168. package/lib/server/webkit/wkWorkers.js +7 -7
  169. package/lib/utils/isomorphic/ariaSnapshot.js +13 -7
  170. package/lib/utils/isomorphic/cssParser.js +1 -2
  171. package/lib/utils/isomorphic/locatorGenerators.js +18 -0
  172. package/lib/utils/isomorphic/manualPromise.js +1 -2
  173. package/lib/utils/isomorphic/mimeType.js +1 -2
  174. package/lib/utils/isomorphic/multimap.js +1 -2
  175. package/lib/utils/isomorphic/oldUtilityScriptSerializers.js +248 -0
  176. package/lib/utils/isomorphic/protocolFormatter.js +78 -0
  177. package/lib/utils/isomorphic/protocolMetainfo.js +318 -0
  178. package/lib/utils/isomorphic/selectorParser.js +3 -4
  179. package/lib/utils/isomorphic/stringUtils.js +3 -24
  180. package/lib/utils/isomorphic/time.js +9 -4
  181. package/lib/utils/isomorphic/timeoutRunner.js +3 -4
  182. package/lib/utils/isomorphic/traceUtils.js +2 -3
  183. package/lib/utils/isomorphic/urlMatch.js +21 -7
  184. package/lib/utils/isomorphic/utilityScriptSerializers.js +208 -205
  185. package/lib/utils.js +8 -2
  186. package/lib/utilsBundleImpl/index.js +160 -150
  187. package/lib/vite/htmlReport/index.html +17 -17
  188. package/lib/vite/recorder/assets/{codeMirrorModule-CXVeovup.js → codeMirrorModule-DzQ0k89p.js} +1 -1
  189. package/lib/vite/recorder/assets/{index-eHBmevrY.css → index-CI4HQ-Zb.css} +1 -1
  190. package/lib/vite/recorder/assets/index-D7C7daHH.js +184 -0
  191. package/lib/vite/recorder/index.html +3 -3
  192. package/lib/vite/traceViewer/assets/{codeMirrorModule-_GLjJL-7.js → codeMirrorModule-Di48jgWx.js} +1 -1
  193. package/lib/vite/traceViewer/assets/defaultSettingsView-szBn8781.js +256 -0
  194. package/lib/vite/traceViewer/defaultSettingsView.DVJHpiGt.css +1 -0
  195. package/lib/vite/traceViewer/index.BFsek2M6.css +1 -0
  196. package/lib/vite/traceViewer/index.DQvXoPLL.js +2 -0
  197. package/lib/vite/traceViewer/index.html +6 -6
  198. package/lib/vite/traceViewer/sw.bundle.js +3 -3
  199. package/lib/vite/traceViewer/uiMode.dBV3oN9h.js +5 -0
  200. package/lib/vite/traceViewer/uiMode.html +4 -4
  201. package/lib/zipBundleImpl.js +4 -4
  202. package/package.json +1 -1
  203. package/types/protocol.d.ts +712 -107
  204. package/types/types.d.ts +148 -37
  205. package/lib/generated/consoleApiSource.js +0 -28
  206. package/lib/protocol/debug.js +0 -211
  207. package/lib/server/recorder/contextRecorder.js +0 -286
  208. package/lib/server/recorder/recorderCollection.js +0 -116
  209. package/lib/server/recorder/recorderFrontend.js +0 -16
  210. package/lib/server/storageScript.js +0 -154
  211. package/lib/server/timeoutSettings.js +0 -89
  212. package/lib/utils/isomorphic/builtins.js +0 -86
  213. package/lib/vite/recorder/assets/index-BsWQsSGl.js +0 -184
  214. package/lib/vite/traceViewer/assets/defaultSettingsView-DtCQiGHe.js +0 -265
  215. package/lib/vite/traceViewer/defaultSettingsView.QdHITyLI.css +0 -1
  216. package/lib/vite/traceViewer/index.CFOW-Ezb.css +0 -1
  217. package/lib/vite/traceViewer/index.cFZzK9RN.js +0 -2
  218. package/lib/vite/traceViewer/uiMode.XVPIqBeS.js +0 -5
@@ -44,6 +44,7 @@ var import_browserContext = require("./browserContext");
44
44
  var import_network = require("./utils/network");
45
45
  var import_debugLogger = require("./utils/debugLogger");
46
46
  var import_happyEyeballs = require("./utils/happyEyeballs");
47
+ var import_utilsBundle = require("../utilsBundle");
47
48
  let dummyServerTlsOptions = void 0;
48
49
  function loadDummyServerCertsIfNeeded() {
49
50
  if (dummyServerTlsOptions)
@@ -51,168 +52,150 @@ function loadDummyServerCertsIfNeeded() {
51
52
  const { cert, key } = (0, import_utils.generateSelfSignedCertificate)();
52
53
  dummyServerTlsOptions = { key, cert };
53
54
  }
54
- class ALPNCache {
55
- constructor() {
56
- this._cache = /* @__PURE__ */ new Map();
57
- }
58
- get(host, port, success) {
59
- const cacheKey = `${host}:${port}`;
60
- {
61
- const result2 = this._cache.get(cacheKey);
62
- if (result2) {
63
- result2.then(success);
64
- return;
65
- }
66
- }
67
- const result = new import_utils.ManualPromise();
68
- this._cache.set(cacheKey, result);
69
- result.then(success);
70
- (0, import_happyEyeballs.createTLSSocket)({
71
- host,
72
- port,
73
- servername: import_net.default.isIP(host) ? void 0 : host,
74
- ALPNProtocols: ["h2", "http/1.1"],
75
- rejectUnauthorized: false
76
- }).then((socket) => {
77
- result.resolve(socket.alpnProtocol || "http/1.1");
78
- socket.end();
79
- }).catch((error) => {
80
- import_debugLogger.debugLogger.log("client-certificates", `ALPN error: ${error.message}`);
81
- result.resolve("http/1.1");
82
- });
83
- }
84
- }
85
55
  class SocksProxyConnection {
86
56
  constructor(socksProxy, uid, host, port) {
87
- this.firstPackageReceived = false;
57
+ this._firstPackageReceived = false;
88
58
  this._closed = false;
89
59
  this.socksProxy = socksProxy;
90
60
  this.uid = uid;
91
61
  this.host = host;
92
62
  this.port = port;
93
- this._targetCloseEventListener = () => {
94
- this.socksProxy._socksProxy.sendSocketEnd({ uid: this.uid });
95
- this.internalTLS?.destroy();
96
- this._dummyServer?.close();
63
+ this._serverCloseEventListener = () => {
64
+ this._browserEncrypted.destroy();
97
65
  };
66
+ this._browserEncrypted = new import_stream.default.Duplex({
67
+ read: () => {
68
+ },
69
+ write: (data, encoding, callback) => {
70
+ this.socksProxy._socksProxy.sendSocketData({ uid: this.uid, data });
71
+ callback();
72
+ },
73
+ destroy: (error, callback) => {
74
+ if (error)
75
+ socksProxy._socksProxy.sendSocketError({ uid: this.uid, error: error.message });
76
+ else
77
+ socksProxy._socksProxy.sendSocketEnd({ uid: this.uid });
78
+ callback();
79
+ }
80
+ });
98
81
  }
99
82
  async connect() {
100
- if (this.socksProxy.proxyAgentFromOptions)
101
- this.target = await this.socksProxy.proxyAgentFromOptions.callback(new import_events.EventEmitter(), { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false });
83
+ const proxyAgent = this.socksProxy.getProxyAgent(this.host, this.port);
84
+ if (proxyAgent)
85
+ this._serverEncrypted = await proxyAgent.callback(new import_events.EventEmitter(), { host: rewriteToLocalhostIfNeeded(this.host), port: this.port, secureEndpoint: false });
102
86
  else
103
- this.target = await (0, import_happyEyeballs.createSocket)(rewriteToLocalhostIfNeeded(this.host), this.port);
104
- this.target.once("close", this._targetCloseEventListener);
105
- this.target.once("error", (error) => this.socksProxy._socksProxy.sendSocketError({ uid: this.uid, error: error.message }));
87
+ this._serverEncrypted = await (0, import_happyEyeballs.createSocket)(rewriteToLocalhostIfNeeded(this.host), this.port);
88
+ this._serverEncrypted.once("close", this._serverCloseEventListener);
89
+ this._serverEncrypted.once("error", (error) => this._browserEncrypted.destroy(error));
106
90
  if (this._closed) {
107
- this.target.destroy();
91
+ this._serverEncrypted.destroy();
108
92
  return;
109
93
  }
110
94
  this.socksProxy._socksProxy.socketConnected({
111
95
  uid: this.uid,
112
- host: this.target.localAddress,
113
- port: this.target.localPort
96
+ host: this._serverEncrypted.localAddress,
97
+ port: this._serverEncrypted.localPort
114
98
  });
115
99
  }
116
100
  onClose() {
117
- this.target.destroy();
118
- this.internalTLS?.destroy();
119
- this._dummyServer?.close();
101
+ this._serverEncrypted.destroy();
102
+ this._browserEncrypted.destroy();
120
103
  this._closed = true;
121
104
  }
122
105
  onData(data) {
123
- if (!this.firstPackageReceived) {
124
- this.firstPackageReceived = true;
106
+ if (!this._firstPackageReceived) {
107
+ this._firstPackageReceived = true;
125
108
  if (data[0] === 22)
126
- this._attachTLSListeners();
109
+ this._establishTlsTunnel(this._browserEncrypted, data);
127
110
  else
128
- this.target.on("data", (data2) => this.socksProxy._socksProxy.sendSocketData({ uid: this.uid, data: data2 }));
111
+ this._establishPlaintextTunnel(this._browserEncrypted);
129
112
  }
130
- if (this.internal)
131
- this.internal.push(data);
132
- else
133
- this.target.write(data);
113
+ this._browserEncrypted.push(data);
134
114
  }
135
- _attachTLSListeners() {
136
- this.internal = new import_stream.default.Duplex({
137
- read: () => {
138
- },
139
- write: (data, encoding, callback) => {
140
- this.socksProxy._socksProxy.sendSocketData({ uid: this.uid, data });
141
- callback();
115
+ _establishPlaintextTunnel(browserEncrypted) {
116
+ browserEncrypted.pipe(this._serverEncrypted);
117
+ this._serverEncrypted.pipe(browserEncrypted);
118
+ }
119
+ _establishTlsTunnel(browserEncrypted, clientHello) {
120
+ const browserALPNProtocols = parseALPNFromClientHello(clientHello) || ["http/1.1"];
121
+ import_debugLogger.debugLogger.log("client-certificates", `Browser->Proxy ${this.host}:${this.port} offers ALPN ${browserALPNProtocols}`);
122
+ const serverDecrypted = import_tls.default.connect({
123
+ socket: this._serverEncrypted,
124
+ host: this.host,
125
+ port: this.port,
126
+ rejectUnauthorized: !this.socksProxy.ignoreHTTPSErrors,
127
+ ALPNProtocols: browserALPNProtocols,
128
+ servername: !import_net.default.isIP(this.host) ? this.host : void 0,
129
+ secureContext: this.socksProxy.secureContextMap.get(new URL(`https://${this.host}:${this.port}`).origin)
130
+ }, async () => {
131
+ const browserDecrypted = await this._upgradeToTLSIfNeeded(browserEncrypted, serverDecrypted.alpnProtocol);
132
+ import_debugLogger.debugLogger.log("client-certificates", `Proxy->Server ${this.host}:${this.port} chooses ALPN ${browserDecrypted.alpnProtocol}`);
133
+ browserDecrypted.pipe(serverDecrypted);
134
+ serverDecrypted.pipe(browserDecrypted);
135
+ const cleanup = (error) => this._serverEncrypted.destroy(error);
136
+ browserDecrypted.once("error", cleanup);
137
+ serverDecrypted.once("error", cleanup);
138
+ browserDecrypted.once("close", cleanup);
139
+ serverDecrypted.once("close", cleanup);
140
+ if (this._closed)
141
+ serverDecrypted.destroy();
142
+ });
143
+ serverDecrypted.once("error", async (error) => {
144
+ import_debugLogger.debugLogger.log("client-certificates", `error when connecting to server: ${error.message.replaceAll("\n", " ")}`);
145
+ this._serverEncrypted.removeListener("close", this._serverCloseEventListener);
146
+ this._serverEncrypted.destroy();
147
+ const browserDecrypted = await this._upgradeToTLSIfNeeded(this._browserEncrypted, serverDecrypted.alpnProtocol);
148
+ const responseBody = (0, import_utils.escapeHTML)("Playwright client-certificate error: " + error.message).replaceAll("\n", " <br>");
149
+ if (browserDecrypted.alpnProtocol === "h2") {
150
+ if ("performServerHandshake" in import_http2.default) {
151
+ const session = import_http2.default.performServerHandshake(browserDecrypted);
152
+ session.on("error", (error2) => {
153
+ this._browserEncrypted.destroy(error2);
154
+ });
155
+ session.once("stream", (stream2) => {
156
+ const cleanup = (error2) => {
157
+ session.close();
158
+ this._browserEncrypted.destroy(error2);
159
+ };
160
+ stream2.once("end", cleanup);
161
+ stream2.once("error", cleanup);
162
+ stream2.respond({
163
+ [import_http2.default.constants.HTTP2_HEADER_CONTENT_TYPE]: "text/html",
164
+ [import_http2.default.constants.HTTP2_HEADER_STATUS]: 503
165
+ });
166
+ stream2.end(responseBody);
167
+ });
168
+ } else {
169
+ this._browserEncrypted.destroy(error);
170
+ }
171
+ } else {
172
+ browserDecrypted.end([
173
+ "HTTP/1.1 503 Internal Server Error",
174
+ "Content-Type: text/html; charset=utf-8",
175
+ "Content-Length: " + Buffer.byteLength(responseBody),
176
+ "",
177
+ responseBody
178
+ ].join("\r\n"));
142
179
  }
143
180
  });
144
- this.socksProxy.alpnCache.get(rewriteToLocalhostIfNeeded(this.host), this.port, (alpnProtocolChosenByServer) => {
145
- import_debugLogger.debugLogger.log("client-certificates", `Proxy->Target ${this.host}:${this.port} chooses ALPN ${alpnProtocolChosenByServer}`);
146
- if (this._closed)
147
- return;
148
- this._dummyServer = import_tls.default.createServer({
181
+ }
182
+ async _upgradeToTLSIfNeeded(socket, alpnProtocol) {
183
+ this._brorwserDecrypted ??= new Promise((resolve, reject) => {
184
+ const dummyServer = import_tls.default.createServer({
149
185
  ...dummyServerTlsOptions,
150
- ALPNProtocols: alpnProtocolChosenByServer === "h2" ? ["h2", "http/1.1"] : ["http/1.1"]
186
+ ALPNProtocols: [alpnProtocol || "http/1.1"]
151
187
  });
152
- this._dummyServer.emit("connection", this.internal);
153
- this._dummyServer.once("secureConnection", (internalTLS) => {
154
- this.internalTLS = internalTLS;
155
- import_debugLogger.debugLogger.log("client-certificates", `Browser->Proxy ${this.host}:${this.port} chooses ALPN ${internalTLS.alpnProtocol}`);
156
- let targetTLS = void 0;
157
- const handleError = (error) => {
158
- import_debugLogger.debugLogger.log("client-certificates", `error when connecting to target: ${error.message.replaceAll("\n", " ")}`);
159
- const responseBody = (0, import_utils.escapeHTML)("Playwright client-certificate error: " + error.message).replaceAll("\n", " <br>");
160
- if (internalTLS?.alpnProtocol === "h2") {
161
- if ("performServerHandshake" in import_http2.default) {
162
- this.target.removeListener("close", this._targetCloseEventListener);
163
- const session = import_http2.default.performServerHandshake(internalTLS);
164
- session.on("error", () => {
165
- this.target.destroy();
166
- this._targetCloseEventListener();
167
- });
168
- session.once("stream", (stream2) => {
169
- stream2.respond({
170
- "content-type": "text/html",
171
- [import_http2.default.constants.HTTP2_HEADER_STATUS]: 503
172
- });
173
- const cleanup = () => {
174
- session.close();
175
- this.target.destroy();
176
- this._targetCloseEventListener();
177
- };
178
- stream2.end(responseBody, cleanup);
179
- stream2.once("error", cleanup);
180
- });
181
- } else {
182
- this.target.destroy();
183
- }
184
- } else {
185
- internalTLS.end([
186
- "HTTP/1.1 503 Internal Server Error",
187
- "Content-Type: text/html; charset=utf-8",
188
- "Content-Length: " + Buffer.byteLength(responseBody),
189
- "",
190
- responseBody
191
- ].join("\r\n"));
192
- this.target.destroy();
193
- }
194
- };
195
- if (this._closed) {
196
- internalTLS.destroy();
197
- return;
198
- }
199
- targetTLS = import_tls.default.connect({
200
- socket: this.target,
201
- host: this.host,
202
- port: this.port,
203
- rejectUnauthorized: !this.socksProxy.ignoreHTTPSErrors,
204
- ALPNProtocols: [internalTLS.alpnProtocol || "http/1.1"],
205
- servername: !import_net.default.isIP(this.host) ? this.host : void 0,
206
- secureContext: this.socksProxy.secureContextMap.get(new URL(`https://${this.host}:${this.port}`).origin)
207
- });
208
- targetTLS.once("secureConnect", () => {
209
- internalTLS.pipe(targetTLS);
210
- targetTLS.pipe(internalTLS);
211
- });
212
- internalTLS.once("error", () => this.target.destroy());
213
- targetTLS.once("error", handleError);
188
+ dummyServer.emit("connection", socket);
189
+ dummyServer.once("secureConnection", (tlsSocket) => {
190
+ dummyServer.close();
191
+ resolve(tlsSocket);
192
+ });
193
+ dummyServer.once("error", (error) => {
194
+ dummyServer.close();
195
+ reject(error);
214
196
  });
215
197
  });
198
+ return this._brorwserDecrypted;
216
199
  }
217
200
  }
218
201
  class ClientCertificatesProxy {
@@ -220,9 +203,8 @@ class ClientCertificatesProxy {
220
203
  this._connections = /* @__PURE__ */ new Map();
221
204
  this.secureContextMap = /* @__PURE__ */ new Map();
222
205
  (0, import_browserContext.verifyClientCertificates)(contextOptions.clientCertificates);
223
- this.alpnCache = new ALPNCache();
224
206
  this.ignoreHTTPSErrors = contextOptions.ignoreHTTPSErrors;
225
- this.proxyAgentFromOptions = (0, import_network.createProxyAgent)(contextOptions.proxy);
207
+ this._proxy = contextOptions.proxy;
226
208
  this._initSecureContexts(contextOptions.clientCertificates);
227
209
  this._socksProxy = new import_socksProxy.SocksProxy();
228
210
  this._socksProxy.setPattern("*");
@@ -232,10 +214,11 @@ class ClientCertificatesProxy {
232
214
  await connection.connect();
233
215
  this._connections.set(payload.uid, connection);
234
216
  } catch (error) {
217
+ import_debugLogger.debugLogger.log("client-certificates", `Failed to connect to ${payload.host}:${payload.port}: ${error.message}`);
235
218
  this._socksProxy.socketFailed({ uid: payload.uid, errorCode: error.code });
236
219
  }
237
220
  });
238
- this._socksProxy.addListener(import_socksProxy.SocksProxy.Events.SocksData, async (payload) => {
221
+ this._socksProxy.addListener(import_socksProxy.SocksProxy.Events.SocksData, (payload) => {
239
222
  this._connections.get(payload.uid)?.onData(payload.data);
240
223
  });
241
224
  this._socksProxy.addListener(import_socksProxy.SocksProxy.Events.SocksClosed, (payload) => {
@@ -244,6 +227,14 @@ class ClientCertificatesProxy {
244
227
  });
245
228
  loadDummyServerCertsIfNeeded();
246
229
  }
230
+ getProxyAgent(host, port) {
231
+ const proxyFromOptions = (0, import_network.createProxyAgent)(this._proxy);
232
+ if (proxyFromOptions)
233
+ return proxyFromOptions;
234
+ const proxyFromEnv = (0, import_utilsBundle.getProxyForUrl)(`https://${host}:${port}`);
235
+ if (proxyFromEnv)
236
+ return (0, import_network.createProxyAgent)({ server: proxyFromEnv });
237
+ }
247
238
  _initSecureContexts(clientCertificates) {
248
239
  const origin2certs = /* @__PURE__ */ new Map();
249
240
  for (const cert of clientCertificates || []) {
@@ -261,9 +252,18 @@ class ClientCertificatesProxy {
261
252
  }
262
253
  }
263
254
  }
264
- async listen() {
265
- const port = await this._socksProxy.listen(0, "127.0.0.1");
266
- return { server: `socks5://127.0.0.1:${port}` };
255
+ static async create(progress, contextOptions) {
256
+ const proxy = new ClientCertificatesProxy(contextOptions);
257
+ try {
258
+ await progress.race(proxy._socksProxy.listen(0, "127.0.0.1"));
259
+ return proxy;
260
+ } catch (error) {
261
+ await proxy.close();
262
+ throw error;
263
+ }
264
+ }
265
+ proxySettings() {
266
+ return { server: `socks5://127.0.0.1:${this._socksProxy.port()}` };
267
267
  }
268
268
  async close() {
269
269
  await this._socksProxy.close();
@@ -313,6 +313,68 @@ function rewriteOpenSSLErrorIfNeeded(error) {
313
313
  "You could probably modernize the certificate by following the steps at https://github.com/nodejs/node/issues/40672#issuecomment-1243648223"
314
314
  ].join("\n"));
315
315
  }
316
+ function parseALPNFromClientHello(buffer) {
317
+ if (buffer.length < 6)
318
+ return null;
319
+ if (buffer[0] !== 22)
320
+ return null;
321
+ let offset = 5;
322
+ if (buffer[offset] !== 1)
323
+ return null;
324
+ offset += 4;
325
+ offset += 2;
326
+ offset += 32;
327
+ if (offset >= buffer.length)
328
+ return null;
329
+ const sessionIdLength = buffer[offset];
330
+ offset += 1 + sessionIdLength;
331
+ if (offset + 2 > buffer.length)
332
+ return null;
333
+ const cipherSuitesLength = buffer.readUInt16BE(offset);
334
+ offset += 2 + cipherSuitesLength;
335
+ if (offset >= buffer.length)
336
+ return null;
337
+ const compressionMethodsLength = buffer[offset];
338
+ offset += 1 + compressionMethodsLength;
339
+ if (offset + 2 > buffer.length)
340
+ return null;
341
+ const extensionsLength = buffer.readUInt16BE(offset);
342
+ offset += 2;
343
+ const extensionsEnd = offset + extensionsLength;
344
+ if (extensionsEnd > buffer.length)
345
+ return null;
346
+ while (offset + 4 <= extensionsEnd) {
347
+ const extensionType = buffer.readUInt16BE(offset);
348
+ offset += 2;
349
+ const extensionLength = buffer.readUInt16BE(offset);
350
+ offset += 2;
351
+ if (offset + extensionLength > extensionsEnd)
352
+ return null;
353
+ if (extensionType === 16)
354
+ return parseALPNExtension(buffer.subarray(offset, offset + extensionLength));
355
+ offset += extensionLength;
356
+ }
357
+ return null;
358
+ }
359
+ function parseALPNExtension(buffer) {
360
+ if (buffer.length < 2)
361
+ return null;
362
+ const listLength = buffer.readUInt16BE(0);
363
+ if (listLength !== buffer.length - 2)
364
+ return null;
365
+ const protocols = [];
366
+ let offset = 2;
367
+ while (offset < buffer.length) {
368
+ const protocolLength = buffer[offset];
369
+ offset += 1;
370
+ if (offset + protocolLength > buffer.length)
371
+ break;
372
+ const protocol = buffer.subarray(offset, offset + protocolLength).toString("utf8");
373
+ protocols.push(protocol);
374
+ offset += protocolLength;
375
+ }
376
+ return protocols.length > 0 ? protocols : null;
377
+ }
316
378
  // Annotate the CommonJS export names for ESM import in node:
317
379
  0 && (module.exports = {
318
380
  ClientCertificatesProxy,
@@ -32,7 +32,6 @@ var import_page = require("../../page");
32
32
  class Snapshotter {
33
33
  constructor(context, delegate) {
34
34
  this._eventListeners = [];
35
- this._initialized = false;
36
35
  this._started = false;
37
36
  this._context = context;
38
37
  this._delegate = delegate;
@@ -44,21 +43,23 @@ class Snapshotter {
44
43
  }
45
44
  async start() {
46
45
  this._started = true;
47
- if (!this._initialized) {
48
- this._initialized = true;
46
+ if (!this._initScript)
49
47
  await this._initialize();
50
- }
51
48
  await this.reset();
52
49
  }
53
50
  async reset() {
54
51
  if (this._started)
55
- await this._runInAllFrames(`window["${this._snapshotStreamer}"].reset()`);
52
+ await this._context.safeNonStallingEvaluateInAllFrames(`window["${this._snapshotStreamer}"].reset()`, "main");
56
53
  }
57
- async stop() {
54
+ stop() {
58
55
  this._started = false;
59
56
  }
60
- resetForReuse() {
61
- this._initialized = false;
57
+ async resetForReuse() {
58
+ if (this._initScript) {
59
+ import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
60
+ await this._context.removeInitScripts([this._initScript]);
61
+ this._initScript = void 0;
62
+ }
62
63
  }
63
64
  async _initialize() {
64
65
  for (const page of this._context.pages())
@@ -67,17 +68,9 @@ class Snapshotter {
67
68
  import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.Page, this._onPage.bind(this))
68
69
  ];
69
70
  const { javaScriptEnabled } = this._context._options;
70
- const initScript = `(${import_snapshotterInjected.frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === void 0})`;
71
- await this._context.addInitScript(initScript);
72
- await this._runInAllFrames(initScript);
73
- }
74
- async _runInAllFrames(expression) {
75
- const frames = [];
76
- for (const page of this._context.pages())
77
- frames.push(...page.frames());
78
- await Promise.all(frames.map((frame) => {
79
- return frame.nonStallingRawEvaluateInExistingMainContext(expression).catch((e) => import_debugLogger.debugLogger.log("error", e));
80
- }));
71
+ const initScriptSource = `(${import_snapshotterInjected.frameSnapshotStreamer})("${this._snapshotStreamer}", ${javaScriptEnabled || javaScriptEnabled === void 0})`;
72
+ this._initScript = await this._context.addInitScript(void 0, initScriptSource);
73
+ await this._context.safeNonStallingEvaluateInAllFrames(initScriptSource, "main");
81
74
  }
82
75
  dispose() {
83
76
  import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
@@ -28,15 +28,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var tracing_exports = {};
30
30
  __export(tracing_exports, {
31
- Tracing: () => Tracing,
32
- shouldCaptureSnapshot: () => shouldCaptureSnapshot
31
+ Tracing: () => Tracing
33
32
  });
34
33
  module.exports = __toCommonJS(tracing_exports);
35
34
  var import_fs = __toESM(require("fs"));
36
35
  var import_os = __toESM(require("os"));
37
36
  var import_path = __toESM(require("path"));
38
37
  var import_snapshotter = require("./snapshotter");
39
- var import_debug = require("../../../protocol/debug");
38
+ var import_protocolMetainfo = require("../../../utils/isomorphic/protocolMetainfo");
40
39
  var import_assert = require("../../../utils/isomorphic/assert");
41
40
  var import_time = require("../../../utils/isomorphic/time");
42
41
  var import_eventsHelper = require("../../utils/eventsHelper");
@@ -49,7 +48,8 @@ var import_fileUtils = require("../../utils/fileUtils");
49
48
  var import_harTracer = require("../../har/harTracer");
50
49
  var import_instrumentation = require("../../instrumentation");
51
50
  var import_page = require("../../page");
52
- const version = 7;
51
+ var import_progress = require("../../progress");
52
+ const version = 8;
53
53
  const kScreencastOptions = { width: 800, height: 600, quality: 90 };
54
54
  class Tracing extends import_instrumentation.SdkObject {
55
55
  constructor(context, tracesDir) {
@@ -78,7 +78,7 @@ class Tracing extends import_instrumentation.SdkObject {
78
78
  platform: process.platform,
79
79
  wallTime: 0,
80
80
  monotonicTime: 0,
81
- sdkLanguage: context.attribution.playwright.options.sdkLanguage,
81
+ sdkLanguage: this._sdkLanguage(),
82
82
  testIdAttributeName,
83
83
  contextId: context.guid
84
84
  };
@@ -90,18 +90,22 @@ class Tracing extends import_instrumentation.SdkObject {
90
90
  this._contextCreatedEvent.options = context._options;
91
91
  }
92
92
  }
93
- async resetForReuse() {
94
- await this.stopChunk({ mode: "discard" }).catch(() => {
93
+ _sdkLanguage() {
94
+ return this._context instanceof import_browserContext.BrowserContext ? this._context._browser.sdkLanguage() : this._context.attribution.playwright.options.sdkLanguage;
95
+ }
96
+ async resetForReuse(progress) {
97
+ await this.stopChunk(progress, { mode: "discard" }).catch(() => {
95
98
  });
96
- await this.stop();
97
- this._snapshotter?.resetForReuse();
99
+ await this.stop(progress);
100
+ if (this._snapshotter)
101
+ await progress.race(this._snapshotter.resetForReuse());
98
102
  }
99
- async start(options) {
103
+ start(options) {
100
104
  if (this._isStopping)
101
105
  throw new Error("Cannot start tracing while stopping");
102
106
  if (this._state)
103
107
  throw new Error("Tracing has been already started");
104
- this._contextCreatedEvent.sdkLanguage = this._context.attribution.playwright.options.sdkLanguage;
108
+ this._contextCreatedEvent.sdkLanguage = this._sdkLanguage();
105
109
  const traceName = options.name || (0, import_crypto.createGuid)();
106
110
  const tracesDir = this._createTracesDirIfNeeded();
107
111
  this._state = {
@@ -123,9 +127,9 @@ class Tracing extends import_instrumentation.SdkObject {
123
127
  if (options.snapshots)
124
128
  this._harTracer.start({ omitScripts: !options.live });
125
129
  }
126
- async startChunk(options = {}) {
130
+ async startChunk(progress, options = {}) {
127
131
  if (this._state && this._state.recording)
128
- await this.stopChunk({ mode: "discard" });
132
+ await this.stopChunk(progress, { mode: "discard" });
129
133
  if (!this._state)
130
134
  throw new Error("Must start tracing before starting a new chunk");
131
135
  if (this._isStopping)
@@ -161,7 +165,7 @@ class Tracing extends import_instrumentation.SdkObject {
161
165
  _currentGroupId() {
162
166
  return this._state?.groupStack.length ? this._state.groupStack[this._state.groupStack.length - 1] : void 0;
163
167
  }
164
- async group(name, location, metadata) {
168
+ group(name, location, metadata) {
165
169
  if (!this._state)
166
170
  return;
167
171
  const stackFrames = [];
@@ -177,7 +181,7 @@ class Tracing extends import_instrumentation.SdkObject {
177
181
  type: "before",
178
182
  callId: metadata.id,
179
183
  startTime: metadata.startTime,
180
- apiName: name,
184
+ title: name,
181
185
  class: "Tracing",
182
186
  method: "tracingGroup",
183
187
  params: {},
@@ -232,7 +236,7 @@ class Tracing extends import_instrumentation.SdkObject {
232
236
  this._fs.copyFile(state.networkFile, newNetworkFile);
233
237
  state.networkFile = newNetworkFile;
234
238
  }
235
- async stop() {
239
+ async stop(progress) {
236
240
  if (!this._state)
237
241
  return;
238
242
  if (this._isStopping)
@@ -242,8 +246,10 @@ class Tracing extends import_instrumentation.SdkObject {
242
246
  this._closeAllGroups();
243
247
  this._harTracer.stop();
244
248
  this.flushHarEntries();
245
- await this._fs.syncAndGetError();
246
- this._state = void 0;
249
+ const promise = progress ? progress.race(this._fs.syncAndGetError()) : this._fs.syncAndGetError();
250
+ await promise.finally(() => {
251
+ this._state = void 0;
252
+ });
247
253
  }
248
254
  async deleteTmpTracesDir() {
249
255
  if (this._tracesTmpDir)
@@ -267,7 +273,7 @@ class Tracing extends import_instrumentation.SdkObject {
267
273
  while (this._currentGroupId())
268
274
  this.groupEnd();
269
275
  }
270
- async stopChunk(params) {
276
+ async stopChunk(progress, params) {
271
277
  if (this._isStopping)
272
278
  throw new Error(`Tracing is already stopping`);
273
279
  this._isStopping = true;
@@ -283,7 +289,7 @@ class Tracing extends import_instrumentation.SdkObject {
283
289
  if (this._state.options.screenshots)
284
290
  this._stopScreencast();
285
291
  if (this._state.options.snapshots)
286
- await this._snapshotter?.stop();
292
+ this._snapshotter?.stop();
287
293
  this.flushHarEntries();
288
294
  const newNetworkFile = import_path.default.join(this._state.tracesDir, this._state.traceName + `-pwnetcopy-${this._state.chunkOrdinal}.network`);
289
295
  const entries = [];
@@ -301,12 +307,13 @@ class Tracing extends import_instrumentation.SdkObject {
301
307
  const zipFileName = this._state.traceFile + ".zip";
302
308
  if (params.mode === "archive")
303
309
  this._fs.zip(entries, zipFileName);
304
- const error = await this._fs.syncAndGetError();
310
+ const promise = progress ? progress.race(this._fs.syncAndGetError()) : this._fs.syncAndGetError();
311
+ const error = await promise.catch((e) => e);
305
312
  this._isStopping = false;
306
313
  if (this._state)
307
314
  this._state.recording = false;
308
315
  if (error) {
309
- if (this._context instanceof import_browserContext.BrowserContext && !this._context._browser.isConnected())
316
+ if (!(0, import_progress.isAbortError)(error) && this._context instanceof import_browserContext.BrowserContext && !this._context._browser.isConnected())
310
317
  return {};
311
318
  throw error;
312
319
  }
@@ -350,7 +357,9 @@ class Tracing extends import_instrumentation.SdkObject {
350
357
  return this._captureSnapshot(event.inputSnapshot, sdkObject, metadata);
351
358
  }
352
359
  onCallLog(sdkObject, metadata, logName, message) {
353
- if (metadata.isServerSide || metadata.internal)
360
+ if (!this._state?.callIds.has(metadata.id))
361
+ return;
362
+ if (metadata.internal)
354
363
  return;
355
364
  if (logName !== "api")
356
365
  return;
@@ -535,7 +544,8 @@ function visitTraceEvent(object, sha1s) {
535
544
  return object;
536
545
  }
537
546
  function shouldCaptureSnapshot(metadata) {
538
- return import_debug.commandsWithTracingSnapshots.has(metadata.type + "." + metadata.method);
547
+ const metainfo = import_protocolMetainfo.methodMetainfo.get(metadata.type + "." + metadata.method);
548
+ return !!metainfo?.snapshot;
539
549
  }
540
550
  function createBeforeActionTraceEvent(metadata, parentId) {
541
551
  if (metadata.internal || metadata.method.startsWith("tracing"))
@@ -544,7 +554,7 @@ function createBeforeActionTraceEvent(metadata, parentId) {
544
554
  type: "before",
545
555
  callId: metadata.id,
546
556
  startTime: metadata.startTime,
547
- apiName: metadata.apiName || metadata.type + "." + metadata.method,
557
+ title: metadata.title,
548
558
  class: metadata.type,
549
559
  method: metadata.method,
550
560
  params: metadata.params,
@@ -588,6 +598,5 @@ function createAfterActionTraceEvent(metadata) {
588
598
  }
589
599
  // Annotate the CommonJS export names for ESM import in node:
590
600
  0 && (module.exports = {
591
- Tracing,
592
- shouldCaptureSnapshot
601
+ Tracing
593
602
  });