@one2x/playwright 1.57.0-alpha.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 (331) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +168 -0
  4. package/ThirdPartyNotices.txt +6277 -0
  5. package/cli.js +19 -0
  6. package/index.d.ts +17 -0
  7. package/index.js +17 -0
  8. package/index.mjs +18 -0
  9. package/jsx-runtime.js +42 -0
  10. package/jsx-runtime.mjs +21 -0
  11. package/lib/agents/copilot-setup-steps.yml +34 -0
  12. package/lib/agents/generateAgents.js +394 -0
  13. package/lib/agents/generateAgents.js.map +7 -0
  14. package/lib/agents/playwright-test-coverage.prompt.md +31 -0
  15. package/lib/agents/playwright-test-generate.prompt.md +8 -0
  16. package/lib/agents/playwright-test-generator.agent.md +88 -0
  17. package/lib/agents/playwright-test-heal.prompt.md +6 -0
  18. package/lib/agents/playwright-test-healer.agent.md +55 -0
  19. package/lib/agents/playwright-test-plan.prompt.md +9 -0
  20. package/lib/agents/playwright-test-planner.agent.md +117 -0
  21. package/lib/common/config.js +280 -0
  22. package/lib/common/config.js.map +7 -0
  23. package/lib/common/configLoader.js +344 -0
  24. package/lib/common/configLoader.js.map +7 -0
  25. package/lib/common/esmLoaderHost.js +102 -0
  26. package/lib/common/esmLoaderHost.js.map +7 -0
  27. package/lib/common/expectBundle.js +52 -0
  28. package/lib/common/expectBundle.js.map +7 -0
  29. package/lib/common/expectBundleImpl.js +389 -0
  30. package/lib/common/expectBundleImpl.js.map +7 -0
  31. package/lib/common/fixtures.js +302 -0
  32. package/lib/common/fixtures.js.map +7 -0
  33. package/lib/common/globals.js +58 -0
  34. package/lib/common/globals.js.map +7 -0
  35. package/lib/common/ipc.js +60 -0
  36. package/lib/common/ipc.js.map +7 -0
  37. package/lib/common/poolBuilder.js +85 -0
  38. package/lib/common/poolBuilder.js.map +7 -0
  39. package/lib/common/process.js +104 -0
  40. package/lib/common/process.js.map +7 -0
  41. package/lib/common/suiteUtils.js +140 -0
  42. package/lib/common/suiteUtils.js.map +7 -0
  43. package/lib/common/test.js +321 -0
  44. package/lib/common/test.js.map +7 -0
  45. package/lib/common/testLoader.js +101 -0
  46. package/lib/common/testLoader.js.map +7 -0
  47. package/lib/common/testType.js +298 -0
  48. package/lib/common/testType.js.map +7 -0
  49. package/lib/common/validators.js +68 -0
  50. package/lib/common/validators.js.map +7 -0
  51. package/lib/fsWatcher.js +67 -0
  52. package/lib/fsWatcher.js.map +7 -0
  53. package/lib/index.js +682 -0
  54. package/lib/index.js.map +7 -0
  55. package/lib/internalsForTest.js +42 -0
  56. package/lib/internalsForTest.js.map +7 -0
  57. package/lib/isomorphic/events.js +77 -0
  58. package/lib/isomorphic/events.js.map +7 -0
  59. package/lib/isomorphic/folders.js +30 -0
  60. package/lib/isomorphic/folders.js.map +7 -0
  61. package/lib/isomorphic/stringInternPool.js +69 -0
  62. package/lib/isomorphic/stringInternPool.js.map +7 -0
  63. package/lib/isomorphic/teleReceiver.js +508 -0
  64. package/lib/isomorphic/teleReceiver.js.map +7 -0
  65. package/lib/isomorphic/teleSuiteUpdater.js +137 -0
  66. package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
  67. package/lib/isomorphic/testServerConnection.js +211 -0
  68. package/lib/isomorphic/testServerConnection.js.map +7 -0
  69. package/lib/isomorphic/testServerInterface.js +16 -0
  70. package/lib/isomorphic/testServerInterface.js.map +7 -0
  71. package/lib/isomorphic/testTree.js +334 -0
  72. package/lib/isomorphic/testTree.js.map +7 -0
  73. package/lib/isomorphic/types.d.js +16 -0
  74. package/lib/isomorphic/types.d.js.map +7 -0
  75. package/lib/loader/loaderMain.js +59 -0
  76. package/lib/loader/loaderMain.js.map +7 -0
  77. package/lib/matchers/expect.js +325 -0
  78. package/lib/matchers/expect.js.map +7 -0
  79. package/lib/matchers/matcherHint.js +87 -0
  80. package/lib/matchers/matcherHint.js.map +7 -0
  81. package/lib/matchers/matchers.js +366 -0
  82. package/lib/matchers/matchers.js.map +7 -0
  83. package/lib/matchers/toBeTruthy.js +73 -0
  84. package/lib/matchers/toBeTruthy.js.map +7 -0
  85. package/lib/matchers/toEqual.js +99 -0
  86. package/lib/matchers/toEqual.js.map +7 -0
  87. package/lib/matchers/toHaveURL.js +102 -0
  88. package/lib/matchers/toHaveURL.js.map +7 -0
  89. package/lib/matchers/toMatchAriaSnapshot.js +159 -0
  90. package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
  91. package/lib/matchers/toMatchSnapshot.js +341 -0
  92. package/lib/matchers/toMatchSnapshot.js.map +7 -0
  93. package/lib/matchers/toMatchText.js +99 -0
  94. package/lib/matchers/toMatchText.js.map +7 -0
  95. package/lib/mcp/browser/actions.d.js +16 -0
  96. package/lib/mcp/browser/actions.d.js.map +7 -0
  97. package/lib/mcp/browser/browserContextFactory.js +357 -0
  98. package/lib/mcp/browser/browserContextFactory.js.map +7 -0
  99. package/lib/mcp/browser/browserServerBackend.js +76 -0
  100. package/lib/mcp/browser/browserServerBackend.js.map +7 -0
  101. package/lib/mcp/browser/codegen.js +66 -0
  102. package/lib/mcp/browser/codegen.js.map +7 -0
  103. package/lib/mcp/browser/config.js +425 -0
  104. package/lib/mcp/browser/config.js.map +7 -0
  105. package/lib/mcp/browser/context.js +287 -0
  106. package/lib/mcp/browser/context.js.map +7 -0
  107. package/lib/mcp/browser/response.js +228 -0
  108. package/lib/mcp/browser/response.js.map +7 -0
  109. package/lib/mcp/browser/sessionLog.js +160 -0
  110. package/lib/mcp/browser/sessionLog.js.map +7 -0
  111. package/lib/mcp/browser/tab.js +280 -0
  112. package/lib/mcp/browser/tab.js.map +7 -0
  113. package/lib/mcp/browser/tools/actionRetry.js +40 -0
  114. package/lib/mcp/browser/tools/actionRetry.js.map +7 -0
  115. package/lib/mcp/browser/tools/common.js +63 -0
  116. package/lib/mcp/browser/tools/common.js.map +7 -0
  117. package/lib/mcp/browser/tools/console.js +44 -0
  118. package/lib/mcp/browser/tools/console.js.map +7 -0
  119. package/lib/mcp/browser/tools/dialogs.js +60 -0
  120. package/lib/mcp/browser/tools/dialogs.js.map +7 -0
  121. package/lib/mcp/browser/tools/evaluate.js +69 -0
  122. package/lib/mcp/browser/tools/evaluate.js.map +7 -0
  123. package/lib/mcp/browser/tools/files.js +58 -0
  124. package/lib/mcp/browser/tools/files.js.map +7 -0
  125. package/lib/mcp/browser/tools/form.js +79 -0
  126. package/lib/mcp/browser/tools/form.js.map +7 -0
  127. package/lib/mcp/browser/tools/install.js +69 -0
  128. package/lib/mcp/browser/tools/install.js.map +7 -0
  129. package/lib/mcp/browser/tools/keyboard.js +84 -0
  130. package/lib/mcp/browser/tools/keyboard.js.map +7 -0
  131. package/lib/mcp/browser/tools/mouse.js +107 -0
  132. package/lib/mcp/browser/tools/mouse.js.map +7 -0
  133. package/lib/mcp/browser/tools/navigate.js +62 -0
  134. package/lib/mcp/browser/tools/navigate.js.map +7 -0
  135. package/lib/mcp/browser/tools/network.js +54 -0
  136. package/lib/mcp/browser/tools/network.js.map +7 -0
  137. package/lib/mcp/browser/tools/pdf.js +59 -0
  138. package/lib/mcp/browser/tools/pdf.js.map +7 -0
  139. package/lib/mcp/browser/tools/screenshot.js +106 -0
  140. package/lib/mcp/browser/tools/screenshot.js.map +7 -0
  141. package/lib/mcp/browser/tools/snapshot.js +312 -0
  142. package/lib/mcp/browser/tools/snapshot.js.map +7 -0
  143. package/lib/mcp/browser/tools/tabs.js +67 -0
  144. package/lib/mcp/browser/tools/tabs.js.map +7 -0
  145. package/lib/mcp/browser/tools/tool.js +49 -0
  146. package/lib/mcp/browser/tools/tool.js.map +7 -0
  147. package/lib/mcp/browser/tools/tracing.js +74 -0
  148. package/lib/mcp/browser/tools/tracing.js.map +7 -0
  149. package/lib/mcp/browser/tools/utils.js +96 -0
  150. package/lib/mcp/browser/tools/utils.js.map +7 -0
  151. package/lib/mcp/browser/tools/verify.js +153 -0
  152. package/lib/mcp/browser/tools/verify.js.map +7 -0
  153. package/lib/mcp/browser/tools/wait.js +63 -0
  154. package/lib/mcp/browser/tools/wait.js.map +7 -0
  155. package/lib/mcp/browser/tools.js +80 -0
  156. package/lib/mcp/browser/tools.js.map +7 -0
  157. package/lib/mcp/browser/watchdog.js +44 -0
  158. package/lib/mcp/browser/watchdog.js.map +7 -0
  159. package/lib/mcp/config.d.js +16 -0
  160. package/lib/mcp/config.d.js.map +7 -0
  161. package/lib/mcp/extension/cdpRelay.js +351 -0
  162. package/lib/mcp/extension/cdpRelay.js.map +7 -0
  163. package/lib/mcp/extension/extensionContextFactory.js +75 -0
  164. package/lib/mcp/extension/extensionContextFactory.js.map +7 -0
  165. package/lib/mcp/extension/protocol.js +28 -0
  166. package/lib/mcp/extension/protocol.js.map +7 -0
  167. package/lib/mcp/index.js +61 -0
  168. package/lib/mcp/index.js.map +7 -0
  169. package/lib/mcp/log.js +35 -0
  170. package/lib/mcp/log.js.map +7 -0
  171. package/lib/mcp/program.js +118 -0
  172. package/lib/mcp/program.js.map +7 -0
  173. package/lib/mcp/sdk/bundle.js +81 -0
  174. package/lib/mcp/sdk/bundle.js.map +7 -0
  175. package/lib/mcp/sdk/exports.js +32 -0
  176. package/lib/mcp/sdk/exports.js.map +7 -0
  177. package/lib/mcp/sdk/http.js +276 -0
  178. package/lib/mcp/sdk/http.js.map +7 -0
  179. package/lib/mcp/sdk/inProcessTransport.js +71 -0
  180. package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
  181. package/lib/mcp/sdk/mdb.js +208 -0
  182. package/lib/mcp/sdk/mdb.js.map +7 -0
  183. package/lib/mcp/sdk/proxyBackend.js +128 -0
  184. package/lib/mcp/sdk/proxyBackend.js.map +7 -0
  185. package/lib/mcp/sdk/server.js +190 -0
  186. package/lib/mcp/sdk/server.js.map +7 -0
  187. package/lib/mcp/sdk/tool.js +51 -0
  188. package/lib/mcp/sdk/tool.js.map +7 -0
  189. package/lib/mcp/test/browserBackend.js +98 -0
  190. package/lib/mcp/test/browserBackend.js.map +7 -0
  191. package/lib/mcp/test/generatorTools.js +122 -0
  192. package/lib/mcp/test/generatorTools.js.map +7 -0
  193. package/lib/mcp/test/plannerTools.js +46 -0
  194. package/lib/mcp/test/plannerTools.js.map +7 -0
  195. package/lib/mcp/test/seed.js +82 -0
  196. package/lib/mcp/test/seed.js.map +7 -0
  197. package/lib/mcp/test/streams.js +41 -0
  198. package/lib/mcp/test/streams.js.map +7 -0
  199. package/lib/mcp/test/testBackend.js +97 -0
  200. package/lib/mcp/test/testBackend.js.map +7 -0
  201. package/lib/mcp/test/testContext.js +216 -0
  202. package/lib/mcp/test/testContext.js.map +7 -0
  203. package/lib/mcp/test/testTool.js +30 -0
  204. package/lib/mcp/test/testTool.js.map +7 -0
  205. package/lib/mcp/test/testTools.js +111 -0
  206. package/lib/mcp/test/testTools.js.map +7 -0
  207. package/lib/mcpBundleImpl.js +41 -0
  208. package/lib/mcpBundleImpl.js.map +7 -0
  209. package/lib/plugins/gitCommitInfoPlugin.js +198 -0
  210. package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
  211. package/lib/plugins/index.js +28 -0
  212. package/lib/plugins/index.js.map +7 -0
  213. package/lib/plugins/webServerPlugin.js +233 -0
  214. package/lib/plugins/webServerPlugin.js.map +7 -0
  215. package/lib/program.js +412 -0
  216. package/lib/program.js.map +7 -0
  217. package/lib/reporters/base.js +609 -0
  218. package/lib/reporters/base.js.map +7 -0
  219. package/lib/reporters/blob.js +135 -0
  220. package/lib/reporters/blob.js.map +7 -0
  221. package/lib/reporters/dot.js +82 -0
  222. package/lib/reporters/dot.js.map +7 -0
  223. package/lib/reporters/empty.js +32 -0
  224. package/lib/reporters/empty.js.map +7 -0
  225. package/lib/reporters/github.js +128 -0
  226. package/lib/reporters/github.js.map +7 -0
  227. package/lib/reporters/html.js +623 -0
  228. package/lib/reporters/html.js.map +7 -0
  229. package/lib/reporters/internalReporter.js +130 -0
  230. package/lib/reporters/internalReporter.js.map +7 -0
  231. package/lib/reporters/json.js +254 -0
  232. package/lib/reporters/json.js.map +7 -0
  233. package/lib/reporters/junit.js +232 -0
  234. package/lib/reporters/junit.js.map +7 -0
  235. package/lib/reporters/line.js +113 -0
  236. package/lib/reporters/line.js.map +7 -0
  237. package/lib/reporters/list.js +231 -0
  238. package/lib/reporters/list.js.map +7 -0
  239. package/lib/reporters/listModeReporter.js +69 -0
  240. package/lib/reporters/listModeReporter.js.map +7 -0
  241. package/lib/reporters/markdown.js +144 -0
  242. package/lib/reporters/markdown.js.map +7 -0
  243. package/lib/reporters/merge.js +541 -0
  244. package/lib/reporters/merge.js.map +7 -0
  245. package/lib/reporters/multiplexer.js +104 -0
  246. package/lib/reporters/multiplexer.js.map +7 -0
  247. package/lib/reporters/reporterV2.js +102 -0
  248. package/lib/reporters/reporterV2.js.map +7 -0
  249. package/lib/reporters/teleEmitter.js +298 -0
  250. package/lib/reporters/teleEmitter.js.map +7 -0
  251. package/lib/reporters/versions/blobV1.js +16 -0
  252. package/lib/reporters/versions/blobV1.js.map +7 -0
  253. package/lib/runner/dispatcher.js +491 -0
  254. package/lib/runner/dispatcher.js.map +7 -0
  255. package/lib/runner/failureTracker.js +72 -0
  256. package/lib/runner/failureTracker.js.map +7 -0
  257. package/lib/runner/lastRun.js +77 -0
  258. package/lib/runner/lastRun.js.map +7 -0
  259. package/lib/runner/loadUtils.js +334 -0
  260. package/lib/runner/loadUtils.js.map +7 -0
  261. package/lib/runner/loaderHost.js +89 -0
  262. package/lib/runner/loaderHost.js.map +7 -0
  263. package/lib/runner/processHost.js +161 -0
  264. package/lib/runner/processHost.js.map +7 -0
  265. package/lib/runner/projectUtils.js +241 -0
  266. package/lib/runner/projectUtils.js.map +7 -0
  267. package/lib/runner/rebase.js +189 -0
  268. package/lib/runner/rebase.js.map +7 -0
  269. package/lib/runner/reporters.js +138 -0
  270. package/lib/runner/reporters.js.map +7 -0
  271. package/lib/runner/runner.js +110 -0
  272. package/lib/runner/sigIntWatcher.js +96 -0
  273. package/lib/runner/sigIntWatcher.js.map +7 -0
  274. package/lib/runner/taskRunner.js +127 -0
  275. package/lib/runner/taskRunner.js.map +7 -0
  276. package/lib/runner/tasks.js +410 -0
  277. package/lib/runner/tasks.js.map +7 -0
  278. package/lib/runner/testGroups.js +117 -0
  279. package/lib/runner/testGroups.js.map +7 -0
  280. package/lib/runner/testRunner.js +390 -0
  281. package/lib/runner/testRunner.js.map +7 -0
  282. package/lib/runner/testServer.js +267 -0
  283. package/lib/runner/testServer.js.map +7 -0
  284. package/lib/runner/uiModeReporter.js +30 -0
  285. package/lib/runner/uiModeReporter.js.map +7 -0
  286. package/lib/runner/vcs.js +72 -0
  287. package/lib/runner/vcs.js.map +7 -0
  288. package/lib/runner/watchMode.js +395 -0
  289. package/lib/runner/watchMode.js.map +7 -0
  290. package/lib/runner/workerHost.js +95 -0
  291. package/lib/runner/workerHost.js.map +7 -0
  292. package/lib/third_party/pirates.js +62 -0
  293. package/lib/third_party/pirates.js.map +7 -0
  294. package/lib/third_party/tsconfig-loader.js +103 -0
  295. package/lib/third_party/tsconfig-loader.js.map +7 -0
  296. package/lib/transform/babelBundle.js +43 -0
  297. package/lib/transform/babelBundle.js.map +7 -0
  298. package/lib/transform/babelBundleImpl.js +461 -0
  299. package/lib/transform/babelBundleImpl.js.map +7 -0
  300. package/lib/transform/compilationCache.js +272 -0
  301. package/lib/transform/compilationCache.js.map +7 -0
  302. package/lib/transform/esmLoader.js +104 -0
  303. package/lib/transform/esmLoader.js.map +7 -0
  304. package/lib/transform/portTransport.js +67 -0
  305. package/lib/transform/portTransport.js.map +7 -0
  306. package/lib/transform/transform.js +293 -0
  307. package/lib/transform/transform.js.map +7 -0
  308. package/lib/util.js +403 -0
  309. package/lib/util.js.map +7 -0
  310. package/lib/utilsBundle.js +43 -0
  311. package/lib/utilsBundle.js.map +7 -0
  312. package/lib/utilsBundleImpl.js +100 -0
  313. package/lib/utilsBundleImpl.js.map +7 -0
  314. package/lib/worker/fixtureRunner.js +258 -0
  315. package/lib/worker/fixtureRunner.js.map +7 -0
  316. package/lib/worker/testInfo.js +514 -0
  317. package/lib/worker/testInfo.js.map +7 -0
  318. package/lib/worker/testTracing.js +344 -0
  319. package/lib/worker/testTracing.js.map +7 -0
  320. package/lib/worker/timeoutManager.js +174 -0
  321. package/lib/worker/timeoutManager.js.map +7 -0
  322. package/lib/worker/util.js +31 -0
  323. package/lib/worker/util.js.map +7 -0
  324. package/lib/worker/workerMain.js +520 -0
  325. package/lib/worker/workerMain.js.map +7 -0
  326. package/package.json +74 -0
  327. package/test.d.ts +18 -0
  328. package/test.js +24 -0
  329. package/test.mjs +33 -0
  330. package/types/test.d.ts +10196 -0
  331. package/types/testReporter.d.ts +821 -0
