patchright-core 1.52.5 → 1.55.1

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 +54 -32
  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 +30 -26
  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 +421 -345
  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 +43 -31
  72. package/lib/server/chromium/crPage.js +98 -72
  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 +98 -101
  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 +63 -20
  123. package/lib/server/frames.js +495 -555
  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 +8 -16
  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 +232 -177
  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 +128 -17
  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
@@ -29,7 +29,8 @@ __export(validatorPrimitives_exports, {
29
29
  tBoolean: () => tBoolean,
30
30
  tChannel: () => tChannel,
31
31
  tEnum: () => tEnum,
32
- tNumber: () => tNumber,
32
+ tFloat: () => tFloat,
33
+ tInt: () => tInt,
33
34
  tObject: () => tObject,
34
35
  tOptional: () => tOptional,
35
36
  tString: () => tString,
@@ -53,12 +54,24 @@ function maybeFindValidator(type, method, kind) {
53
54
  function createMetadataValidator() {
54
55
  return tOptional(scheme["Metadata"]);
55
56
  }
56
- const tNumber = (arg, path, context) => {
57
+ const tFloat = (arg, path, context) => {
57
58
  if (arg instanceof Number)
58
59
  return arg.valueOf();
59
60
  if (typeof arg === "number")
60
61
  return arg;
61
- throw new ValidationError(`${path}: expected number, got ${typeof arg}`);
62
+ throw new ValidationError(`${path}: expected float, got ${typeof arg}`);
63
+ };
64
+ const tInt = (arg, path, context) => {
65
+ let value;
66
+ if (arg instanceof Number)
67
+ value = arg.valueOf();
68
+ else if (typeof arg === "number")
69
+ value = arg;
70
+ else
71
+ throw new ValidationError(`${path}: expected integer, got ${typeof arg}`);
72
+ if (!Number.isInteger(value))
73
+ throw new ValidationError(`${path}: expected integer, got float ${value}`);
74
+ return value;
62
75
  };
63
76
  const tBoolean = (arg, path, context) => {
64
77
  if (arg instanceof Boolean)
@@ -170,7 +183,8 @@ const tType = (name) => {
170
183
  tBoolean,
171
184
  tChannel,
172
185
  tEnum,
173
- tNumber,
186
+ tFloat,
187
+ tInt,
174
188
  tObject,
175
189
  tOptional,
176
190
  tString,
@@ -21,32 +21,22 @@ __export(playwrightConnection_exports, {
21
21
  PlaywrightConnection: () => PlaywrightConnection
22
22
  });
23
23
  module.exports = __toCommonJS(playwrightConnection_exports);
24
- var import_socksProxy = require("../server/utils/socksProxy");
25
24
  var import_server = require("../server");
26
25
  var import_android = require("../server/android/android");
27
26
  var import_browser = require("../server/browser");
28
27
  var import_debugControllerDispatcher = require("../server/dispatchers/debugControllerDispatcher");
29
- var import_instrumentation = require("../server/instrumentation");
30
- var import_assert = require("../utils/isomorphic/assert");
31
- var import_debug = require("../server/utils/debug");
32
28
  var import_profiler = require("../server/utils/profiler");
33
29
  var import_utils = require("../utils");
34
30
  var import_debugLogger = require("../server/utils/debugLogger");
35
31
  class PlaywrightConnection {
36
- constructor(lock, clientType, ws, options, preLaunched, id, onClose) {
32
+ constructor(semaphore, ws, controller, playwright, initialize, id) {
37
33
  this._cleanups = [];
38
34
  this._disconnected = false;
39
35
  this._ws = ws;
40
- this._preLaunched = preLaunched;
41
- this._options = options;
42
- options.launchOptions = filterLaunchOptions(options.launchOptions, options.allowFSPaths);
43
- if (clientType === "reuse-browser" || clientType === "pre-launched-browser-or-android")
44
- (0, import_assert.assert)(preLaunched.playwright);
45
- if (clientType === "pre-launched-browser-or-android")
46
- (0, import_assert.assert)(preLaunched.browser || preLaunched.androidDevice);
47
- this._onClose = onClose;
36
+ this._semaphore = semaphore;
48
37
  this._id = id;
49
- this._profileName = `${(/* @__PURE__ */ new Date()).toISOString()}-${clientType}`;
38
+ this._profileName = (/* @__PURE__ */ new Date()).toISOString();
39
+ const lock = this._semaphore.acquire();
50
40
  this._dispatcherConnection = new import_server.DispatcherConnection();
51
41
  this._dispatcherConnection.onmessage = async (message) => {
52
42
  await lock;
@@ -71,134 +61,46 @@ class PlaywrightConnection {
71
61
  });
72
62
  ws.on("close", () => this._onDisconnect());
73
63
  ws.on("error", (error) => this._onDisconnect(error));
74
- if (clientType === "controller") {
75
- this._root = this._initDebugControllerMode();
64
+ if (controller) {
65
+ import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse controller mode`);
66
+ this._root = new import_debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
76
67
  return;
77
68
  }
78
- this._root = new import_server.RootDispatcher(this._dispatcherConnection, async (scope, options2) => {
69
+ this._root = new import_server.RootDispatcher(this._dispatcherConnection, async (scope, params) => {
79
70
  await (0, import_profiler.startProfiling)();
80
- if (clientType === "reuse-browser")
81
- return await this._initReuseBrowsersMode(scope);
82
- if (clientType === "pre-launched-browser-or-android")
83
- return this._preLaunched.browser ? await this._initPreLaunchedBrowserMode(scope) : await this._initPreLaunchedAndroidMode(scope);
84
- if (clientType === "launch-browser")
85
- return await this._initLaunchBrowserMode(scope, options2);
86
- throw new Error("Unsupported client type: " + clientType);
87
- });
88
- }
89
- async _initLaunchBrowserMode(scope, options) {
90
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
91
- const playwright = (0, import_server.createPlaywright)({ sdkLanguage: options.sdkLanguage, isServer: true });
92
- const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
93
- let browserName = this._options.browserName;
94
- if ("bidi" === browserName) {
95
- if (this._options.launchOptions?.channel?.toLocaleLowerCase().includes("firefox"))
96
- browserName = "bidiFirefox";
97
- else
98
- browserName = "bidiChromium";
99
- }
100
- const browser = await playwright[browserName].launch((0, import_instrumentation.serverSideCallMetadata)(), this._options.launchOptions);
101
- this._cleanups.push(async () => {
102
- for (const browser2 of playwright.allBrowsers())
103
- await browser2.close({ reason: "Connection terminated" });
104
- });
105
- browser.on(import_browser.Browser.Events.Disconnected, () => {
106
- this.close({ code: 1001, reason: "Browser closed" });
107
- });
108
- return new import_server.PlaywrightDispatcher(scope, playwright, ownedSocksProxy, browser);
109
- }
110
- async _initPreLaunchedBrowserMode(scope) {
111
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged pre-launched (browser) mode`);
112
- const playwright = this._preLaunched.playwright;
113
- this._preLaunched.socksProxy?.setPattern(this._options.socksProxyPattern);
114
- const browser = this._preLaunched.browser;
115
- browser.on(import_browser.Browser.Events.Disconnected, () => {
116
- this.close({ code: 1001, reason: "Browser closed" });
117
- });
118
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, playwright, this._preLaunched.socksProxy, browser);
119
- for (const b of playwright.allBrowsers()) {
120
- if (b !== browser)
121
- await b.close({ reason: "Connection terminated" });
122
- }
123
- this._cleanups.push(() => playwrightDispatcher.cleanup());
124
- return playwrightDispatcher;
125
- }
126
- async _initPreLaunchedAndroidMode(scope) {
127
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged pre-launched (Android) mode`);
128
- const playwright = this._preLaunched.playwright;
129
- const androidDevice = this._preLaunched.androidDevice;
130
- androidDevice.on(import_android.AndroidDevice.Events.Close, () => {
131
- this.close({ code: 1001, reason: "Android device disconnected" });
132
- });
133
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, playwright, void 0, void 0, androidDevice);
134
- this._cleanups.push(() => playwrightDispatcher.cleanup());
135
- return playwrightDispatcher;
136
- }
137
- _initDebugControllerMode() {
138
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse controller mode`);
139
- const playwright = this._preLaunched.playwright;
140
- return new import_debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
141
- }
142
- async _initReuseBrowsersMode(scope) {
143
- import_debugLogger.debugLogger.log("server", `[${this._id}] engaged reuse browsers mode for ${this._options.browserName}`);
144
- const playwright = this._preLaunched.playwright;
145
- const requestedOptions = launchOptionsHash(this._options.launchOptions);
146
- let browser = playwright.allBrowsers().find((b) => {
147
- if (b.options.name !== this._options.browserName)
148
- return false;
149
- const existingOptions = launchOptionsHash(b.options.originalLaunchOptions);
150
- return existingOptions === requestedOptions;
151
- });
152
- for (const b of playwright.allBrowsers()) {
153
- if (b === browser)
154
- continue;
155
- if (b.options.name === this._options.browserName && b.options.channel === this._options.launchOptions.channel)
156
- await b.close({ reason: "Connection terminated" });
157
- }
158
- if (!browser) {
159
- browser = await playwright[this._options.browserName || "chromium"].launch((0, import_instrumentation.serverSideCallMetadata)(), {
160
- ...this._options.launchOptions,
161
- headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS
162
- });
163
- browser.on(import_browser.Browser.Events.Disconnected, () => {
164
- this.close({ code: 1001, reason: "Browser closed" });
165
- });
166
- }
167
- this._cleanups.push(async () => {
168
- for (const browser2 of playwright.allBrowsers()) {
169
- for (const context of browser2.contexts()) {
170
- if (!context.pages().length)
171
- await context.close({ reason: "Connection terminated" });
172
- else
173
- await context.stopPendingOperations("Connection closed");
174
- }
175
- if (!browser2.contexts())
176
- await browser2.close({ reason: "Connection terminated" });
71
+ const options = await initialize();
72
+ if (options.preLaunchedBrowser) {
73
+ const browser = options.preLaunchedBrowser;
74
+ browser.options.sdkLanguage = params.sdkLanguage;
75
+ browser.on(import_browser.Browser.Events.Disconnected, () => {
76
+ this.close({ code: 1001, reason: "Browser closed" });
77
+ });
78
+ }
79
+ if (options.preLaunchedAndroidDevice) {
80
+ const androidDevice = options.preLaunchedAndroidDevice;
81
+ androidDevice.on(import_android.AndroidDevice.Events.Close, () => {
82
+ this.close({ code: 1001, reason: "Android device disconnected" });
83
+ });
177
84
  }
85
+ if (options.dispose)
86
+ this._cleanups.push(options.dispose);
87
+ const dispatcher = new import_server.PlaywrightDispatcher(scope, playwright, options);
88
+ this._cleanups.push(() => dispatcher.cleanup());
89
+ return dispatcher;
178
90
  });
179
- const playwrightDispatcher = new import_server.PlaywrightDispatcher(scope, playwright, void 0, browser);
180
- return playwrightDispatcher;
181
- }
182
- async _createOwnedSocksProxy(playwright) {
183
- if (!this._options.socksProxyPattern)
184
- return;
185
- const socksProxy = new import_socksProxy.SocksProxy();
186
- socksProxy.setPattern(this._options.socksProxyPattern);
187
- playwright.options.socksProxyPort = await socksProxy.listen(0);
188
- import_debugLogger.debugLogger.log("server", `[${this._id}] started socks proxy on port ${playwright.options.socksProxyPort}`);
189
- this._cleanups.push(() => socksProxy.close());
190
- return socksProxy;
191
91
  }
192
92
  async _onDisconnect(error) {
193
93
  this._disconnected = true;
194
94
  import_debugLogger.debugLogger.log("server", `[${this._id}] disconnected. error: ${error}`);
95
+ await this._root.stopPendingOperations(new Error("Disconnected")).catch(() => {
96
+ });
195
97
  this._root._dispose();
196
98
  import_debugLogger.debugLogger.log("server", `[${this._id}] starting cleanup`);
197
99
  for (const cleanup of this._cleanups)
198
100
  await cleanup().catch(() => {
199
101
  });
200
102
  await (0, import_profiler.stopProfiling)(this._profileName);
201
- this._onClose();
103
+ this._semaphore.release();
202
104
  import_debugLogger.debugLogger.log("server", `[${this._id}] finished cleanup`);
203
105
  }
204
106
  logServerMetadata(message, messageString, direction) {
@@ -221,45 +123,6 @@ class PlaywrightConnection {
221
123
  }
222
124
  }
223
125
  }
224
- function launchOptionsHash(options) {
225
- const copy = { ...options };
226
- for (const k of Object.keys(copy)) {
227
- const key = k;
228
- if (copy[key] === defaultLaunchOptions[key])
229
- delete copy[key];
230
- }
231
- for (const key of optionsThatAllowBrowserReuse)
232
- delete copy[key];
233
- return JSON.stringify(copy);
234
- }
235
- function filterLaunchOptions(options, allowFSPaths) {
236
- return {
237
- channel: options.channel,
238
- args: options.args,
239
- ignoreAllDefaultArgs: options.ignoreAllDefaultArgs,
240
- ignoreDefaultArgs: options.ignoreDefaultArgs,
241
- timeout: options.timeout,
242
- headless: options.headless,
243
- proxy: options.proxy,
244
- chromiumSandbox: options.chromiumSandbox,
245
- firefoxUserPrefs: options.firefoxUserPrefs,
246
- slowMo: options.slowMo,
247
- executablePath: (0, import_debug.isUnderTest)() || allowFSPaths ? options.executablePath : void 0,
248
- downloadsPath: allowFSPaths ? options.downloadsPath : void 0
249
- };
250
- }
251
- const defaultLaunchOptions = {
252
- ignoreAllDefaultArgs: false,
253
- handleSIGINT: false,
254
- handleSIGTERM: false,
255
- handleSIGHUP: false,
256
- headless: true,
257
- devtools: false
258
- };
259
- const optionsThatAllowBrowserReuse = [
260
- "headless",
261
- "tracesDir"
262
- ];
263
126
  // Annotate the CommonJS export names for ESM import in node:
264
127
  0 && (module.exports = {
265
128
  PlaywrightConnection
@@ -23,22 +23,40 @@ __export(playwrightServer_exports, {
23
23
  module.exports = __toCommonJS(playwrightServer_exports);
24
24
  var import_playwrightConnection = require("./playwrightConnection");
25
25
  var import_playwright = require("../server/playwright");
26
- var import_debugLogger = require("../server/utils/debugLogger");
27
26
  var import_semaphore = require("../utils/isomorphic/semaphore");
27
+ var import_time = require("../utils/isomorphic/time");
28
28
  var import_wsServer = require("../server/utils/wsServer");
29
29
  var import_ascii = require("../server/utils/ascii");
30
30
  var import_userAgent = require("../server/utils/userAgent");
31
+ var import_utils = require("../utils");
32
+ var import_socksProxy = require("../server/utils/socksProxy");
33
+ var import_browser = require("../server/browser");
34
+ var import_progress = require("../server/progress");
31
35
  class PlaywrightServer {
32
36
  constructor(options) {
37
+ this._dontReuseBrowsers = /* @__PURE__ */ new Set();
33
38
  this._options = options;
34
- if (options.preLaunchedBrowser)
35
- this._preLaunchedPlaywright = options.preLaunchedBrowser.attribution.playwright;
39
+ if (options.preLaunchedBrowser) {
40
+ this._playwright = options.preLaunchedBrowser.attribution.playwright;
41
+ this._dontReuse(options.preLaunchedBrowser);
42
+ }
36
43
  if (options.preLaunchedAndroidDevice)
37
- this._preLaunchedPlaywright = options.preLaunchedAndroidDevice._android.attribution.playwright;
44
+ this._playwright = options.preLaunchedAndroidDevice._android.attribution.playwright;
45
+ this._playwright ??= (0, import_playwright.createPlaywright)({ sdkLanguage: "javascript", isServer: true });
38
46
  const browserSemaphore = new import_semaphore.Semaphore(this._options.maxConnections);
39
47
  const controllerSemaphore = new import_semaphore.Semaphore(1);
40
48
  const reuseBrowserSemaphore = new import_semaphore.Semaphore(1);
41
49
  this._wsServer = new import_wsServer.WSServer({
50
+ onRequest: (request, response) => {
51
+ if (request.method === "GET" && request.url === "/json") {
52
+ response.setHeader("Content-Type", "application/json");
53
+ response.end(JSON.stringify({
54
+ wsEndpointPath: this._options.path
55
+ }));
56
+ return;
57
+ }
58
+ response.end("Running");
59
+ },
42
60
  onUpgrade: (request, socket) => {
43
61
  const uaError = userAgentVersionMatchesErrorMessage(request.headers["user-agent"] || "");
44
62
  if (uaError)
@@ -58,51 +76,191 @@ ${uaError}` };
58
76
  const launchOptionsHeader = request.headers["x-playwright-launch-options"] || "";
59
77
  const launchOptionsHeaderValue = Array.isArray(launchOptionsHeader) ? launchOptionsHeader[0] : launchOptionsHeader;
60
78
  const launchOptionsParam = url.searchParams.get("launch-options");
61
- let launchOptions = {};
79
+ let launchOptions = { timeout: import_time.DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT };
62
80
  try {
63
81
  launchOptions = JSON.parse(launchOptionsParam || launchOptionsHeaderValue);
82
+ if (!launchOptions.timeout)
83
+ launchOptions.timeout = import_time.DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT;
64
84
  } catch (e) {
65
85
  }
66
86
  const isExtension = this._options.mode === "extension";
87
+ const allowFSPaths = isExtension;
88
+ launchOptions = filterLaunchOptions(launchOptions, allowFSPaths);
89
+ if (url.searchParams.has("debug-controller")) {
90
+ if (!(this._options.debugController || isExtension))
91
+ throw new Error("Debug controller is not enabled");
92
+ return new import_playwrightConnection.PlaywrightConnection(
93
+ controllerSemaphore,
94
+ ws,
95
+ true,
96
+ this._playwright,
97
+ async () => {
98
+ throw new Error("shouldnt be used");
99
+ },
100
+ id
101
+ );
102
+ }
67
103
  if (isExtension) {
68
- if (!this._preLaunchedPlaywright)
69
- this._preLaunchedPlaywright = (0, import_playwright.createPlaywright)({ sdkLanguage: "javascript", isServer: true });
104
+ const connectFilter = url.searchParams.get("connect");
105
+ if (connectFilter) {
106
+ if (connectFilter !== "first")
107
+ throw new Error(`Unknown connect filter: ${connectFilter}`);
108
+ return new import_playwrightConnection.PlaywrightConnection(
109
+ browserSemaphore,
110
+ ws,
111
+ false,
112
+ this._playwright,
113
+ () => this._initConnectMode(id, connectFilter, browserName, launchOptions),
114
+ id
115
+ );
116
+ }
117
+ return new import_playwrightConnection.PlaywrightConnection(
118
+ reuseBrowserSemaphore,
119
+ ws,
120
+ false,
121
+ this._playwright,
122
+ () => this._initReuseBrowsersMode(browserName, launchOptions, id),
123
+ id
124
+ );
70
125
  }
71
- let clientType = "launch-browser";
72
- let semaphore = browserSemaphore;
73
- if (isExtension && url.searchParams.has("debug-controller")) {
74
- clientType = "controller";
75
- semaphore = controllerSemaphore;
76
- } else if (isExtension) {
77
- clientType = "reuse-browser";
78
- semaphore = reuseBrowserSemaphore;
79
- } else if (this._options.mode === "launchServer") {
80
- clientType = "pre-launched-browser-or-android";
81
- semaphore = browserSemaphore;
126
+ if (this._options.mode === "launchServer" || this._options.mode === "launchServerShared") {
127
+ if (this._options.preLaunchedBrowser) {
128
+ return new import_playwrightConnection.PlaywrightConnection(
129
+ browserSemaphore,
130
+ ws,
131
+ false,
132
+ this._playwright,
133
+ () => this._initPreLaunchedBrowserMode(id),
134
+ id
135
+ );
136
+ }
137
+ return new import_playwrightConnection.PlaywrightConnection(
138
+ browserSemaphore,
139
+ ws,
140
+ false,
141
+ this._playwright,
142
+ () => this._initPreLaunchedAndroidMode(id),
143
+ id
144
+ );
82
145
  }
83
146
  return new import_playwrightConnection.PlaywrightConnection(
84
- semaphore.acquire(),
85
- clientType,
147
+ browserSemaphore,
86
148
  ws,
87
- { socksProxyPattern: proxyValue, browserName, launchOptions, allowFSPaths: this._options.mode === "extension" },
88
- {
89
- playwright: this._preLaunchedPlaywright,
90
- browser: this._options.preLaunchedBrowser,
91
- androidDevice: this._options.preLaunchedAndroidDevice,
92
- socksProxy: this._options.preLaunchedSocksProxy
93
- },
94
- id,
95
- () => semaphore.release()
149
+ false,
150
+ this._playwright,
151
+ () => this._initLaunchBrowserMode(browserName, proxyValue, launchOptions, id),
152
+ id
96
153
  );
97
- },
98
- onClose: async () => {
99
- import_debugLogger.debugLogger.log("server", "closing browsers");
100
- if (this._preLaunchedPlaywright)
101
- await Promise.all(this._preLaunchedPlaywright.allBrowsers().map((browser) => browser.close({ reason: "Playwright Server stopped" })));
102
- import_debugLogger.debugLogger.log("server", "closed browsers");
103
154
  }
104
155
  });
105
156
  }
157
+ async _initReuseBrowsersMode(browserName, launchOptions, id) {
158
+ import_utils.debugLogger.log("server", `[${id}] engaged reuse browsers mode for ${browserName}`);
159
+ const requestedOptions = launchOptionsHash(launchOptions);
160
+ let browser = this._playwright.allBrowsers().find((b) => {
161
+ if (b.options.name !== browserName)
162
+ return false;
163
+ if (this._dontReuseBrowsers.has(b))
164
+ return false;
165
+ const existingOptions = launchOptionsHash({ ...b.options.originalLaunchOptions, timeout: import_time.DEFAULT_PLAYWRIGHT_LAUNCH_TIMEOUT });
166
+ return existingOptions === requestedOptions;
167
+ });
168
+ for (const b of this._playwright.allBrowsers()) {
169
+ if (b === browser)
170
+ continue;
171
+ if (this._dontReuseBrowsers.has(b))
172
+ continue;
173
+ if (b.options.name === browserName && b.options.channel === launchOptions.channel)
174
+ await b.close({ reason: "Connection terminated" });
175
+ }
176
+ if (!browser) {
177
+ const browserType = this._playwright[browserName || "chromium"];
178
+ const controller = new import_progress.ProgressController();
179
+ browser = await controller.run((progress) => browserType.launch(progress, {
180
+ ...launchOptions,
181
+ headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS
182
+ }), launchOptions.timeout);
183
+ }
184
+ return {
185
+ preLaunchedBrowser: browser,
186
+ denyLaunch: true,
187
+ dispose: async () => {
188
+ for (const context of browser.contexts()) {
189
+ if (!context.pages().length)
190
+ await context.close({ reason: "Connection terminated" });
191
+ }
192
+ }
193
+ };
194
+ }
195
+ async _initConnectMode(id, filter, browserName, launchOptions) {
196
+ browserName ??= "chromium";
197
+ import_utils.debugLogger.log("server", `[${id}] engaged connect mode`);
198
+ let browser = this._playwright.allBrowsers().find((b) => b.options.name === browserName);
199
+ if (!browser) {
200
+ const browserType = this._playwright[browserName];
201
+ const controller = new import_progress.ProgressController();
202
+ browser = await controller.run((progress) => browserType.launch(progress, launchOptions), launchOptions.timeout);
203
+ this._dontReuse(browser);
204
+ }
205
+ return {
206
+ preLaunchedBrowser: browser,
207
+ denyLaunch: true,
208
+ sharedBrowser: true
209
+ };
210
+ }
211
+ async _initPreLaunchedBrowserMode(id) {
212
+ import_utils.debugLogger.log("server", `[${id}] engaged pre-launched (browser) mode`);
213
+ const browser = this._options.preLaunchedBrowser;
214
+ for (const b of this._playwright.allBrowsers()) {
215
+ if (b !== browser)
216
+ await b.close({ reason: "Connection terminated" });
217
+ }
218
+ return {
219
+ preLaunchedBrowser: browser,
220
+ socksProxy: this._options.preLaunchedSocksProxy,
221
+ sharedBrowser: this._options.mode === "launchServerShared",
222
+ denyLaunch: true
223
+ };
224
+ }
225
+ async _initPreLaunchedAndroidMode(id) {
226
+ import_utils.debugLogger.log("server", `[${id}] engaged pre-launched (Android) mode`);
227
+ const androidDevice = this._options.preLaunchedAndroidDevice;
228
+ return {
229
+ preLaunchedAndroidDevice: androidDevice,
230
+ denyLaunch: true
231
+ };
232
+ }
233
+ async _initLaunchBrowserMode(browserName, proxyValue, launchOptions, id) {
234
+ import_utils.debugLogger.log("server", `[${id}] engaged launch mode for "${browserName}"`);
235
+ let socksProxy;
236
+ if (proxyValue) {
237
+ socksProxy = new import_socksProxy.SocksProxy();
238
+ socksProxy.setPattern(proxyValue);
239
+ launchOptions.socksProxyPort = await socksProxy.listen(0);
240
+ import_utils.debugLogger.log("server", `[${id}] started socks proxy on port ${launchOptions.socksProxyPort}`);
241
+ } else {
242
+ launchOptions.socksProxyPort = void 0;
243
+ }
244
+ const browserType = this._playwright[browserName];
245
+ const controller = new import_progress.ProgressController();
246
+ const browser = await controller.run((progress) => browserType.launch(progress, launchOptions), launchOptions.timeout);
247
+ this._dontReuseBrowsers.add(browser);
248
+ return {
249
+ preLaunchedBrowser: browser,
250
+ socksProxy,
251
+ denyLaunch: true,
252
+ dispose: async () => {
253
+ await browser.close({ reason: "Connection terminated" });
254
+ socksProxy?.close();
255
+ }
256
+ };
257
+ }
258
+ _dontReuse(browser) {
259
+ this._dontReuseBrowsers.add(browser);
260
+ browser.on(import_browser.Browser.Events.Disconnected, () => {
261
+ this._dontReuseBrowsers.delete(browser);
262
+ });
263
+ }
106
264
  async listen(port = 0, hostname) {
107
265
  return this._wsServer.listen(port, hostname, this._options.path);
108
266
  }
@@ -133,6 +291,46 @@ function userAgentVersionMatchesErrorMessage(userAgent) {
133
291
  ].join("\n"), 1);
134
292
  }
135
293
  }
294
+ function launchOptionsHash(options) {
295
+ const copy = { ...options };
296
+ for (const k of Object.keys(copy)) {
297
+ const key = k;
298
+ if (copy[key] === defaultLaunchOptions[key])
299
+ delete copy[key];
300
+ }
301
+ for (const key of optionsThatAllowBrowserReuse)
302
+ delete copy[key];
303
+ return JSON.stringify(copy);
304
+ }
305
+ function filterLaunchOptions(options, allowFSPaths) {
306
+ return {
307
+ channel: options.channel,
308
+ args: options.args,
309
+ ignoreAllDefaultArgs: options.ignoreAllDefaultArgs,
310
+ ignoreDefaultArgs: options.ignoreDefaultArgs,
311
+ timeout: options.timeout,
312
+ headless: options.headless,
313
+ proxy: options.proxy,
314
+ chromiumSandbox: options.chromiumSandbox,
315
+ firefoxUserPrefs: options.firefoxUserPrefs,
316
+ slowMo: options.slowMo,
317
+ executablePath: (0, import_utils.isUnderTest)() || allowFSPaths ? options.executablePath : void 0,
318
+ downloadsPath: allowFSPaths ? options.downloadsPath : void 0
319
+ };
320
+ }
321
+ const defaultLaunchOptions = {
322
+ ignoreAllDefaultArgs: false,
323
+ handleSIGINT: false,
324
+ handleSIGTERM: false,
325
+ handleSIGHUP: false,
326
+ headless: true,
327
+ devtools: false
328
+ };
329
+ const optionsThatAllowBrowserReuse = [
330
+ "headless",
331
+ "timeout",
332
+ "tracesDir"
333
+ ];
136
334
  // Annotate the CommonJS export names for ESM import in node:
137
335
  0 && (module.exports = {
138
336
  PlaywrightServer