patchright-bun-core 1.58.2 → 1.59.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 (272) hide show
  1. package/ThirdPartyNotices.txt +126 -650
  2. package/browsers.json +16 -14
  3. package/lib/bootstrap.js +77 -0
  4. package/lib/cli/browserActions.js +308 -0
  5. package/lib/cli/driver.js +3 -2
  6. package/lib/cli/installActions.js +171 -0
  7. package/lib/cli/program.js +47 -411
  8. package/lib/client/android.js +4 -4
  9. package/lib/client/api.js +3 -3
  10. package/lib/client/browser.js +8 -0
  11. package/lib/client/browserContext.js +18 -37
  12. package/lib/client/browserType.js +19 -51
  13. package/lib/client/cdpSession.js +6 -2
  14. package/lib/client/channelOwner.js +1 -1
  15. package/lib/client/{webSocket.js → connect.js} +57 -7
  16. package/lib/client/connection.js +8 -4
  17. package/lib/client/consoleMessage.js +3 -0
  18. package/lib/client/debugger.js +57 -0
  19. package/lib/client/dialog.js +8 -1
  20. package/lib/client/disposable.js +76 -0
  21. package/lib/client/electron.js +1 -0
  22. package/lib/client/elementHandle.js +1 -4
  23. package/lib/client/events.js +3 -3
  24. package/lib/client/fetch.js +0 -1
  25. package/lib/client/frame.js +0 -5
  26. package/lib/client/harRouter.js +13 -1
  27. package/lib/client/jsHandle.js +0 -4
  28. package/lib/client/locator.js +5 -7
  29. package/lib/client/network.js +14 -11
  30. package/lib/client/page.js +34 -48
  31. package/lib/client/platform.js +0 -3
  32. package/lib/client/screencast.js +88 -0
  33. package/lib/client/selectors.js +3 -1
  34. package/lib/client/tracing.js +11 -4
  35. package/lib/client/video.js +13 -20
  36. package/lib/generated/bindingsControllerSource.js +1 -1
  37. package/lib/generated/clockSource.js +1 -1
  38. package/lib/generated/injectedScriptSource.js +1 -1
  39. package/lib/generated/pollingRecorderSource.js +1 -1
  40. package/lib/generated/storageScriptSource.js +1 -1
  41. package/lib/generated/utilityScriptSource.js +1 -1
  42. package/lib/mcpBundle.js +0 -6
  43. package/lib/mcpBundleImpl.js +91 -0
  44. package/lib/protocol/validator.js +216 -118
  45. package/lib/protocol/validatorPrimitives.js +1 -1
  46. package/lib/remote/playwrightConnection.js +10 -8
  47. package/lib/remote/playwrightPipeServer.js +100 -0
  48. package/lib/remote/playwrightServer.js +13 -8
  49. package/lib/remote/playwrightWebSocketServer.js +73 -0
  50. package/lib/remote/serverTransport.js +96 -0
  51. package/lib/server/android/android.js +2 -2
  52. package/lib/server/bidi/bidiBrowser.js +30 -8
  53. package/lib/server/bidi/bidiChromium.js +18 -5
  54. package/lib/server/bidi/bidiNetworkManager.js +39 -11
  55. package/lib/server/bidi/bidiPage.js +31 -15
  56. package/lib/server/bidi/third_party/firefoxPrefs.js +3 -1
  57. package/lib/server/browser.js +84 -21
  58. package/lib/server/browserContext.js +97 -58
  59. package/lib/server/browserType.js +14 -12
  60. package/lib/server/chromium/chromium.js +15 -13
  61. package/lib/server/chromium/crBrowser.js +18 -10
  62. package/lib/server/chromium/crNetworkManager.js +4 -4
  63. package/lib/server/chromium/crPage.js +26 -64
  64. package/lib/server/chromium/crServiceWorker.js +5 -4
  65. package/lib/server/clock.js +33 -33
  66. package/lib/server/console.js +5 -1
  67. package/lib/server/debugController.js +12 -6
  68. package/lib/server/debugger.js +40 -47
  69. package/lib/server/deviceDescriptorsSource.json +137 -137
  70. package/lib/server/dispatchers/browserContextDispatcher.js +27 -30
  71. package/lib/server/dispatchers/browserDispatcher.js +11 -5
  72. package/lib/server/dispatchers/browserTypeDispatcher.js +7 -0
  73. package/lib/server/dispatchers/cdpSessionDispatcher.js +4 -1
  74. package/lib/server/dispatchers/debuggerDispatcher.js +84 -0
  75. package/lib/server/dispatchers/dispatcher.js +1 -1
  76. package/lib/server/dispatchers/disposableDispatcher.js +39 -0
  77. package/lib/server/dispatchers/electronDispatcher.js +2 -1
  78. package/lib/server/dispatchers/frameDispatcher.js +3 -3
  79. package/lib/server/dispatchers/localUtilsDispatcher.js +37 -1
  80. package/lib/server/dispatchers/networkDispatchers.js +6 -5
  81. package/lib/server/dispatchers/pageDispatcher.js +101 -38
  82. package/lib/server/dispatchers/webSocketRouteDispatcher.js +4 -5
  83. package/lib/server/disposable.js +41 -0
  84. package/lib/server/dom.js +44 -26
  85. package/lib/server/download.js +3 -2
  86. package/lib/server/electron/electron.js +12 -7
  87. package/lib/server/firefox/ffBrowser.js +9 -19
  88. package/lib/server/firefox/ffInput.js +21 -5
  89. package/lib/server/firefox/ffNetworkManager.js +2 -2
  90. package/lib/server/firefox/ffPage.js +24 -27
  91. package/lib/server/frames.js +40 -11
  92. package/lib/server/har/harRecorder.js +2 -2
  93. package/lib/server/har/harTracer.js +5 -4
  94. package/lib/server/input.js +49 -4
  95. package/lib/server/instrumentation.js +5 -0
  96. package/lib/server/launchApp.js +0 -1
  97. package/lib/server/localUtils.js +6 -6
  98. package/lib/server/network.js +9 -8
  99. package/lib/server/overlay.js +138 -0
  100. package/lib/server/page.js +111 -51
  101. package/lib/server/progress.js +6 -0
  102. package/lib/server/recorder/recorderApp.js +9 -8
  103. package/lib/server/recorder.js +76 -40
  104. package/lib/server/registry/index.js +54 -81
  105. package/lib/server/registry/nativeDeps.js +1 -0
  106. package/lib/server/screencast.js +90 -143
  107. package/lib/server/trace/recorder/snapshotter.js +2 -2
  108. package/lib/server/trace/recorder/tracing.js +87 -36
  109. package/lib/server/trace/viewer/traceViewer.js +3 -4
  110. package/lib/server/usKeyboardLayout.js +7 -0
  111. package/lib/server/utils/comparators.js +1 -1
  112. package/lib/server/utils/disposable.js +32 -0
  113. package/lib/server/utils/eventsHelper.js +3 -1
  114. package/lib/server/utils/fileUtils.js +16 -2
  115. package/lib/server/utils/happyEyeballs.js +15 -12
  116. package/lib/server/utils/hostPlatform.js +0 -15
  117. package/lib/server/utils/httpServer.js +5 -3
  118. package/lib/server/utils/network.js +2 -1
  119. package/lib/server/utils/nodePlatform.js +0 -6
  120. package/lib/server/utils/processLauncher.js +8 -6
  121. package/lib/server/utils/zipFile.js +2 -2
  122. package/lib/server/videoRecorder.js +82 -12
  123. package/lib/server/webkit/wkBrowser.js +1 -6
  124. package/lib/server/webkit/wkPage.js +27 -25
  125. package/lib/server/webkit/wkWorkers.js +2 -1
  126. package/lib/serverRegistry.js +156 -0
  127. package/lib/tools/backend/browserBackend.js +79 -0
  128. package/lib/tools/backend/common.js +63 -0
  129. package/lib/tools/backend/config.js +41 -0
  130. package/lib/tools/backend/console.js +66 -0
  131. package/lib/tools/backend/context.js +296 -0
  132. package/lib/tools/backend/cookies.js +152 -0
  133. package/lib/tools/backend/devtools.js +69 -0
  134. package/lib/tools/backend/dialogs.js +59 -0
  135. package/lib/tools/backend/evaluate.js +64 -0
  136. package/lib/tools/backend/files.js +60 -0
  137. package/lib/tools/backend/form.js +64 -0
  138. package/lib/tools/backend/keyboard.js +155 -0
  139. package/lib/tools/backend/logFile.js +95 -0
  140. package/lib/tools/backend/mouse.js +168 -0
  141. package/lib/tools/backend/navigate.js +106 -0
  142. package/lib/tools/backend/network.js +135 -0
  143. package/lib/tools/backend/pdf.js +48 -0
  144. package/lib/tools/backend/response.js +305 -0
  145. package/lib/tools/backend/route.js +140 -0
  146. package/lib/tools/backend/runCode.js +77 -0
  147. package/lib/tools/backend/screenshot.js +88 -0
  148. package/lib/tools/backend/sessionLog.js +74 -0
  149. package/lib/tools/backend/snapshot.js +208 -0
  150. package/lib/tools/backend/storage.js +68 -0
  151. package/lib/tools/backend/tab.js +445 -0
  152. package/lib/tools/backend/tabs.js +67 -0
  153. package/lib/tools/backend/tool.js +47 -0
  154. package/lib/tools/backend/tools.js +102 -0
  155. package/lib/tools/backend/tracing.js +78 -0
  156. package/lib/tools/backend/utils.js +83 -0
  157. package/lib/tools/backend/verify.js +151 -0
  158. package/lib/tools/backend/video.js +98 -0
  159. package/lib/tools/backend/wait.js +63 -0
  160. package/lib/tools/backend/webstorage.js +223 -0
  161. package/lib/tools/cli-client/cli.js +6 -0
  162. package/lib/tools/cli-client/help.json +399 -0
  163. package/lib/tools/cli-client/minimist.js +128 -0
  164. package/lib/tools/cli-client/program.js +350 -0
  165. package/lib/tools/cli-client/registry.js +176 -0
  166. package/lib/tools/cli-client/session.js +289 -0
  167. package/lib/tools/cli-client/skill/SKILL.md +328 -0
  168. package/lib/tools/cli-client/skill/references/element-attributes.md +23 -0
  169. package/lib/tools/cli-client/skill/references/playwright-tests.md +39 -0
  170. package/lib/tools/cli-client/skill/references/request-mocking.md +87 -0
  171. package/lib/tools/cli-client/skill/references/running-code.md +231 -0
  172. package/lib/tools/cli-client/skill/references/session-management.md +169 -0
  173. package/lib/tools/cli-client/skill/references/storage-state.md +275 -0
  174. package/lib/tools/cli-client/skill/references/test-generation.md +88 -0
  175. package/lib/tools/cli-client/skill/references/tracing.md +139 -0
  176. package/lib/tools/cli-client/skill/references/video-recording.md +143 -0
  177. package/lib/tools/cli-daemon/command.js +73 -0
  178. package/lib/tools/cli-daemon/commands.js +956 -0
  179. package/lib/tools/cli-daemon/daemon.js +157 -0
  180. package/lib/tools/cli-daemon/helpGenerator.js +177 -0
  181. package/lib/tools/cli-daemon/program.js +129 -0
  182. package/lib/tools/dashboard/appIcon.png +0 -0
  183. package/lib/tools/dashboard/dashboardApp.js +284 -0
  184. package/lib/tools/dashboard/dashboardController.js +296 -0
  185. package/lib/tools/exports.js +60 -0
  186. package/lib/tools/mcp/browserFactory.js +233 -0
  187. package/lib/tools/mcp/cdpRelay.js +352 -0
  188. package/lib/tools/mcp/cli-stub.js +7 -0
  189. package/lib/tools/mcp/config.d.js +16 -0
  190. package/lib/tools/mcp/config.js +446 -0
  191. package/lib/tools/mcp/configIni.js +189 -0
  192. package/lib/tools/mcp/extensionContextFactory.js +55 -0
  193. package/lib/tools/mcp/index.js +62 -0
  194. package/lib/tools/mcp/log.js +35 -0
  195. package/lib/tools/mcp/program.js +107 -0
  196. package/lib/tools/mcp/protocol.js +28 -0
  197. package/lib/tools/mcp/watchdog.js +44 -0
  198. package/lib/tools/trace/SKILL.md +171 -0
  199. package/lib/{server/trace/viewer/traceParser.js → tools/trace/installSkill.js} +15 -39
  200. package/lib/tools/trace/traceActions.js +142 -0
  201. package/lib/tools/trace/traceAttachments.js +69 -0
  202. package/lib/tools/trace/traceCli.js +87 -0
  203. package/lib/tools/trace/traceConsole.js +97 -0
  204. package/lib/tools/trace/traceErrors.js +55 -0
  205. package/lib/tools/trace/traceOpen.js +69 -0
  206. package/lib/tools/trace/traceParser.js +96 -0
  207. package/lib/tools/trace/traceRequests.js +182 -0
  208. package/lib/tools/trace/traceScreenshot.js +68 -0
  209. package/lib/tools/trace/traceSnapshot.js +149 -0
  210. package/lib/tools/trace/traceUtils.js +153 -0
  211. package/lib/tools/utils/connect.js +32 -0
  212. package/lib/tools/utils/mcp/http.js +152 -0
  213. package/lib/tools/utils/mcp/server.js +230 -0
  214. package/lib/tools/utils/mcp/tool.js +47 -0
  215. package/lib/tools/utils/socketConnection.js +108 -0
  216. package/lib/utils/isomorphic/formatUtils.js +64 -0
  217. package/lib/utils/isomorphic/jsonSchema.js +89 -0
  218. package/lib/utils/isomorphic/mimeType.js +7 -2
  219. package/lib/utils/isomorphic/protocolFormatter.js +2 -2
  220. package/lib/utils/isomorphic/protocolMetainfo.js +127 -106
  221. package/lib/utils/isomorphic/stringUtils.js +3 -3
  222. package/lib/utils/isomorphic/timeoutRunner.js +3 -3
  223. package/lib/utils/isomorphic/trace/snapshotRenderer.js +35 -42
  224. package/lib/utils/isomorphic/trace/traceLoader.js +15 -14
  225. package/lib/utils/isomorphic/trace/traceModel.js +3 -2
  226. package/lib/utils/isomorphic/trace/traceModernizer.js +1 -0
  227. package/lib/utils/isomorphic/urlMatch.js +54 -1
  228. package/lib/utils/isomorphic/utilityScriptSerializers.js +11 -0
  229. package/lib/utils.js +6 -2
  230. package/lib/utilsBundle.js +3 -21
  231. package/lib/utilsBundleImpl/index.js +132 -133
  232. package/lib/vite/dashboard/assets/index-BAOybkp8.js +50 -0
  233. package/lib/vite/dashboard/assets/index-CZAYOG76.css +1 -0
  234. package/lib/vite/dashboard/index.html +28 -0
  235. package/lib/vite/htmlReport/index.html +2 -70
  236. package/lib/vite/htmlReport/report.css +1 -0
  237. package/lib/vite/htmlReport/report.js +72 -0
  238. package/lib/vite/recorder/assets/{codeMirrorModule-DadYNm1I.js → codeMirrorModule-C8KMvO9L.js} +20 -20
  239. package/lib/vite/recorder/assets/index-CqAYX1I3.js +193 -0
  240. package/lib/vite/recorder/index.html +1 -1
  241. package/lib/vite/traceViewer/assets/{codeMirrorModule-a5XoALAZ.js → codeMirrorModule-DS0FLvoc.js} +20 -20
  242. package/lib/vite/traceViewer/assets/defaultSettingsView-GTWI-W_B.js +262 -0
  243. package/lib/vite/traceViewer/defaultSettingsView.B4dS75f0.css +1 -0
  244. package/lib/vite/traceViewer/{index.BVu7tZDe.css → index.CzXZzn5A.css} +1 -1
  245. package/lib/vite/traceViewer/{index.BDwrLSGN.js → index.Dtstcb7U.js} +1 -1
  246. package/lib/vite/traceViewer/index.html +4 -4
  247. package/lib/vite/traceViewer/sw.bundle.js +4 -4
  248. package/lib/vite/traceViewer/uiMode.Vipi55dB.js +6 -0
  249. package/lib/vite/traceViewer/uiMode.html +3 -3
  250. package/lib/zipBundleImpl.js +2 -2
  251. package/lib/zodBundle.js +39 -0
  252. package/lib/zodBundleImpl.js +40 -0
  253. package/package.json +6 -1
  254. package/types/protocol.d.ts +947 -51
  255. package/types/types.d.ts +854 -74
  256. package/lib/client/pageAgent.js +0 -64
  257. package/lib/mcpBundleImpl/index.js +0 -147
  258. package/lib/server/agent/actionRunner.js +0 -335
  259. package/lib/server/agent/actions.js +0 -128
  260. package/lib/server/agent/codegen.js +0 -111
  261. package/lib/server/agent/context.js +0 -150
  262. package/lib/server/agent/expectTools.js +0 -156
  263. package/lib/server/agent/pageAgent.js +0 -204
  264. package/lib/server/agent/performTools.js +0 -262
  265. package/lib/server/agent/tool.js +0 -109
  266. package/lib/server/dispatchers/pageAgentDispatcher.js +0 -96
  267. package/lib/vite/recorder/assets/index-BhTWtUlo.js +0 -193
  268. package/lib/vite/traceViewer/assets/defaultSettingsView-CJSZINFr.js +0 -266
  269. package/lib/vite/traceViewer/defaultSettingsView.7ch9cixO.css +0 -1
  270. package/lib/vite/traceViewer/uiMode.CQJ9SCIQ.js +0 -5
  271. /package/lib/{server/utils → utils/isomorphic}/imageUtils.js +0 -0
  272. /package/lib/utils/isomorphic/{traceUtils.js → trace/traceUtils.js} +0 -0
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var browserFactory_exports = {};
30
+ __export(browserFactory_exports, {
31
+ createBrowser: () => createBrowser,
32
+ createBrowserWithInfo: () => createBrowserWithInfo,
33
+ isProfileLocked: () => isProfileLocked
34
+ });
35
+ module.exports = __toCommonJS(browserFactory_exports);
36
+ var import_crypto = __toESM(require("crypto"));
37
+ var import_fs = __toESM(require("fs"));
38
+ var import_net = __toESM(require("net"));
39
+ var import_path = __toESM(require("path"));
40
+ var playwright = __toESM(require("../../.."));
41
+ var import_registry = require("../../server/registry/index");
42
+ var import_log = require("./log");
43
+ var import_context = require("../backend/context");
44
+ var import_extensionContextFactory = require("./extensionContextFactory");
45
+ var import_connect = require("../utils/connect");
46
+ var import_serverRegistry = require("../../serverRegistry");
47
+ var import_connect2 = require("../../client/connect");
48
+ async function createBrowser(config, clientInfo) {
49
+ const { browser } = await createBrowserWithInfo(config, clientInfo);
50
+ return browser;
51
+ }
52
+ async function createBrowserWithInfo(config, clientInfo) {
53
+ if (config.browser.remoteEndpoint)
54
+ return await createRemoteBrowser(config);
55
+ let browser;
56
+ if (config.browser.cdpEndpoint)
57
+ browser = await createCDPBrowser(config, clientInfo);
58
+ else if (config.browser.isolated)
59
+ browser = await createIsolatedBrowser(config, clientInfo);
60
+ else if (config.extension)
61
+ browser = await (0, import_extensionContextFactory.createExtensionBrowser)(config, clientInfo);
62
+ else
63
+ browser = await createPersistentBrowser(config, clientInfo);
64
+ return { browser, browserInfo: browserInfo(browser, config) };
65
+ }
66
+ function browserInfo(browser, config) {
67
+ return {
68
+ // eslint-disable-next-line no-restricted-syntax
69
+ guid: browser._guid,
70
+ browserName: config.browser.browserName,
71
+ launchOptions: config.browser.launchOptions,
72
+ userDataDir: config.browser.userDataDir
73
+ };
74
+ }
75
+ async function createIsolatedBrowser(config, clientInfo) {
76
+ (0, import_log.testDebug)("create browser (isolated)");
77
+ await injectCdpPort(config.browser);
78
+ const browserType = playwright[config.browser.browserName];
79
+ const tracesDir = await computeTracesDir(config, clientInfo);
80
+ const browser = await browserType.launch({
81
+ tracesDir,
82
+ ...config.browser.launchOptions,
83
+ handleSIGINT: false,
84
+ handleSIGTERM: false
85
+ }).catch((error) => {
86
+ if (error.message.includes("Executable doesn't exist"))
87
+ throwBrowserIsNotInstalledError(config);
88
+ throw error;
89
+ });
90
+ await startServer(browser, clientInfo);
91
+ return browser;
92
+ }
93
+ async function createCDPBrowser(config, clientInfo) {
94
+ (0, import_log.testDebug)("create browser (cdp)");
95
+ const browser = await playwright.chromium.connectOverCDP(config.browser.cdpEndpoint, {
96
+ headers: config.browser.cdpHeaders,
97
+ timeout: config.browser.cdpTimeout
98
+ });
99
+ await startServer(browser, clientInfo);
100
+ return browser;
101
+ }
102
+ async function createRemoteBrowser(config) {
103
+ (0, import_log.testDebug)("create browser (remote)");
104
+ const descriptor = await import_serverRegistry.serverRegistry.find(config.browser.remoteEndpoint);
105
+ if (descriptor) {
106
+ const browser2 = await (0, import_connect.connectToBrowserAcrossVersions)(descriptor);
107
+ return {
108
+ browser: browser2,
109
+ browserInfo: {
110
+ guid: descriptor.browser.guid,
111
+ browserName: descriptor.browser.browserName,
112
+ launchOptions: descriptor.browser.launchOptions,
113
+ userDataDir: descriptor.browser.userDataDir
114
+ }
115
+ };
116
+ }
117
+ const endpoint = config.browser.remoteEndpoint;
118
+ const playwrightObject = playwright;
119
+ const browser = await (0, import_connect2.connectToBrowser)(playwrightObject, { endpoint });
120
+ browser._connectToBrowserType(playwrightObject[browser._browserName], {}, void 0);
121
+ return { browser, browserInfo: browserInfo(browser, config) };
122
+ }
123
+ async function createPersistentBrowser(config, clientInfo) {
124
+ (0, import_log.testDebug)("create browser (persistent)");
125
+ await injectCdpPort(config.browser);
126
+ const userDataDir = config.browser.userDataDir ?? await createUserDataDir(config, clientInfo);
127
+ const tracesDir = await computeTracesDir(config, clientInfo);
128
+ if (await isProfileLocked5Times(userDataDir))
129
+ throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
130
+ const browserType = playwright[config.browser.browserName];
131
+ const launchOptions = {
132
+ tracesDir,
133
+ ...config.browser.launchOptions,
134
+ ...config.browser.contextOptions,
135
+ handleSIGINT: false,
136
+ handleSIGTERM: false,
137
+ ignoreDefaultArgs: [
138
+ "--disable-extensions"
139
+ ]
140
+ };
141
+ try {
142
+ const browserContext = await browserType.launchPersistentContext(userDataDir, launchOptions);
143
+ const browser = browserContext.browser();
144
+ await startServer(browser, clientInfo);
145
+ return browser;
146
+ } catch (error) {
147
+ if (error.message.includes("Executable doesn't exist"))
148
+ throwBrowserIsNotInstalledError(config);
149
+ if (error.message.includes("cannot open shared object file: No such file or directory")) {
150
+ const browserName = launchOptions.channel ?? config.browser.browserName;
151
+ throw new Error(`Missing system dependencies required to run browser ${browserName}. Install them with: sudo npx playwright install-deps ${browserName}`);
152
+ }
153
+ if (error.message.includes("ProcessSingleton") || error.message.includes("exitCode=21"))
154
+ throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
155
+ throw error;
156
+ }
157
+ }
158
+ async function createUserDataDir(config, clientInfo) {
159
+ const dir = process.env.PWMCP_PROFILES_DIR_FOR_TEST ?? import_registry.registryDirectory;
160
+ const browserToken = config.browser.launchOptions?.channel ?? config.browser?.browserName;
161
+ const rootPathToken = createHash(clientInfo.cwd);
162
+ const result = import_path.default.join(dir, `mcp-${browserToken}-${rootPathToken}`);
163
+ await import_fs.default.promises.mkdir(result, { recursive: true });
164
+ return result;
165
+ }
166
+ async function injectCdpPort(browserConfig) {
167
+ if (browserConfig.browserName === "chromium")
168
+ browserConfig.launchOptions.cdpPort = await findFreePort();
169
+ }
170
+ async function findFreePort() {
171
+ return new Promise((resolve, reject) => {
172
+ const server = import_net.default.createServer();
173
+ server.listen(0, "127.0.0.1", () => {
174
+ const { port } = server.address();
175
+ server.close(() => resolve(port));
176
+ });
177
+ server.on("error", reject);
178
+ });
179
+ }
180
+ function createHash(data) {
181
+ return import_crypto.default.createHash("sha256").update(data).digest("hex").slice(0, 7);
182
+ }
183
+ async function computeTracesDir(config, clientInfo) {
184
+ return import_path.default.resolve((0, import_context.outputDir)({ config, cwd: clientInfo.cwd }), "traces");
185
+ }
186
+ async function isProfileLocked5Times(userDataDir) {
187
+ for (let i = 0; i < 5; i++) {
188
+ if (!isProfileLocked(userDataDir))
189
+ return false;
190
+ await new Promise((f) => setTimeout(f, 1e3));
191
+ }
192
+ return true;
193
+ }
194
+ function isProfileLocked(userDataDir) {
195
+ const lockFile = process.platform === "win32" ? "lockfile" : "SingletonLock";
196
+ const lockPath = import_path.default.join(userDataDir, lockFile);
197
+ if (process.platform === "win32") {
198
+ try {
199
+ const fd = import_fs.default.openSync(lockPath, "r+");
200
+ import_fs.default.closeSync(fd);
201
+ return false;
202
+ } catch (e) {
203
+ return e.code !== "ENOENT";
204
+ }
205
+ }
206
+ try {
207
+ const target = import_fs.default.readlinkSync(lockPath);
208
+ const pid = parseInt(target.split("-").pop() || "", 10);
209
+ if (isNaN(pid))
210
+ return false;
211
+ process.kill(pid, 0);
212
+ return true;
213
+ } catch {
214
+ return false;
215
+ }
216
+ }
217
+ function throwBrowserIsNotInstalledError(config) {
218
+ const channel = config.browser.launchOptions?.channel ?? config.browser.browserName;
219
+ if (config.skillMode)
220
+ throw new Error(`Browser "${channel}" is not installed. Run \`playwright-cli install-browser ${channel}\` to install`);
221
+ else
222
+ throw new Error(`Browser "${channel}" is not installed. Run \`npx @playwright/mcp install-browser ${channel}\` to install`);
223
+ }
224
+ async function startServer(browser, clientInfo) {
225
+ if (clientInfo.sessionName)
226
+ await browser.bind(clientInfo.sessionName, { workspaceDir: clientInfo.workspaceDir });
227
+ }
228
+ // Annotate the CommonJS export names for ESM import in node:
229
+ 0 && (module.exports = {
230
+ createBrowser,
231
+ createBrowserWithInfo,
232
+ isProfileLocked
233
+ });
@@ -0,0 +1,352 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var cdpRelay_exports = {};
30
+ __export(cdpRelay_exports, {
31
+ CDPRelayServer: () => CDPRelayServer
32
+ });
33
+ module.exports = __toCommonJS(cdpRelay_exports);
34
+ var import_child_process = require("child_process");
35
+ var import_os = __toESM(require("os"));
36
+ var import_utilsBundle = require("../../utilsBundle");
37
+ var import_registry = require("../../server/registry/index");
38
+ var import_manualPromise = require("../../utils/isomorphic/manualPromise");
39
+ var import_http2 = require("../utils/mcp/http");
40
+ var import_log = require("./log");
41
+ var protocol = __toESM(require("./protocol"));
42
+ const debugLogger = (0, import_utilsBundle.debug)("pw:mcp:relay");
43
+ class CDPRelayServer {
44
+ constructor(server, browserChannel, userDataDir, executablePath) {
45
+ this._playwrightConnection = null;
46
+ this._extensionConnection = null;
47
+ this._nextSessionId = 1;
48
+ this._wsHost = (0, import_http2.addressToString)(server.address(), { protocol: "ws" });
49
+ this._browserChannel = browserChannel;
50
+ this._userDataDir = userDataDir;
51
+ this._executablePath = executablePath;
52
+ const uuid = crypto.randomUUID();
53
+ this._cdpPath = `/cdp/${uuid}`;
54
+ this._extensionPath = `/extension/${uuid}`;
55
+ this._resetExtensionConnection();
56
+ this._wss = new import_utilsBundle.wsServer({ server });
57
+ this._wss.on("connection", this._onConnection.bind(this));
58
+ }
59
+ cdpEndpoint() {
60
+ return `${this._wsHost}${this._cdpPath}`;
61
+ }
62
+ extensionEndpoint() {
63
+ return `${this._wsHost}${this._extensionPath}`;
64
+ }
65
+ async ensureExtensionConnectionForMCPContext(clientInfo) {
66
+ debugLogger("Ensuring extension connection for MCP context");
67
+ if (this._extensionConnection)
68
+ return;
69
+ this._connectBrowser(clientInfo);
70
+ debugLogger("Waiting for incoming extension connection");
71
+ await Promise.race([
72
+ this._extensionConnectionPromise,
73
+ new Promise((_, reject) => setTimeout(() => {
74
+ reject(new Error(`Extension connection timeout. Make sure the "Playwright MCP Bridge" extension is installed. See https://github.com/microsoft/playwright-mcp/blob/main/packages/extension/README.md for installation instructions.`));
75
+ }, process.env.PWMCP_TEST_CONNECTION_TIMEOUT ? parseInt(process.env.PWMCP_TEST_CONNECTION_TIMEOUT, 10) : 5e3))
76
+ ]);
77
+ debugLogger("Extension connection established");
78
+ }
79
+ _connectBrowser(clientInfo) {
80
+ const mcpRelayEndpoint = `${this._wsHost}${this._extensionPath}`;
81
+ const url = new URL("chrome-extension://mmlmfjhmonkocbjadbfplnigmagldckm/connect.html");
82
+ url.searchParams.set("mcpRelayUrl", mcpRelayEndpoint);
83
+ const client = {
84
+ name: "Playwright Agent",
85
+ version: require("../../../package.json").version
86
+ };
87
+ url.searchParams.set("client", JSON.stringify(client));
88
+ url.searchParams.set("protocolVersion", process.env.PWMCP_TEST_PROTOCOL_VERSION ?? protocol.VERSION.toString());
89
+ const token = process.env.PLAYWRIGHT_MCP_EXTENSION_TOKEN;
90
+ if (token)
91
+ url.searchParams.set("token", token);
92
+ const href = url.toString();
93
+ const channel = import_registry.registry.isChromiumAlias(this._browserChannel) ? "chromium" : this._browserChannel;
94
+ let executablePath = this._executablePath;
95
+ if (!executablePath) {
96
+ const executableInfo = import_registry.registry.findExecutable(channel);
97
+ if (!executableInfo)
98
+ throw new Error(`Unsupported channel: "${this._browserChannel}"`);
99
+ executablePath = executableInfo.executablePath();
100
+ if (!executablePath)
101
+ throw new Error(`"${this._browserChannel}" executable not found. Make sure it is installed at a standard location.`);
102
+ }
103
+ const args = [];
104
+ if (this._userDataDir)
105
+ args.push(`--user-data-dir=${this._userDataDir}`);
106
+ if (import_os.default.platform() === "linux" && channel === "chromium")
107
+ args.push("--no-sandbox");
108
+ args.push(href);
109
+ (0, import_child_process.spawn)(executablePath, args, {
110
+ windowsHide: true,
111
+ detached: true,
112
+ shell: false,
113
+ stdio: "ignore"
114
+ });
115
+ }
116
+ stop() {
117
+ this.closeConnections("Server stopped");
118
+ this._wss.close();
119
+ }
120
+ closeConnections(reason) {
121
+ this._closePlaywrightConnection(reason);
122
+ this._closeExtensionConnection(reason);
123
+ }
124
+ _onConnection(ws2, request) {
125
+ const url = new URL(`http://localhost${request.url}`);
126
+ debugLogger(`New connection to ${url.pathname}`);
127
+ if (url.pathname === this._cdpPath) {
128
+ this._handlePlaywrightConnection(ws2);
129
+ } else if (url.pathname === this._extensionPath) {
130
+ this._handleExtensionConnection(ws2);
131
+ } else {
132
+ debugLogger(`Invalid path: ${url.pathname}`);
133
+ ws2.close(4004, "Invalid path");
134
+ }
135
+ }
136
+ _handlePlaywrightConnection(ws2) {
137
+ if (this._playwrightConnection) {
138
+ debugLogger("Rejecting second Playwright connection");
139
+ ws2.close(1e3, "Another CDP client already connected");
140
+ return;
141
+ }
142
+ this._playwrightConnection = ws2;
143
+ ws2.on("message", async (data) => {
144
+ try {
145
+ const message = JSON.parse(data.toString());
146
+ await this._handlePlaywrightMessage(message);
147
+ } catch (error) {
148
+ debugLogger(`Error while handling Playwright message
149
+ ${data.toString()}
150
+ `, error);
151
+ }
152
+ });
153
+ ws2.on("close", () => {
154
+ if (this._playwrightConnection !== ws2)
155
+ return;
156
+ this._playwrightConnection = null;
157
+ this._closeExtensionConnection("Playwright client disconnected");
158
+ debugLogger("Playwright WebSocket closed");
159
+ });
160
+ ws2.on("error", (error) => {
161
+ debugLogger("Playwright WebSocket error:", error);
162
+ });
163
+ debugLogger("Playwright MCP connected");
164
+ }
165
+ _closeExtensionConnection(reason) {
166
+ this._extensionConnection?.close(reason);
167
+ this._extensionConnectionPromise.reject(new Error(reason));
168
+ this._resetExtensionConnection();
169
+ }
170
+ _resetExtensionConnection() {
171
+ this._connectedTabInfo = void 0;
172
+ this._extensionConnection = null;
173
+ this._extensionConnectionPromise = new import_manualPromise.ManualPromise();
174
+ void this._extensionConnectionPromise.catch(import_log.logUnhandledError);
175
+ }
176
+ _closePlaywrightConnection(reason) {
177
+ if (this._playwrightConnection?.readyState === import_utilsBundle.ws.OPEN)
178
+ this._playwrightConnection.close(1e3, reason);
179
+ this._playwrightConnection = null;
180
+ }
181
+ _handleExtensionConnection(ws2) {
182
+ if (this._extensionConnection) {
183
+ ws2.close(1e3, "Another extension connection already established");
184
+ return;
185
+ }
186
+ this._extensionConnection = new ExtensionConnection(ws2);
187
+ this._extensionConnection.onclose = (c, reason) => {
188
+ debugLogger("Extension WebSocket closed:", reason, c === this._extensionConnection);
189
+ if (this._extensionConnection !== c)
190
+ return;
191
+ this._resetExtensionConnection();
192
+ this._closePlaywrightConnection(`Extension disconnected: ${reason}`);
193
+ };
194
+ this._extensionConnection.onmessage = this._handleExtensionMessage.bind(this);
195
+ this._extensionConnectionPromise.resolve();
196
+ }
197
+ _handleExtensionMessage(method, params) {
198
+ switch (method) {
199
+ case "forwardCDPEvent":
200
+ const sessionId = params.sessionId || this._connectedTabInfo?.sessionId;
201
+ this._sendToPlaywright({
202
+ sessionId,
203
+ method: params.method,
204
+ params: params.params
205
+ });
206
+ break;
207
+ }
208
+ }
209
+ async _handlePlaywrightMessage(message) {
210
+ debugLogger("\u2190 Playwright:", `${message.method} (id=${message.id})`);
211
+ const { id, sessionId, method, params } = message;
212
+ try {
213
+ const result = await this._handleCDPCommand(method, params, sessionId);
214
+ this._sendToPlaywright({ id, sessionId, result });
215
+ } catch (e) {
216
+ debugLogger("Error in the extension:", e);
217
+ this._sendToPlaywright({
218
+ id,
219
+ sessionId,
220
+ error: { message: e.message }
221
+ });
222
+ }
223
+ }
224
+ async _handleCDPCommand(method, params, sessionId) {
225
+ switch (method) {
226
+ case "Browser.getVersion": {
227
+ return {
228
+ protocolVersion: "1.3",
229
+ product: "Chrome/Extension-Bridge",
230
+ userAgent: "CDP-Bridge-Server/1.0.0"
231
+ };
232
+ }
233
+ case "Browser.setDownloadBehavior": {
234
+ return {};
235
+ }
236
+ case "Target.setAutoAttach": {
237
+ if (sessionId)
238
+ break;
239
+ const { targetInfo } = await this._extensionConnection.send("attachToTab", {});
240
+ this._connectedTabInfo = {
241
+ targetInfo,
242
+ sessionId: `pw-tab-${this._nextSessionId++}`
243
+ };
244
+ debugLogger("Simulating auto-attach");
245
+ this._sendToPlaywright({
246
+ method: "Target.attachedToTarget",
247
+ params: {
248
+ sessionId: this._connectedTabInfo.sessionId,
249
+ targetInfo: {
250
+ ...this._connectedTabInfo.targetInfo,
251
+ attached: true
252
+ },
253
+ waitingForDebugger: false
254
+ }
255
+ });
256
+ return {};
257
+ }
258
+ case "Target.getTargetInfo": {
259
+ return this._connectedTabInfo?.targetInfo;
260
+ }
261
+ }
262
+ return await this._forwardToExtension(method, params, sessionId);
263
+ }
264
+ async _forwardToExtension(method, params, sessionId) {
265
+ if (!this._extensionConnection)
266
+ throw new Error("Extension not connected");
267
+ if (this._connectedTabInfo?.sessionId === sessionId)
268
+ sessionId = void 0;
269
+ return await this._extensionConnection.send("forwardCDPCommand", { sessionId, method, params });
270
+ }
271
+ _sendToPlaywright(message) {
272
+ debugLogger("\u2192 Playwright:", `${message.method ?? `response(id=${message.id})`}`);
273
+ this._playwrightConnection?.send(JSON.stringify(message));
274
+ }
275
+ }
276
+ class ExtensionConnection {
277
+ constructor(ws2) {
278
+ this._callbacks = /* @__PURE__ */ new Map();
279
+ this._lastId = 0;
280
+ this._ws = ws2;
281
+ this._ws.on("message", this._onMessage.bind(this));
282
+ this._ws.on("close", this._onClose.bind(this));
283
+ this._ws.on("error", this._onError.bind(this));
284
+ }
285
+ async send(method, params) {
286
+ if (this._ws.readyState !== import_utilsBundle.ws.OPEN)
287
+ throw new Error(`Unexpected WebSocket state: ${this._ws.readyState}`);
288
+ const id = ++this._lastId;
289
+ this._ws.send(JSON.stringify({ id, method, params }));
290
+ const error = new Error(`Protocol error: ${method}`);
291
+ return new Promise((resolve, reject) => {
292
+ this._callbacks.set(id, { resolve, reject, error });
293
+ });
294
+ }
295
+ close(message) {
296
+ debugLogger("closing extension connection:", message);
297
+ if (this._ws.readyState === import_utilsBundle.ws.OPEN)
298
+ this._ws.close(1e3, message);
299
+ }
300
+ _onMessage(event) {
301
+ const eventData = event.toString();
302
+ let parsedJson;
303
+ try {
304
+ parsedJson = JSON.parse(eventData);
305
+ } catch (e) {
306
+ debugLogger(`<closing ws> Closing websocket due to malformed JSON. eventData=${eventData} e=${e?.message}`);
307
+ this._ws.close();
308
+ return;
309
+ }
310
+ try {
311
+ this._handleParsedMessage(parsedJson);
312
+ } catch (e) {
313
+ debugLogger(`<closing ws> Closing websocket due to failed onmessage callback. eventData=${eventData} e=${e?.message}`);
314
+ this._ws.close();
315
+ }
316
+ }
317
+ _handleParsedMessage(object) {
318
+ if (object.id && this._callbacks.has(object.id)) {
319
+ const callback = this._callbacks.get(object.id);
320
+ this._callbacks.delete(object.id);
321
+ if (object.error) {
322
+ const error = callback.error;
323
+ error.message = object.error;
324
+ callback.reject(error);
325
+ } else {
326
+ callback.resolve(object.result);
327
+ }
328
+ } else if (object.id) {
329
+ debugLogger("\u2190 Extension: unexpected response", object);
330
+ } else {
331
+ this.onmessage?.(object.method, object.params);
332
+ }
333
+ }
334
+ _onClose(event) {
335
+ debugLogger(`<ws closed> code=${event.code} reason=${event.reason}`);
336
+ this._dispose();
337
+ this.onclose?.(this, event.reason);
338
+ }
339
+ _onError(event) {
340
+ debugLogger(`<ws error> message=${event.message} type=${event.type} target=${event.target}`);
341
+ this._dispose();
342
+ }
343
+ _dispose() {
344
+ for (const callback of this._callbacks.values())
345
+ callback.reject(new Error("WebSocket closed"));
346
+ this._callbacks.clear();
347
+ }
348
+ }
349
+ // Annotate the CommonJS export names for ESM import in node:
350
+ 0 && (module.exports = {
351
+ CDPRelayServer
352
+ });
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ var import_utilsBundle = require("../../utilsBundle");
3
+ var import_program = require("./program");
4
+ const packageJSON = require("../../../package.json");
5
+ const p = import_utilsBundle.program.version("Version " + packageJSON.version).name("Playwright MCP");
6
+ (0, import_program.decorateMCPCommand)(p);
7
+ void import_utilsBundle.program.parseAsync(process.argv);
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var config_d_exports = {};
16
+ module.exports = __toCommonJS(config_d_exports);