@@ -0,0 +1,76 @@
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 __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var browserServerBackend_exports = {};
20
+ __export(browserServerBackend_exports, {
21
+ BrowserServerBackend: () => BrowserServerBackend
22
+ });
23
+ module.exports = __toCommonJS(browserServerBackend_exports);
24
+ var import_context = require("./context");
25
+ var import_log = require("../log");
26
+ var import_response = require("./response");
27
+ var import_sessionLog = require("./sessionLog");
28
+ var import_tools = require("./tools");
29
+ var import_tool = require("../sdk/tool");
30
+ class BrowserServerBackend {
31
+ constructor(config, factory) {
32
+ this._config = config;
33
+ this._browserContextFactory = factory;
34
+ this._tools = (0, import_tools.filteredTools)(config);
35
+ }
36
+ async initialize(server, clientInfo) {
37
+ this._sessionLog = this._config.saveSession ? await import_sessionLog.SessionLog.create(this._config, clientInfo) : void 0;
38
+ this._context = new import_context.Context({
39
+ config: this._config,
40
+ browserContextFactory: this._browserContextFactory,
41
+ sessionLog: this._sessionLog,
42
+ clientInfo
43
+ });
44
+ }
45
+ async listTools() {
46
+ return this._tools.map((tool) => (0, import_tool.toMcpTool)(tool.schema));
47
+ }
48
+ async callTool(name, rawArguments) {
49
+ const tool = this._tools.find((tool2) => tool2.schema.name === name);
50
+ if (!tool)
51
+ throw new Error(`Tool "${name}" not found`);
52
+ const parsedArguments = tool.schema.inputSchema.parse(rawArguments || {});
53
+ const context = this._context;
54
+ const response = new import_response.Response(context, name, parsedArguments);
55
+ response.logBegin();
56
+ context.setRunningTool(name);
57
+ try {
58
+ await tool.handle(context, parsedArguments, response);
59
+ await response.finish();
60
+ this._sessionLog?.logResponse(response);
61
+ } catch (error) {
62
+ response.addError(String(error));
63
+ } finally {
64
+ context.setRunningTool(void 0);
65
+ }
66
+ response.logEnd();
67
+ return response.serialize();
68
+ }
69
+ serverClosed() {
70
+ void this._context?.dispose().catch(import_log.logUnhandledError);
71
+ }
72
+ }
73
+ // Annotate the CommonJS export names for ESM import in node:
74
+ 0 && (module.exports = {
75
+ BrowserServerBackend
76
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/mcp/browser/browserServerBackend.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FullConfig } from './config';\nimport { Context } from './context';\nimport { logUnhandledError } from '../log';\nimport { Response } from './response';\nimport { SessionLog } from './sessionLog';\nimport { filteredTools } from './tools';\nimport { toMcpTool } from '../sdk/tool';\n\nimport type { Tool } from './tools/tool';\nimport type { BrowserContextFactory } from './browserContextFactory';\nimport type * as mcpServer from '../sdk/server';\nimport type { ServerBackend } from '../sdk/server';\n\nexport class BrowserServerBackend implements ServerBackend {\n private _tools: Tool[];\n private _context: Context | undefined;\n private _sessionLog: SessionLog | undefined;\n private _config: FullConfig;\n private _browserContextFactory: BrowserContextFactory;\n\n constructor(config: FullConfig, factory: BrowserContextFactory) {\n this._config = config;\n this._browserContextFactory = factory;\n this._tools = filteredTools(config);\n }\n\n async initialize(server: mcpServer.Server, clientInfo: mcpServer.ClientInfo): Promise<void> {\n this._sessionLog = this._config.saveSession ? await SessionLog.create(this._config, clientInfo) : undefined;\n this._context = new Context({\n config: this._config,\n browserContextFactory: this._browserContextFactory,\n sessionLog: this._sessionLog,\n clientInfo,\n });\n }\n\n async listTools(): Promise<mcpServer.Tool[]> {\n return this._tools.map(tool => toMcpTool(tool.schema));\n }\n\n async callTool(name: string, rawArguments: mcpServer.CallToolRequest['params']['arguments']) {\n const tool = this._tools.find(tool => tool.schema.name === name)!;\n if (!tool)\n throw new Error(`Tool \"${name}\" not found`);\n const parsedArguments = tool.schema.inputSchema.parse(rawArguments || {});\n const context = this._context!;\n const response = new Response(context, name, parsedArguments);\n response.logBegin();\n context.setRunningTool(name);\n try {\n await tool.handle(context, parsedArguments, response);\n await response.finish();\n this._sessionLog?.logResponse(response);\n } catch (error: any) {\n response.addError(String(error));\n } finally {\n context.setRunningTool(undefined);\n }\n response.logEnd();\n return response.serialize();\n }\n\n serverClosed() {\n void this._context?.dispose().catch(logUnhandledError);\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,qBAAwB;AACxB,iBAAkC;AAClC,sBAAyB;AACzB,wBAA2B;AAC3B,mBAA8B;AAC9B,kBAA0B;AAOnB,MAAM,qBAA8C;AAAA,EAOzD,YAAY,QAAoB,SAAgC;AAC9D,SAAK,UAAU;AACf,SAAK,yBAAyB;AAC9B,SAAK,aAAS,4BAAc,MAAM;AAAA,EACpC;AAAA,EAEA,MAAM,WAAW,QAA0B,YAAiD;AAC1F,SAAK,cAAc,KAAK,QAAQ,cAAc,MAAM,6BAAW,OAAO,KAAK,SAAS,UAAU,IAAI;AAClG,SAAK,WAAW,IAAI,uBAAQ;AAAA,MAC1B,QAAQ,KAAK;AAAA,MACb,uBAAuB,KAAK;AAAA,MAC5B,YAAY,KAAK;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,YAAuC;AAC3C,WAAO,KAAK,OAAO,IAAI,cAAQ,uBAAU,KAAK,MAAM,CAAC;AAAA,EACvD;AAAA,EAEA,MAAM,SAAS,MAAc,cAAgE;AAC3F,UAAM,OAAO,KAAK,OAAO,KAAK,CAAAA,UAAQA,MAAK,OAAO,SAAS,IAAI;AAC/D,QAAI,CAAC;AACH,YAAM,IAAI,MAAM,SAAS,IAAI,aAAa;AAC5C,UAAM,kBAAkB,KAAK,OAAO,YAAY,MAAM,gBAAgB,CAAC,CAAC;AACxE,UAAM,UAAU,KAAK;AACrB,UAAM,WAAW,IAAI,yBAAS,SAAS,MAAM,eAAe;AAC5D,aAAS,SAAS;AAClB,YAAQ,eAAe,IAAI;AAC3B,QAAI;AACF,YAAM,KAAK,OAAO,SAAS,iBAAiB,QAAQ;AACpD,YAAM,SAAS,OAAO;AACtB,WAAK,aAAa,YAAY,QAAQ;AAAA,IACxC,SAAS,OAAY;AACnB,eAAS,SAAS,OAAO,KAAK,CAAC;AAAA,IACjC,UAAE;AACA,cAAQ,eAAe,MAAS;AAAA,IAClC;AACA,aAAS,OAAO;AAChB,WAAO,SAAS,UAAU;AAAA,EAC5B;AAAA,EAEA,eAAe;AACb,SAAK,KAAK,UAAU,QAAQ,EAAE,MAAM,4BAAiB;AAAA,EACvD;AACF;",
6
+ "names": ["tool"]
7
+ }
@@ -0,0 +1,66 @@
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 __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var codegen_exports = {};
20
+ __export(codegen_exports, {
21
+ escapeWithQuotes: () => escapeWithQuotes,
22
+ formatObject: () => formatObject,
23
+ quote: () => quote
24
+ });
25
+ module.exports = __toCommonJS(codegen_exports);
26
+ function escapeWithQuotes(text, char = "'") {
27
+ const stringified = JSON.stringify(text);
28
+ const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\"/g, '"');
29
+ if (char === "'")
30
+ return char + escapedText.replace(/[']/g, "\\'") + char;
31
+ if (char === '"')
32
+ return char + escapedText.replace(/["]/g, '\\"') + char;
33
+ if (char === "`")
34
+ return char + escapedText.replace(/[`]/g, "\\`") + char;
35
+ throw new Error("Invalid escape char");
36
+ }
37
+ function quote(text) {
38
+ return escapeWithQuotes(text, "'");
39
+ }
40
+ function formatObject(value, indent = " ", mode = "multiline") {
41
+ if (typeof value === "string")
42
+ return quote(value);
43
+ if (Array.isArray(value))
44
+ return `[${value.map((o) => formatObject(o)).join(", ")}]`;
45
+ if (typeof value === "object") {
46
+ const keys = Object.keys(value).filter((key) => value[key] !== void 0).sort();
47
+ if (!keys.length)
48
+ return "{}";
49
+ const tokens = [];
50
+ for (const key of keys)
51
+ tokens.push(`${key}: ${formatObject(value[key])}`);
52
+ if (mode === "multiline")
53
+ return `{
54
+ ${tokens.join(`,
55
+ ${indent}`)}
56
+ }`;
57
+ return `{ ${tokens.join(", ")} }`;
58
+ }
59
+ return String(value);
60
+ }
61
+ // Annotate the CommonJS export names for ESM import in node:
62
+ 0 && (module.exports = {
63
+ escapeWithQuotes,
64
+ formatObject,
65
+ quote
66
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/mcp/browser/codegen.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// adapted from:\n// - https://github.com/microsoft/playwright/blob/76ee48dc9d4034536e3ec5b2c7ce8be3b79418a8/packages/playwright-core/src/utils/isomorphic/stringUtils.ts\n// - https://github.com/microsoft/playwright/blob/76ee48dc9d4034536e3ec5b2c7ce8be3b79418a8/packages/playwright-core/src/server/codegen/javascript.ts\n\n// NOTE: this function should not be used to escape any selectors.\nexport function escapeWithQuotes(text: string, char: string = '\\'') {\n const stringified = JSON.stringify(text);\n const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\\\\"/g, '\"');\n if (char === '\\'')\n return char + escapedText.replace(/[']/g, '\\\\\\'') + char;\n if (char === '\"')\n return char + escapedText.replace(/[\"]/g, '\\\\\"') + char;\n if (char === '`')\n return char + escapedText.replace(/[`]/g, '\\\\`') + char;\n throw new Error('Invalid escape char');\n}\n\nexport function quote(text: string) {\n return escapeWithQuotes(text, '\\'');\n}\n\nexport function formatObject(value: any, indent = ' ', mode: 'multiline' | 'oneline' = 'multiline'): string {\n if (typeof value === 'string')\n return quote(value);\n if (Array.isArray(value))\n return `[${value.map(o => formatObject(o)).join(', ')}]`;\n if (typeof value === 'object') {\n const keys = Object.keys(value).filter(key => value[key] !== undefined).sort();\n if (!keys.length)\n return '{}';\n const tokens: string[] = [];\n for (const key of keys)\n tokens.push(`${key}: ${formatObject(value[key])}`);\n if (mode === 'multiline')\n return `{\\n${tokens.join(`,\\n${indent}`)}\\n}`;\n return `{ ${tokens.join(', ')} }`;\n }\n return String(value);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,SAAS,iBAAiB,MAAc,OAAe,KAAM;AAClE,QAAM,cAAc,KAAK,UAAU,IAAI;AACvC,QAAM,cAAc,YAAY,UAAU,GAAG,YAAY,SAAS,CAAC,EAAE,QAAQ,QAAQ,GAAG;AACxF,MAAI,SAAS;AACX,WAAO,OAAO,YAAY,QAAQ,QAAQ,KAAM,IAAI;AACtD,MAAI,SAAS;AACX,WAAO,OAAO,YAAY,QAAQ,QAAQ,KAAK,IAAI;AACrD,MAAI,SAAS;AACX,WAAO,OAAO,YAAY,QAAQ,QAAQ,KAAK,IAAI;AACrD,QAAM,IAAI,MAAM,qBAAqB;AACvC;AAEO,SAAS,MAAM,MAAc;AAClC,SAAO,iBAAiB,MAAM,GAAI;AACpC;AAEO,SAAS,aAAa,OAAY,SAAS,MAAM,OAAgC,aAAqB;AAC3G,MAAI,OAAO,UAAU;AACnB,WAAO,MAAM,KAAK;AACpB,MAAI,MAAM,QAAQ,KAAK;AACrB,WAAO,IAAI,MAAM,IAAI,OAAK,aAAa,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AACvD,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,OAAO,OAAO,KAAK,KAAK,EAAE,OAAO,SAAO,MAAM,GAAG,MAAM,MAAS,EAAE,KAAK;AAC7E,QAAI,CAAC,KAAK;AACR,aAAO;AACT,UAAM,SAAmB,CAAC;AAC1B,eAAW,OAAO;AAChB,aAAO,KAAK,GAAG,GAAG,KAAK,aAAa,MAAM,GAAG,CAAC,CAAC,EAAE;AACnD,QAAI,SAAS;AACX,aAAO;AAAA,EAAM,OAAO,KAAK;AAAA,EAAM,MAAM,EAAE,CAAC;AAAA;AAC1C,WAAO,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,EAC/B;AACA,SAAO,OAAO,KAAK;AACrB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,425 @@
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 config_exports = {};
30
+ __export(config_exports, {
31
+ commaSeparatedList: () => commaSeparatedList,
32
+ configFromCLIOptions: () => configFromCLIOptions,
33
+ configFromURLParams: () => configFromURLParams,
34
+ defaultConfig: () => defaultConfig,
35
+ dotenvFileLoader: () => dotenvFileLoader,
36
+ headerParser: () => headerParser,
37
+ mergeConfig: () => mergeConfig,
38
+ numberParser: () => numberParser,
39
+ outputDir: () => outputDir,
40
+ outputFile: () => outputFile,
41
+ resolutionParser: () => resolutionParser,
42
+ resolveCLIConfig: () => resolveCLIConfig,
43
+ resolveConfig: () => resolveConfig,
44
+ semicolonSeparatedList: () => semicolonSeparatedList
45
+ });
46
+ module.exports = __toCommonJS(config_exports);
47
+ var import_fs = __toESM(require("fs"));
48
+ var import_os = __toESM(require("os"));
49
+ var import_path = __toESM(require("path"));
50
+ var import_playwright_core = require("playwright-core");
51
+ var import_utilsBundle = require("playwright-core/lib/utilsBundle");
52
+ var import_util = require("../../util");
53
+ var import_server = require("../sdk/server");
54
+ const defaultConfig = {
55
+ browser: {
56
+ browserName: "chromium",
57
+ launchOptions: {
58
+ channel: "chrome",
59
+ headless: import_os.default.platform() === "linux" && !process.env.DISPLAY,
60
+ chromiumSandbox: true
61
+ },
62
+ contextOptions: {
63
+ viewport: null
64
+ }
65
+ },
66
+ network: {
67
+ allowedOrigins: void 0,
68
+ blockedOrigins: void 0
69
+ },
70
+ server: {},
71
+ saveTrace: false,
72
+ timeouts: {
73
+ action: 5e3,
74
+ navigation: 6e4
75
+ }
76
+ };
77
+ async function resolveConfig(config) {
78
+ return mergeConfig(defaultConfig, config);
79
+ }
80
+ async function resolveCLIConfig(cliOptions) {
81
+ const configInFile = await loadConfig(cliOptions.config);
82
+ const envOverrides = configFromEnv();
83
+ const cliOverrides = configFromCLIOptions(cliOptions);
84
+ let result = defaultConfig;
85
+ result = mergeConfig(result, configInFile);
86
+ result = mergeConfig(result, envOverrides);
87
+ result = mergeConfig(result, cliOverrides);
88
+ await validateConfig(result);
89
+ return result;
90
+ }
91
+ async function validateConfig(config) {
92
+ if (config.browser.initScript) {
93
+ for (const script of config.browser.initScript) {
94
+ if (!await (0, import_util.fileExistsAsync)(script))
95
+ throw new Error(`Init script file does not exist: ${script}`);
96
+ }
97
+ }
98
+ if (config.sharedBrowserContext && config.saveVideo)
99
+ throw new Error("saveVideo is not supported when sharedBrowserContext is true");
100
+ }
101
+ function configFromCLIOptions(cliOptions) {
102
+ let browserName;
103
+ let channel;
104
+ switch (cliOptions.browser) {
105
+ case "chrome":
106
+ case "chrome-beta":
107
+ case "chrome-canary":
108
+ case "chrome-dev":
109
+ case "chromium":
110
+ case "msedge":
111
+ case "msedge-beta":
112
+ case "msedge-canary":
113
+ case "msedge-dev":
114
+ browserName = "chromium";
115
+ channel = cliOptions.browser;
116
+ break;
117
+ case "firefox":
118
+ browserName = "firefox";
119
+ break;
120
+ case "webkit":
121
+ browserName = "webkit";
122
+ break;
123
+ }
124
+ const launchOptions = {
125
+ channel,
126
+ executablePath: cliOptions.executablePath,
127
+ headless: cliOptions.headless
128
+ };
129
+ if (cliOptions.sandbox === false)
130
+ launchOptions.chromiumSandbox = false;
131
+ if (cliOptions.proxyServer) {
132
+ launchOptions.proxy = {
133
+ server: cliOptions.proxyServer
134
+ };
135
+ if (cliOptions.proxyBypass)
136
+ launchOptions.proxy.bypass = cliOptions.proxyBypass;
137
+ }
138
+ if (cliOptions.device && cliOptions.cdpEndpoint)
139
+ throw new Error("Device emulation is not supported with cdpEndpoint.");
140
+ const contextOptions = cliOptions.device ? import_playwright_core.devices[cliOptions.device] : {};
141
+ if (cliOptions.storageState)
142
+ contextOptions.storageState = cliOptions.storageState;
143
+ if (cliOptions.userAgent)
144
+ contextOptions.userAgent = cliOptions.userAgent;
145
+ if (cliOptions.viewportSize)
146
+ contextOptions.viewport = cliOptions.viewportSize;
147
+ if (cliOptions.ignoreHttpsErrors)
148
+ contextOptions.ignoreHTTPSErrors = true;
149
+ if (cliOptions.blockServiceWorkers)
150
+ contextOptions.serviceWorkers = "block";
151
+ if (cliOptions.grantPermissions)
152
+ contextOptions.permissions = cliOptions.grantPermissions;
153
+ if (cliOptions.saveVideo) {
154
+ contextOptions.recordVideo = {
155
+ // Videos are moved to output directory on saveAs.
156
+ dir: tmpDir(),
157
+ size: cliOptions.saveVideo
158
+ };
159
+ }
160
+ const result = {
161
+ browser: {
162
+ browserName,
163
+ isolated: cliOptions.isolated,
164
+ userDataDir: cliOptions.userDataDir,
165
+ launchOptions,
166
+ contextOptions,
167
+ cdpEndpoint: cliOptions.cdpEndpoint,
168
+ cdpHeaders: cliOptions.cdpHeader,
169
+ initScript: cliOptions.initScript
170
+ },
171
+ server: {
172
+ port: cliOptions.port,
173
+ host: cliOptions.host,
174
+ allowedHosts: cliOptions.allowedHosts
175
+ },
176
+ capabilities: cliOptions.caps,
177
+ network: {
178
+ allowedOrigins: cliOptions.allowedOrigins,
179
+ blockedOrigins: cliOptions.blockedOrigins
180
+ },
181
+ saveSession: cliOptions.saveSession,
182
+ saveTrace: cliOptions.saveTrace,
183
+ saveVideo: cliOptions.saveVideo,
184
+ secrets: cliOptions.secrets,
185
+ sharedBrowserContext: cliOptions.sharedBrowserContext,
186
+ outputDir: cliOptions.outputDir,
187
+ imageResponses: cliOptions.imageResponses,
188
+ testIdAttribute: cliOptions.testIdAttribute,
189
+ timeouts: {
190
+ action: cliOptions.timeoutAction,
191
+ navigation: cliOptions.timeoutNavigation
192
+ }
193
+ };
194
+ return result;
195
+ }
196
+ function configFromEnv() {
197
+ const options = {};
198
+ options.allowedHosts = commaSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_HOSTNAMES);
199
+ options.allowedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_ORIGINS);
200
+ options.blockedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_BLOCKED_ORIGINS);
201
+ options.blockServiceWorkers = envToBoolean(process.env.PLAYWRIGHT_MCP_BLOCK_SERVICE_WORKERS);
202
+ options.browser = envToString(process.env.PLAYWRIGHT_MCP_BROWSER);
203
+ options.caps = commaSeparatedList(process.env.PLAYWRIGHT_MCP_CAPS);
204
+ options.cdpEndpoint = envToString(process.env.PLAYWRIGHT_MCP_CDP_ENDPOINT);
205
+ options.cdpHeader = headerParser(process.env.PLAYWRIGHT_MCP_CDP_HEADERS, {});
206
+ options.config = envToString(process.env.PLAYWRIGHT_MCP_CONFIG);
207
+ options.device = envToString(process.env.PLAYWRIGHT_MCP_DEVICE);
208
+ options.executablePath = envToString(process.env.PLAYWRIGHT_MCP_EXECUTABLE_PATH);
209
+ options.grantPermissions = commaSeparatedList(process.env.PLAYWRIGHT_MCP_GRANT_PERMISSIONS);
210
+ options.headless = envToBoolean(process.env.PLAYWRIGHT_MCP_HEADLESS);
211
+ options.host = envToString(process.env.PLAYWRIGHT_MCP_HOST);
212
+ options.ignoreHttpsErrors = envToBoolean(process.env.PLAYWRIGHT_MCP_IGNORE_HTTPS_ERRORS);
213
+ const initScript = envToString(process.env.PLAYWRIGHT_MCP_INIT_SCRIPT);
214
+ if (initScript)
215
+ options.initScript = [initScript];
216
+ options.isolated = envToBoolean(process.env.PLAYWRIGHT_MCP_ISOLATED);
217
+ if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES === "omit")
218
+ options.imageResponses = "omit";
219
+ options.sandbox = envToBoolean(process.env.PLAYWRIGHT_MCP_SANDBOX);
220
+ options.outputDir = envToString(process.env.PLAYWRIGHT_MCP_OUTPUT_DIR);
221
+ options.port = numberParser(process.env.PLAYWRIGHT_MCP_PORT);
222
+ options.proxyBypass = envToString(process.env.PLAYWRIGHT_MCP_PROXY_BYPASS);
223
+ options.proxyServer = envToString(process.env.PLAYWRIGHT_MCP_PROXY_SERVER);
224
+ options.saveTrace = envToBoolean(process.env.PLAYWRIGHT_MCP_SAVE_TRACE);
225
+ options.saveVideo = resolutionParser("--save-video", process.env.PLAYWRIGHT_MCP_SAVE_VIDEO);
226
+ options.secrets = dotenvFileLoader(process.env.PLAYWRIGHT_MCP_SECRETS_FILE);
227
+ options.storageState = envToString(process.env.PLAYWRIGHT_MCP_STORAGE_STATE);
228
+ options.testIdAttribute = envToString(process.env.PLAYWRIGHT_MCP_TEST_ID_ATTRIBUTE);
229
+ options.timeoutAction = numberParser(process.env.PLAYWRIGHT_MCP_TIMEOUT_ACTION);
230
+ options.timeoutNavigation = numberParser(process.env.PLAYWRIGHT_MCP_TIMEOUT_NAVIGATION);
231
+ options.userAgent = envToString(process.env.PLAYWRIGHT_MCP_USER_AGENT);
232
+ options.userDataDir = envToString(process.env.PLAYWRIGHT_MCP_USER_DATA_DIR);
233
+ options.viewportSize = resolutionParser("--viewport-size", process.env.PLAYWRIGHT_MCP_VIEWPORT_SIZE);
234
+ return configFromCLIOptions(options);
235
+ }
236
+ async function loadConfig(configFile) {
237
+ if (!configFile)
238
+ return {};
239
+ try {
240
+ return JSON.parse(await import_fs.default.promises.readFile(configFile, "utf8"));
241
+ } catch (error) {
242
+ throw new Error(`Failed to load config file: ${configFile}, ${error}`);
243
+ }
244
+ }
245
+ function tmpDir() {
246
+ return import_path.default.join(process.env.PW_TMPDIR_FOR_TEST ?? import_os.default.tmpdir(), "playwright-mcp-output");
247
+ }
248
+ function outputDir(config, clientInfo) {
249
+ const rootPath = (0, import_server.firstRootPath)(clientInfo);
250
+ return config.outputDir ?? (rootPath ? import_path.default.join(rootPath, ".playwright-mcp") : void 0) ?? import_path.default.join(tmpDir(), String(clientInfo.timestamp));
251
+ }
252
+ async function outputFile(config, clientInfo, fileName, options) {
253
+ const file = await resolveFile(config, clientInfo, fileName, options);
254
+ (0, import_utilsBundle.debug)("pw:mcp:file")(options.reason, file);
255
+ return file;
256
+ }
257
+ async function resolveFile(config, clientInfo, fileName, options) {
258
+ const dir = outputDir(config, clientInfo);
259
+ if (options.origin === "code")
260
+ return import_path.default.resolve(dir, fileName);
261
+ if (options.origin === "llm") {
262
+ fileName = fileName.split("\\").join("/");
263
+ const resolvedFile = import_path.default.resolve(dir, fileName);
264
+ if (!resolvedFile.startsWith(import_path.default.resolve(dir) + import_path.default.sep))
265
+ throw new Error(`Resolved file path ${resolvedFile} is outside of the output directory ${dir}. Use relative file names to stay within the output directory.`);
266
+ return resolvedFile;
267
+ }
268
+ return import_path.default.join(dir, sanitizeForFilePath(fileName));
269
+ }
270
+ function pickDefined(obj) {
271
+ return Object.fromEntries(
272
+ Object.entries(obj ?? {}).filter(([_, v]) => v !== void 0)
273
+ );
274
+ }
275
+ function mergeConfig(base, overrides) {
276
+ const browser = {
277
+ ...pickDefined(base.browser),
278
+ ...pickDefined(overrides.browser),
279
+ browserName: overrides.browser?.browserName ?? base.browser?.browserName ?? "chromium",
280
+ isolated: overrides.browser?.isolated ?? base.browser?.isolated ?? false,
281
+ launchOptions: {
282
+ ...pickDefined(base.browser?.launchOptions),
283
+ ...pickDefined(overrides.browser?.launchOptions),
284
+ ...{ assistantMode: true }
285
+ },
286
+ contextOptions: {
287
+ ...pickDefined(base.browser?.contextOptions),
288
+ ...pickDefined(overrides.browser?.contextOptions)
289
+ }
290
+ };
291
+ if (browser.browserName !== "chromium" && browser.launchOptions)
292
+ delete browser.launchOptions.channel;
293
+ return {
294
+ ...pickDefined(base),
295
+ ...pickDefined(overrides),
296
+ browser,
297
+ network: {
298
+ ...pickDefined(base.network),
299
+ ...pickDefined(overrides.network)
300
+ },
301
+ server: {
302
+ ...pickDefined(base.server),
303
+ ...pickDefined(overrides.server)
304
+ },
305
+ timeouts: {
306
+ ...pickDefined(base.timeouts),
307
+ ...pickDefined(overrides.timeouts)
308
+ }
309
+ };
310
+ }
311
+ function semicolonSeparatedList(value) {
312
+ if (!value)
313
+ return void 0;
314
+ return value.split(";").map((v) => v.trim());
315
+ }
316
+ function commaSeparatedList(value) {
317
+ if (!value)
318
+ return void 0;
319
+ return value.split(",").map((v) => v.trim());
320
+ }
321
+ function dotenvFileLoader(value) {
322
+ if (!value)
323
+ return void 0;
324
+ return import_utilsBundle.dotenv.parse(import_fs.default.readFileSync(value, "utf8"));
325
+ }
326
+ function numberParser(value) {
327
+ if (!value)
328
+ return void 0;
329
+ return +value;
330
+ }
331
+ function resolutionParser(name, value) {
332
+ if (!value)
333
+ return void 0;
334
+ if (value.includes("x")) {
335
+ const [width, height] = value.split("x").map((v) => +v);
336
+ if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0)
337
+ throw new Error(`Invalid resolution format: use ${name}="800x600"`);
338
+ return { width, height };
339
+ }
340
+ if (value.includes(",")) {
341
+ const [width, height] = value.split(",").map((v) => +v);
342
+ if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0)
343
+ throw new Error(`Invalid resolution format: use ${name}="800x600"`);
344
+ return { width, height };
345
+ }
346
+ throw new Error(`Invalid resolution format: use ${name}="800x600"`);
347
+ }
348
+ function headerParser(arg, previous) {
349
+ if (!arg)
350
+ return previous || {};
351
+ const result = previous || {};
352
+ const [name, value] = arg.split(":").map((v) => v.trim());
353
+ result[name] = value;
354
+ return result;
355
+ }
356
+ function envToBoolean(value) {
357
+ if (value === "true" || value === "1")
358
+ return true;
359
+ if (value === "false" || value === "0")
360
+ return false;
361
+ return void 0;
362
+ }
363
+ function envToString(value) {
364
+ return value ? value.trim() : void 0;
365
+ }
366
+ function sanitizeForFilePath(s) {
367
+ const sanitize = (s2) => s2.replace(/[\x00-\x2C\x2E-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]+/g, "-");
368
+ const separator = s.lastIndexOf(".");
369
+ if (separator === -1)
370
+ return sanitize(s);
371
+ return sanitize(s.substring(0, separator)) + "." + sanitize(s.substring(separator + 1));
372
+ }
373
+ function configFromURLParams(url) {
374
+ const getParam = (name) => url.searchParams.get(name) || void 0;
375
+ const options = {};
376
+ options.allowedOrigins = semicolonSeparatedList(getParam("allowed-origins"));
377
+ options.blockedOrigins = semicolonSeparatedList(getParam("blocked-origins"));
378
+ options.blockServiceWorkers = queryToBoolean(getParam("block-service-workers"));
379
+ options.browser = getParam("browser");
380
+ options.caps = commaSeparatedList(getParam("caps"));
381
+ options.cdpEndpoint = getParam("cdp-endpoint");
382
+ options.device = getParam("device");
383
+ options.headless = queryToBoolean(getParam("headless"));
384
+ options.ignoreHttpsErrors = queryToBoolean(getParam("ignore-https-errors"));
385
+ options.isolated = queryToBoolean(getParam("isolated"));
386
+ const imageResponses = getParam("image-responses");
387
+ if (imageResponses === "omit" || imageResponses === "allow")
388
+ options.imageResponses = imageResponses;
389
+ options.sandbox = queryToBoolean(getParam("sandbox"));
390
+ options.proxyBypass = getParam("proxy-bypass");
391
+ options.proxyServer = getParam("proxy-server");
392
+ options.storageState = getParam("storage-state");
393
+ options.userAgent = getParam("user-agent");
394
+ const viewportSize = getParam("viewport-size");
395
+ if (viewportSize)
396
+ options.viewportSize = resolutionParser("--viewport-size", viewportSize);
397
+ if (!Object.values(options).some((v) => v !== void 0)) {
398
+ return {};
399
+ }
400
+ return configFromCLIOptions(options);
401
+ }
402
+ function queryToBoolean(value) {
403
+ if (value === "true" || value === "1")
404
+ return true;
405
+ if (value === "false" || value === "0")
406
+ return false;
407
+ return void 0;
408
+ }
409
+ // Annotate the CommonJS export names for ESM import in node:
410
+ 0 && (module.exports = {
411
+ commaSeparatedList,
412
+ configFromCLIOptions,
413
+ configFromURLParams,
414
+ defaultConfig,
415
+ dotenvFileLoader,
416
+ headerParser,
417
+ mergeConfig,
418
+ numberParser,
419
+ outputDir,
420
+ outputFile,
421
+ resolutionParser,
422
+ resolveCLIConfig,
423
+ resolveConfig,
424
+ semicolonSeparatedList
425
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/mcp/browser/config.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fs from 'fs';\nimport os from 'os';\nimport path from 'path';\n\nimport { devices } from 'playwright-core';\nimport { dotenv, debug } from 'playwright-core/lib/utilsBundle';\nimport { fileExistsAsync } from '../../util';\nimport { firstRootPath } from '../sdk/server';\n\nimport type * as playwright from '../../../types/test';\nimport type { Config, ToolCapability } from '../config';\nimport type { ClientInfo } from '../sdk/server';\n\ntype ViewportSize = { width: number; height: number };\n\nexport type CLIOptions = {\n allowedHosts?: string[];\n allowedOrigins?: string[];\n blockedOrigins?: string[];\n blockServiceWorkers?: boolean;\n browser?: string;\n caps?: string[];\n cdpEndpoint?: string;\n cdpHeader?: Record<string, string>;\n config?: string;\n device?: string;\n executablePath?: string;\n grantPermissions?: string[];\n headless?: boolean;\n host?: string;\n ignoreHttpsErrors?: boolean;\n initScript?: string[];\n isolated?: boolean;\n imageResponses?: 'allow' | 'omit';\n sandbox?: boolean;\n outputDir?: string;\n port?: number;\n proxyBypass?: string;\n proxyServer?: string;\n saveSession?: boolean;\n saveTrace?: boolean;\n saveVideo?: ViewportSize;\n secrets?: Record<string, string>;\n sharedBrowserContext?: boolean;\n storageState?: string;\n testIdAttribute?: string;\n timeoutAction?: number;\n timeoutNavigation?: number;\n userAgent?: string;\n userDataDir?: string;\n viewportSize?: ViewportSize;\n};\n\nexport const defaultConfig: FullConfig = {\n browser: {\n browserName: 'chromium',\n launchOptions: {\n channel: 'chrome',\n headless: os.platform() === 'linux' && !process.env.DISPLAY,\n chromiumSandbox: true,\n },\n contextOptions: {\n viewport: null,\n },\n },\n network: {\n allowedOrigins: undefined,\n blockedOrigins: undefined,\n },\n server: {},\n saveTrace: false,\n timeouts: {\n action: 5000,\n navigation: 60000,\n },\n};\n\ntype BrowserUserConfig = NonNullable<Config['browser']>;\n\nexport type FullConfig = Config & {\n browser: Omit<BrowserUserConfig, 'browserName'> & {\n browserName: 'chromium' | 'firefox' | 'webkit';\n launchOptions: NonNullable<BrowserUserConfig['launchOptions']>;\n contextOptions: NonNullable<BrowserUserConfig['contextOptions']>;\n },\n network: NonNullable<Config['network']>,\n saveTrace: boolean;\n server: NonNullable<Config['server']>,\n timeouts: {\n action: number;\n navigation: number;\n },\n};\n\nexport async function resolveConfig(config: Config): Promise<FullConfig> {\n return mergeConfig(defaultConfig, config);\n}\n\nexport async function resolveCLIConfig(cliOptions: CLIOptions): Promise<FullConfig> {\n const configInFile = await loadConfig(cliOptions.config);\n const envOverrides = configFromEnv();\n const cliOverrides = configFromCLIOptions(cliOptions);\n let result = defaultConfig;\n result = mergeConfig(result, configInFile);\n result = mergeConfig(result, envOverrides);\n result = mergeConfig(result, cliOverrides);\n await validateConfig(result);\n return result;\n}\n\nasync function validateConfig(config: FullConfig): Promise<void> {\n if (config.browser.initScript) {\n for (const script of config.browser.initScript) {\n if (!await fileExistsAsync(script))\n throw new Error(`Init script file does not exist: ${script}`);\n }\n }\n if (config.sharedBrowserContext && config.saveVideo)\n throw new Error('saveVideo is not supported when sharedBrowserContext is true');\n}\n\nexport function configFromCLIOptions(cliOptions: CLIOptions): Config {\n let browserName: 'chromium' | 'firefox' | 'webkit' | undefined;\n let channel: string | undefined;\n switch (cliOptions.browser) {\n case 'chrome':\n case 'chrome-beta':\n case 'chrome-canary':\n case 'chrome-dev':\n case 'chromium':\n case 'msedge':\n case 'msedge-beta':\n case 'msedge-canary':\n case 'msedge-dev':\n browserName = 'chromium';\n channel = cliOptions.browser;\n break;\n case 'firefox':\n browserName = 'firefox';\n break;\n case 'webkit':\n browserName = 'webkit';\n break;\n }\n\n // Launch options\n const launchOptions: playwright.LaunchOptions = {\n channel,\n executablePath: cliOptions.executablePath,\n headless: cliOptions.headless,\n };\n\n // --no-sandbox was passed, disable the sandbox\n if (cliOptions.sandbox === false)\n launchOptions.chromiumSandbox = false;\n\n if (cliOptions.proxyServer) {\n launchOptions.proxy = {\n server: cliOptions.proxyServer\n };\n if (cliOptions.proxyBypass)\n launchOptions.proxy.bypass = cliOptions.proxyBypass;\n }\n\n if (cliOptions.device && cliOptions.cdpEndpoint)\n throw new Error('Device emulation is not supported with cdpEndpoint.');\n\n // Context options\n const contextOptions: playwright.BrowserContextOptions = cliOptions.device ? devices[cliOptions.device] : {};\n if (cliOptions.storageState)\n contextOptions.storageState = cliOptions.storageState;\n\n if (cliOptions.userAgent)\n contextOptions.userAgent = cliOptions.userAgent;\n\n if (cliOptions.viewportSize)\n contextOptions.viewport = cliOptions.viewportSize;\n\n if (cliOptions.ignoreHttpsErrors)\n contextOptions.ignoreHTTPSErrors = true;\n\n if (cliOptions.blockServiceWorkers)\n contextOptions.serviceWorkers = 'block';\n\n if (cliOptions.grantPermissions)\n contextOptions.permissions = cliOptions.grantPermissions;\n\n if (cliOptions.saveVideo) {\n contextOptions.recordVideo = {\n // Videos are moved to output directory on saveAs.\n dir: tmpDir(),\n size: cliOptions.saveVideo,\n };\n }\n\n const result: Config = {\n browser: {\n browserName,\n isolated: cliOptions.isolated,\n userDataDir: cliOptions.userDataDir,\n launchOptions,\n contextOptions,\n cdpEndpoint: cliOptions.cdpEndpoint,\n cdpHeaders: cliOptions.cdpHeader,\n initScript: cliOptions.initScript,\n },\n server: {\n port: cliOptions.port,\n host: cliOptions.host,\n allowedHosts: cliOptions.allowedHosts,\n },\n capabilities: cliOptions.caps as ToolCapability[],\n network: {\n allowedOrigins: cliOptions.allowedOrigins,\n blockedOrigins: cliOptions.blockedOrigins,\n },\n saveSession: cliOptions.saveSession,\n saveTrace: cliOptions.saveTrace,\n saveVideo: cliOptions.saveVideo,\n secrets: cliOptions.secrets,\n sharedBrowserContext: cliOptions.sharedBrowserContext,\n outputDir: cliOptions.outputDir,\n imageResponses: cliOptions.imageResponses,\n testIdAttribute: cliOptions.testIdAttribute,\n timeouts: {\n action: cliOptions.timeoutAction,\n navigation: cliOptions.timeoutNavigation,\n },\n };\n\n return result;\n}\n\nfunction configFromEnv(): Config {\n const options: CLIOptions = {};\n options.allowedHosts = commaSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_HOSTNAMES);\n options.allowedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_ORIGINS);\n options.blockedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_BLOCKED_ORIGINS);\n options.blockServiceWorkers = envToBoolean(process.env.PLAYWRIGHT_MCP_BLOCK_SERVICE_WORKERS);\n options.browser = envToString(process.env.PLAYWRIGHT_MCP_BROWSER);\n options.caps = commaSeparatedList(process.env.PLAYWRIGHT_MCP_CAPS);\n options.cdpEndpoint = envToString(process.env.PLAYWRIGHT_MCP_CDP_ENDPOINT);\n options.cdpHeader = headerParser(process.env.PLAYWRIGHT_MCP_CDP_HEADERS, {});\n options.config = envToString(process.env.PLAYWRIGHT_MCP_CONFIG);\n options.device = envToString(process.env.PLAYWRIGHT_MCP_DEVICE);\n options.executablePath = envToString(process.env.PLAYWRIGHT_MCP_EXECUTABLE_PATH);\n options.grantPermissions = commaSeparatedList(process.env.PLAYWRIGHT_MCP_GRANT_PERMISSIONS);\n options.headless = envToBoolean(process.env.PLAYWRIGHT_MCP_HEADLESS);\n options.host = envToString(process.env.PLAYWRIGHT_MCP_HOST);\n options.ignoreHttpsErrors = envToBoolean(process.env.PLAYWRIGHT_MCP_IGNORE_HTTPS_ERRORS);\n const initScript = envToString(process.env.PLAYWRIGHT_MCP_INIT_SCRIPT);\n if (initScript)\n options.initScript = [initScript];\n options.isolated = envToBoolean(process.env.PLAYWRIGHT_MCP_ISOLATED);\n if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES === 'omit')\n options.imageResponses = 'omit';\n options.sandbox = envToBoolean(process.env.PLAYWRIGHT_MCP_SANDBOX);\n options.outputDir = envToString(process.env.PLAYWRIGHT_MCP_OUTPUT_DIR);\n options.port = numberParser(process.env.PLAYWRIGHT_MCP_PORT);\n options.proxyBypass = envToString(process.env.PLAYWRIGHT_MCP_PROXY_BYPASS);\n options.proxyServer = envToString(process.env.PLAYWRIGHT_MCP_PROXY_SERVER);\n options.saveTrace = envToBoolean(process.env.PLAYWRIGHT_MCP_SAVE_TRACE);\n options.saveVideo = resolutionParser('--save-video', process.env.PLAYWRIGHT_MCP_SAVE_VIDEO);\n options.secrets = dotenvFileLoader(process.env.PLAYWRIGHT_MCP_SECRETS_FILE);\n options.storageState = envToString(process.env.PLAYWRIGHT_MCP_STORAGE_STATE);\n options.testIdAttribute = envToString(process.env.PLAYWRIGHT_MCP_TEST_ID_ATTRIBUTE);\n options.timeoutAction = numberParser(process.env.PLAYWRIGHT_MCP_TIMEOUT_ACTION);\n options.timeoutNavigation = numberParser(process.env.PLAYWRIGHT_MCP_TIMEOUT_NAVIGATION);\n options.userAgent = envToString(process.env.PLAYWRIGHT_MCP_USER_AGENT);\n options.userDataDir = envToString(process.env.PLAYWRIGHT_MCP_USER_DATA_DIR);\n options.viewportSize = resolutionParser('--viewport-size', process.env.PLAYWRIGHT_MCP_VIEWPORT_SIZE);\n return configFromCLIOptions(options);\n}\n\nasync function loadConfig(configFile: string | undefined): Promise<Config> {\n if (!configFile)\n return {};\n\n try {\n return JSON.parse(await fs.promises.readFile(configFile, 'utf8'));\n } catch (error) {\n throw new Error(`Failed to load config file: ${configFile}, ${error}`);\n }\n}\n\nfunction tmpDir(): string {\n return path.join(process.env.PW_TMPDIR_FOR_TEST ?? os.tmpdir(), 'playwright-mcp-output');\n}\n\nexport function outputDir(config: FullConfig, clientInfo: ClientInfo): string {\n const rootPath = firstRootPath(clientInfo);\n return config.outputDir\n ?? (rootPath ? path.join(rootPath, '.playwright-mcp') : undefined)\n ?? path.join(tmpDir(), String(clientInfo.timestamp));\n}\n\nexport async function outputFile(config: FullConfig, clientInfo: ClientInfo, fileName: string, options: { origin: 'code' | 'llm' | 'web', reason: string }): Promise<string> {\n const file = await resolveFile(config, clientInfo, fileName, options);\n debug('pw:mcp:file')(options.reason, file);\n return file;\n}\n\nasync function resolveFile(config: FullConfig, clientInfo: ClientInfo, fileName: string, options: { origin: 'code' | 'llm' | 'web' }): Promise<string> {\n const dir = outputDir(config, clientInfo);\n\n // Trust code.\n if (options.origin === 'code')\n return path.resolve(dir, fileName);\n\n // Trust llm to use valid characters in file names.\n if (options.origin === 'llm') {\n fileName = fileName.split('\\\\').join('/');\n const resolvedFile = path.resolve(dir, fileName);\n if (!resolvedFile.startsWith(path.resolve(dir) + path.sep))\n throw new Error(`Resolved file path ${resolvedFile} is outside of the output directory ${dir}. Use relative file names to stay within the output directory.`);\n return resolvedFile;\n }\n\n // Do not trust web, at all.\n return path.join(dir, sanitizeForFilePath(fileName));\n}\n\nfunction pickDefined<T extends object>(obj: T | undefined): Partial<T> {\n return Object.fromEntries(\n Object.entries(obj ?? {}).filter(([_, v]) => v !== undefined)\n ) as Partial<T>;\n}\n\nexport function mergeConfig(base: FullConfig, overrides: Config): FullConfig {\n const browser: FullConfig['browser'] = {\n ...pickDefined(base.browser),\n ...pickDefined(overrides.browser),\n browserName: overrides.browser?.browserName ?? base.browser?.browserName ?? 'chromium',\n isolated: overrides.browser?.isolated ?? base.browser?.isolated ?? false,\n launchOptions: {\n ...pickDefined(base.browser?.launchOptions),\n ...pickDefined(overrides.browser?.launchOptions),\n ...{ assistantMode: true },\n },\n contextOptions: {\n ...pickDefined(base.browser?.contextOptions),\n ...pickDefined(overrides.browser?.contextOptions),\n },\n };\n\n if (browser.browserName !== 'chromium' && browser.launchOptions)\n delete browser.launchOptions.channel;\n\n return {\n ...pickDefined(base),\n ...pickDefined(overrides),\n browser,\n network: {\n ...pickDefined(base.network),\n ...pickDefined(overrides.network),\n },\n server: {\n ...pickDefined(base.server),\n ...pickDefined(overrides.server),\n },\n timeouts: {\n ...pickDefined(base.timeouts),\n ...pickDefined(overrides.timeouts),\n },\n } as FullConfig;\n}\n\nexport function semicolonSeparatedList(value: string | undefined): string[] | undefined {\n if (!value)\n return undefined;\n return value.split(';').map(v => v.trim());\n}\n\nexport function commaSeparatedList(value: string | undefined): string[] | undefined {\n if (!value)\n return undefined;\n return value.split(',').map(v => v.trim());\n}\n\nexport function dotenvFileLoader(value: string | undefined): Record<string, string> | undefined {\n if (!value)\n return undefined;\n return dotenv.parse(fs.readFileSync(value, 'utf8'));\n}\n\nexport function numberParser(value: string | undefined): number | undefined {\n if (!value)\n return undefined;\n return +value;\n}\n\nexport function resolutionParser(name: string, value: string | undefined): ViewportSize | undefined {\n if (!value)\n return undefined;\n if (value.includes('x')) {\n const [width, height] = value.split('x').map(v => +v);\n if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0)\n throw new Error(`Invalid resolution format: use ${name}=\"800x600\"`);\n return { width, height };\n }\n\n // Legacy format\n if (value.includes(',')) {\n const [width, height] = value.split(',').map(v => +v);\n if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0)\n throw new Error(`Invalid resolution format: use ${name}=\"800x600\"`);\n return { width, height };\n }\n\n throw new Error(`Invalid resolution format: use ${name}=\"800x600\"`);\n}\n\nexport function headerParser(arg: string | undefined, previous?: Record<string, string>): Record<string, string> {\n if (!arg)\n return previous || {};\n const result: Record<string, string> = previous || {};\n const [name, value] = arg.split(':').map(v => v.trim());\n result[name] = value;\n return result;\n}\n\nfunction envToBoolean(value: string | undefined): boolean | undefined {\n if (value === 'true' || value === '1')\n return true;\n if (value === 'false' || value === '0')\n return false;\n return undefined;\n}\n\nfunction envToString(value: string | undefined): string | undefined {\n return value ? value.trim() : undefined;\n}\n\nfunction sanitizeForFilePath(s: string) {\n const sanitize = (s: string) => s.replace(/[\\x00-\\x2C\\x2E-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7F]+/g, '-');\n const separator = s.lastIndexOf('.');\n if (separator === -1)\n return sanitize(s);\n return sanitize(s.substring(0, separator)) + '.' + sanitize(s.substring(separator + 1));\n}\n\n/**\n * Parse URL query parameters and create config overrides\n * Supports most browser configuration options via URL parameters\n *\n * Excluded parameters (server-level only):\n * - config, host, port, output-dir, save-session, save-trace\n * - executable-path, user-data-dir, extension\n */\nexport function configFromURLParams(url: URL): Config {\n const getParam = (name: string) => url.searchParams.get(name) || undefined;\n\n const options: CLIOptions = {};\n options.allowedOrigins = semicolonSeparatedList(getParam('allowed-origins'));\n options.blockedOrigins = semicolonSeparatedList(getParam('blocked-origins'));\n options.blockServiceWorkers = queryToBoolean(getParam('block-service-workers'));\n options.browser = getParam('browser');\n options.caps = commaSeparatedList(getParam('caps'));\n options.cdpEndpoint = getParam('cdp-endpoint');\n options.device = getParam('device');\n options.headless = queryToBoolean(getParam('headless'));\n options.ignoreHttpsErrors = queryToBoolean(getParam('ignore-https-errors'));\n options.isolated = queryToBoolean(getParam('isolated'));\n const imageResponses = getParam('image-responses');\n if (imageResponses === 'omit' || imageResponses === 'allow')\n options.imageResponses = imageResponses;\n options.sandbox = queryToBoolean(getParam('sandbox'));\n options.proxyBypass = getParam('proxy-bypass');\n options.proxyServer = getParam('proxy-server');\n options.storageState = getParam('storage-state');\n options.userAgent = getParam('user-agent');\n const viewportSize = getParam('viewport-size');\n if (viewportSize)\n options.viewportSize = resolutionParser('--viewport-size', viewportSize);\n\n // If no URL params were actually set, return empty config\n // This ensures empty URLs don't trigger session-specific config in http.ts\n if (!Object.values(options).some(v => v !== undefined)) {\n return {};\n }\n\n return configFromCLIOptions(options);\n}\n\nfunction queryToBoolean(value: string | undefined): boolean | undefined {\n if (value === 'true' || value === '1')\n return true;\n if (value === 'false' || value === '0')\n return false;\n return undefined;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["os", "fs", "path", "s"]
7
+ }