@smoothdeploy/playwright 1.57.1 → 1.58.1-beta-1770383926000
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.
Potentially problematic release.
This version of @smoothdeploy/playwright might be problematic. Click here for more details.
- package/ThirdPartyNotices.txt +1188 -65
- package/lib/agents/agentParser.js +89 -0
- package/lib/agents/generateAgents.js +27 -74
- package/lib/agents/generateAgents.js.map +7 -0
- package/lib/agents/playwright-test-planner.agent.md +1 -0
- package/lib/common/config.js +6 -4
- package/lib/common/config.js.map +7 -0
- package/lib/common/configLoader.js.map +7 -0
- package/lib/common/esmLoaderHost.js +2 -0
- package/lib/common/esmLoaderHost.js.map +7 -0
- package/lib/common/expectBundle.js +2 -17
- package/lib/common/expectBundle.js.map +7 -0
- package/lib/common/expectBundleImpl.js +132 -132
- package/lib/common/expectBundleImpl.js.map +7 -0
- package/lib/common/fixtures.js.map +7 -0
- package/lib/common/globals.js.map +7 -0
- package/lib/common/ipc.js.map +7 -0
- package/lib/common/poolBuilder.js.map +7 -0
- package/lib/common/process.js +28 -0
- package/lib/common/process.js.map +7 -0
- package/lib/common/suiteUtils.js.map +7 -0
- package/lib/common/test.js.map +7 -0
- package/lib/common/testLoader.js.map +7 -0
- package/lib/common/testType.js.map +7 -0
- package/lib/common/validators.js +10 -10
- package/lib/common/validators.js.map +7 -0
- package/lib/fsWatcher.js.map +7 -0
- package/lib/index.js +205 -12
- package/lib/index.js.map +7 -0
- package/lib/internalsForTest.js.map +7 -0
- package/lib/isomorphic/events.js.map +7 -0
- package/lib/isomorphic/folders.js.map +7 -0
- package/lib/isomorphic/stringInternPool.js.map +7 -0
- package/lib/isomorphic/teleReceiver.js +15 -2
- package/lib/isomorphic/teleReceiver.js.map +7 -0
- package/lib/isomorphic/teleSuiteUpdater.js +24 -4
- package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
- package/lib/isomorphic/testServerConnection.js.map +7 -0
- package/lib/isomorphic/testServerInterface.js.map +7 -0
- package/lib/isomorphic/testTree.js +13 -18
- package/lib/isomorphic/testTree.js.map +7 -0
- package/lib/isomorphic/types.d.js.map +7 -0
- package/lib/loader/loaderMain.js.map +7 -0
- package/lib/matchers/expect.js +2 -15
- package/lib/matchers/expect.js.map +7 -0
- package/lib/matchers/matcherHint.js +1 -44
- package/lib/matchers/matcherHint.js.map +7 -0
- package/lib/matchers/matchers.js +3 -2
- package/lib/matchers/matchers.js.map +7 -0
- package/lib/matchers/toBeTruthy.js +5 -3
- package/lib/matchers/toBeTruthy.js.map +7 -0
- package/lib/matchers/toEqual.js +4 -3
- package/lib/matchers/toEqual.js.map +7 -0
- package/lib/matchers/toHaveURL.js +5 -6
- package/lib/matchers/toHaveURL.js.map +7 -0
- package/lib/matchers/toMatchAriaSnapshot.js +5 -5
- package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
- package/lib/matchers/toMatchSnapshot.js +9 -8
- package/lib/matchers/toMatchSnapshot.js.map +7 -0
- package/lib/matchers/toMatchText.js +9 -9
- package/lib/matchers/toMatchText.js.map +7 -0
- package/lib/mcp/browser/actions.d.js.map +7 -0
- package/lib/mcp/browser/browserContextFactory.js +62 -29
- package/lib/mcp/browser/browserContextFactory.js.map +7 -0
- package/lib/mcp/browser/browserServerBackend.js +17 -9
- package/lib/mcp/browser/browserServerBackend.js.map +7 -0
- package/lib/mcp/browser/codegen.js.map +7 -0
- package/lib/mcp/browser/config.js +65 -12
- package/lib/mcp/browser/config.js.map +7 -0
- package/lib/mcp/browser/context.js +71 -94
- package/lib/mcp/browser/context.js.map +7 -0
- package/lib/mcp/browser/response.js +172 -131
- package/lib/mcp/browser/response.js.map +7 -0
- package/lib/mcp/browser/sessionLog.js +19 -104
- package/lib/mcp/browser/sessionLog.js.map +7 -0
- package/lib/mcp/browser/tab.js +92 -41
- package/lib/mcp/browser/tab.js.map +7 -0
- package/lib/mcp/browser/tools/common.js +8 -6
- package/lib/mcp/browser/tools/common.js.map +7 -0
- package/lib/mcp/browser/tools/console.js +7 -5
- package/lib/mcp/browser/tools/console.js.map +7 -0
- package/lib/mcp/browser/tools/dialogs.js +4 -4
- package/lib/mcp/browser/tools/dialogs.js.map +7 -0
- package/lib/mcp/browser/tools/evaluate.js +11 -19
- package/lib/mcp/browser/tools/evaluate.js.map +7 -0
- package/lib/mcp/browser/tools/files.js +3 -3
- package/lib/mcp/browser/tools/files.js.map +7 -0
- package/lib/mcp/browser/tools/form.js +9 -19
- package/lib/mcp/browser/tools/form.js.map +7 -0
- package/lib/mcp/browser/tools/install.js +6 -3
- package/lib/mcp/browser/tools/install.js.map +7 -0
- package/lib/mcp/browser/tools/keyboard.js +34 -11
- package/lib/mcp/browser/tools/keyboard.js.map +7 -0
- package/lib/mcp/browser/tools/mouse.js +11 -11
- package/lib/mcp/browser/tools/mouse.js.map +7 -0
- package/lib/mcp/browser/tools/navigate.js +14 -5
- package/lib/mcp/browser/tools/navigate.js.map +7 -0
- package/lib/mcp/browser/tools/network.js +20 -11
- package/lib/mcp/browser/tools/network.js.map +7 -0
- package/lib/mcp/browser/tools/open.js +57 -0
- package/lib/mcp/browser/tools/pdf.js +9 -19
- package/lib/mcp/browser/tools/pdf.js.map +7 -0
- package/lib/mcp/browser/tools/runCode.js +11 -8
- package/lib/mcp/browser/tools/runCode.js.map +7 -0
- package/lib/mcp/browser/tools/screenshot.js +16 -29
- package/lib/mcp/browser/tools/screenshot.js.map +7 -0
- package/lib/mcp/browser/tools/snapshot.js +21 -29
- package/lib/mcp/browser/tools/snapshot.js.map +7 -0
- package/lib/mcp/browser/tools/tabs.js +12 -12
- package/lib/mcp/browser/tools/tabs.js.map +7 -0
- package/lib/mcp/browser/tools/tool.js +2 -4
- package/lib/mcp/browser/tools/tool.js.map +7 -0
- package/lib/mcp/browser/tools/tracing.js +6 -6
- package/lib/mcp/browser/tools/tracing.js.map +7 -0
- package/lib/mcp/browser/tools/utils.js +49 -44
- package/lib/mcp/browser/tools/utils.js.map +7 -0
- package/lib/mcp/browser/tools/verify.js +24 -34
- package/lib/mcp/browser/tools/verify.js.map +7 -0
- package/lib/mcp/browser/tools/wait.js +6 -6
- package/lib/mcp/browser/tools/wait.js.map +7 -0
- package/lib/mcp/browser/tools.js +3 -1
- package/lib/mcp/browser/tools.js.map +7 -0
- package/lib/mcp/browser/watchdog.js.map +7 -0
- package/lib/mcp/config.d.js.map +7 -0
- package/lib/mcp/extension/cdpRelay.js +1 -1
- package/lib/mcp/extension/cdpRelay.js.map +7 -0
- package/lib/mcp/extension/extensionContextFactory.js +6 -5
- package/lib/mcp/extension/extensionContextFactory.js.map +7 -0
- package/lib/mcp/extension/protocol.js.map +7 -0
- package/lib/mcp/index.js.map +7 -0
- package/lib/mcp/log.js.map +7 -0
- package/lib/mcp/program.js +15 -20
- package/lib/mcp/program.js.map +7 -0
- package/lib/mcp/sdk/bundle.js.map +7 -0
- package/lib/mcp/sdk/exports.js +0 -2
- package/lib/mcp/sdk/exports.js.map +7 -0
- package/lib/mcp/sdk/http.js +20 -55
- package/lib/mcp/sdk/http.js.map +7 -0
- package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
- package/lib/mcp/sdk/proxyBackend.js.map +7 -0
- package/lib/mcp/sdk/server.js +29 -4
- package/lib/mcp/sdk/server.js.map +7 -0
- package/lib/mcp/sdk/tool.js +2 -2
- package/lib/mcp/sdk/tool.js.map +7 -0
- package/lib/mcp/terminal/cli.js +296 -0
- package/lib/mcp/terminal/command.js +56 -0
- package/lib/mcp/terminal/commands.js +333 -0
- package/lib/mcp/terminal/daemon.js +129 -0
- package/lib/mcp/terminal/help.json +32 -0
- package/lib/mcp/terminal/helpGenerator.js +88 -0
- package/lib/mcp/terminal/socketConnection.js +80 -0
- package/lib/mcp/test/browserBackend.js +3 -13
- package/lib/mcp/test/browserBackend.js.map +7 -0
- package/lib/mcp/test/generatorTools.js +9 -9
- package/lib/mcp/test/generatorTools.js.map +7 -0
- package/lib/mcp/test/plannerTools.js +23 -22
- package/lib/mcp/test/plannerTools.js.map +7 -0
- package/lib/mcp/test/seed.js.map +7 -0
- package/lib/mcp/test/streams.js.map +7 -0
- package/lib/mcp/test/testBackend.js +6 -6
- package/lib/mcp/test/testBackend.js.map +7 -0
- package/lib/mcp/test/testContext.js +9 -3
- package/lib/mcp/test/testContext.js.map +7 -0
- package/lib/mcp/test/testTool.js.map +7 -0
- package/lib/mcp/test/testTools.js +12 -10
- package/lib/mcp/test/testTools.js.map +7 -0
- package/lib/mcpBundleImpl.js.map +7 -0
- package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
- package/lib/plugins/index.js.map +7 -0
- package/lib/plugins/webServerPlugin.js.map +7 -0
- package/lib/program.js +18 -4
- package/lib/program.js.map +7 -0
- package/lib/reporters/base.js +29 -4
- package/lib/reporters/base.js.map +7 -0
- package/lib/reporters/blob.js +3 -0
- package/lib/reporters/blob.js.map +7 -0
- package/lib/reporters/dot.js +17 -0
- package/lib/reporters/dot.js.map +7 -0
- package/lib/reporters/empty.js.map +7 -0
- package/lib/reporters/github.js.map +7 -0
- package/lib/reporters/html.js +13 -3
- package/lib/reporters/html.js.map +7 -0
- package/lib/reporters/internalReporter.js +6 -0
- package/lib/reporters/internalReporter.js.map +7 -0
- package/lib/reporters/json.js.map +7 -0
- package/lib/reporters/junit.js.map +7 -0
- package/lib/reporters/line.js +18 -0
- package/lib/reporters/line.js.map +7 -0
- package/lib/reporters/list.js +22 -0
- package/lib/reporters/list.js.map +7 -0
- package/lib/reporters/listModeReporter.js.map +7 -0
- package/lib/reporters/markdown.js.map +7 -0
- package/lib/reporters/merge.js +25 -8
- package/lib/reporters/merge.js.map +7 -0
- package/lib/reporters/multiplexer.js +8 -0
- package/lib/reporters/multiplexer.js.map +7 -0
- package/lib/reporters/reporterV2.js.map +7 -0
- package/lib/reporters/smoothdeploy.js +191 -0
- package/lib/reporters/teleEmitter.js +22 -4
- package/lib/reporters/teleEmitter.js.map +7 -0
- package/lib/reporters/versions/blobV1.js.map +7 -0
- package/lib/runner/dispatcher.js +20 -4
- package/lib/runner/dispatcher.js.map +7 -0
- package/lib/runner/failureTracker.js.map +7 -0
- package/lib/runner/lastRun.js.map +7 -0
- package/lib/runner/loadUtils.js +2 -2
- package/lib/runner/loadUtils.js.map +7 -0
- package/lib/runner/loaderHost.js.map +7 -0
- package/lib/runner/processHost.js +19 -0
- package/lib/runner/processHost.js.map +7 -0
- package/lib/runner/projectUtils.js +1 -1
- package/lib/runner/projectUtils.js.map +7 -0
- package/lib/runner/rebase.js.map +7 -0
- package/lib/runner/reporters.js +3 -1
- package/lib/runner/reporters.js.map +7 -0
- package/lib/runner/sigIntWatcher.js.map +7 -0
- package/lib/runner/storage.js +91 -0
- package/lib/runner/taskRunner.js.map +7 -0
- package/lib/runner/tasks.js.map +7 -0
- package/lib/runner/testGroups.js +14 -6
- package/lib/runner/testGroups.js.map +7 -0
- package/lib/runner/testRunner.js +13 -4
- package/lib/runner/testRunner.js.map +7 -0
- package/lib/runner/testServer.js +2 -2
- package/lib/runner/testServer.js.map +7 -0
- package/lib/runner/uiModeReporter.js.map +7 -0
- package/lib/runner/vcs.js.map +7 -0
- package/lib/runner/watchMode.js +2 -1
- package/lib/runner/watchMode.js.map +7 -0
- package/lib/runner/workerHost.js +6 -0
- package/lib/runner/workerHost.js.map +7 -0
- package/lib/third_party/pirates.js.map +7 -0
- package/lib/third_party/tsconfig-loader.js.map +7 -0
- package/lib/transform/babelBundle.js +3 -0
- package/lib/transform/babelBundle.js.map +7 -0
- package/lib/transform/babelBundleImpl.js +134 -134
- package/lib/transform/babelBundleImpl.js.map +7 -0
- package/lib/transform/compilationCache.js +2 -0
- package/lib/transform/compilationCache.js.map +7 -0
- package/lib/transform/esmLoader.js +10 -11
- package/lib/transform/esmLoader.js.map +7 -0
- package/lib/transform/md.js +221 -0
- package/lib/transform/portTransport.js.map +7 -0
- package/lib/transform/transform.js +18 -8
- package/lib/transform/transform.js.map +7 -0
- package/lib/util.js +3 -6
- package/lib/util.js.map +7 -0
- package/lib/utilsBundle.js +7 -0
- package/lib/utilsBundle.js.map +7 -0
- package/lib/utilsBundleImpl.js +51 -48
- package/lib/utilsBundleImpl.js.map +7 -0
- package/lib/worker/fixtureRunner.js +6 -2
- package/lib/worker/fixtureRunner.js.map +7 -0
- package/lib/worker/testInfo.js +39 -19
- package/lib/worker/testInfo.js.map +7 -0
- package/lib/worker/testTracing.js.map +7 -0
- package/lib/worker/timeoutManager.js.map +7 -0
- package/lib/worker/util.js.map +7 -0
- package/lib/worker/workerMain.js +17 -16
- package/lib/worker/workerMain.js.map +7 -0
- package/package.json +2 -2
- package/test.mjs +1 -0
- package/types/test.d.ts +26 -6
- package/types/testReporter.d.ts +1 -0
|
@@ -29,7 +29,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
var browserContextFactory_exports = {};
|
|
30
30
|
__export(browserContextFactory_exports, {
|
|
31
31
|
SharedContextFactory: () => SharedContextFactory,
|
|
32
|
-
contextFactory: () => contextFactory
|
|
32
|
+
contextFactory: () => contextFactory,
|
|
33
|
+
identityBrowserContextFactory: () => identityBrowserContextFactory
|
|
33
34
|
});
|
|
34
35
|
module.exports = __toCommonJS(browserContextFactory_exports);
|
|
35
36
|
var import_crypto = __toESM(require("crypto"));
|
|
@@ -53,16 +54,27 @@ function contextFactory(config) {
|
|
|
53
54
|
return new IsolatedContextFactory(config);
|
|
54
55
|
return new PersistentContextFactory(config);
|
|
55
56
|
}
|
|
57
|
+
function identityBrowserContextFactory(browserContext) {
|
|
58
|
+
return {
|
|
59
|
+
createContext: async (clientInfo, abortSignal, options) => {
|
|
60
|
+
return {
|
|
61
|
+
browserContext,
|
|
62
|
+
close: async () => {
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
56
68
|
class BaseContextFactory {
|
|
57
69
|
constructor(name, config) {
|
|
58
70
|
this._logName = name;
|
|
59
71
|
this.config = config;
|
|
60
72
|
}
|
|
61
|
-
async _obtainBrowser(clientInfo) {
|
|
73
|
+
async _obtainBrowser(clientInfo, options) {
|
|
62
74
|
if (this._browserPromise)
|
|
63
75
|
return this._browserPromise;
|
|
64
76
|
(0, import_log.testDebug)(`obtain browser (${this._logName})`);
|
|
65
|
-
this._browserPromise = this._doObtainBrowser(clientInfo);
|
|
77
|
+
this._browserPromise = this._doObtainBrowser(clientInfo, options);
|
|
66
78
|
void this._browserPromise.then((browser) => {
|
|
67
79
|
browser.on("disconnected", () => {
|
|
68
80
|
this._browserPromise = void 0;
|
|
@@ -72,28 +84,27 @@ class BaseContextFactory {
|
|
|
72
84
|
});
|
|
73
85
|
return this._browserPromise;
|
|
74
86
|
}
|
|
75
|
-
async _doObtainBrowser(clientInfo) {
|
|
87
|
+
async _doObtainBrowser(clientInfo, options) {
|
|
76
88
|
throw new Error("Not implemented");
|
|
77
89
|
}
|
|
78
|
-
async createContext(clientInfo) {
|
|
90
|
+
async createContext(clientInfo, _, options) {
|
|
79
91
|
(0, import_log.testDebug)(`create browser context (${this._logName})`);
|
|
80
|
-
const browser = await this._obtainBrowser(clientInfo);
|
|
81
|
-
const browserContext = await this._doCreateContext(browser);
|
|
92
|
+
const browser = await this._obtainBrowser(clientInfo, options);
|
|
93
|
+
const browserContext = await this._doCreateContext(browser, clientInfo);
|
|
82
94
|
await addInitScript(browserContext, this.config.browser.initScript);
|
|
83
95
|
return {
|
|
84
96
|
browserContext,
|
|
85
|
-
close: (
|
|
97
|
+
close: () => this._closeBrowserContext(browserContext, browser)
|
|
86
98
|
};
|
|
87
99
|
}
|
|
88
|
-
async _doCreateContext(browser) {
|
|
100
|
+
async _doCreateContext(browser, clientInfo) {
|
|
89
101
|
throw new Error("Not implemented");
|
|
90
102
|
}
|
|
91
|
-
async _closeBrowserContext(browserContext, browser
|
|
103
|
+
async _closeBrowserContext(browserContext, browser) {
|
|
92
104
|
(0, import_log.testDebug)(`close browser context (${this._logName})`);
|
|
93
105
|
if (browser.contexts().length === 1)
|
|
94
106
|
this._browserPromise = void 0;
|
|
95
107
|
await browserContext.close().catch(import_log.logUnhandledError);
|
|
96
|
-
await afterClose();
|
|
97
108
|
if (browser.contexts().length === 0) {
|
|
98
109
|
(0, import_log.testDebug)(`close browser (${this._logName})`);
|
|
99
110
|
await browser.close().catch(import_log.logUnhandledError);
|
|
@@ -104,7 +115,7 @@ class IsolatedContextFactory extends BaseContextFactory {
|
|
|
104
115
|
constructor(config) {
|
|
105
116
|
super("isolated", config);
|
|
106
117
|
}
|
|
107
|
-
async _doObtainBrowser(clientInfo) {
|
|
118
|
+
async _doObtainBrowser(clientInfo, options) {
|
|
108
119
|
await injectCdpPort(this.config.browser);
|
|
109
120
|
const browserType = playwright[this.config.browser.browserName];
|
|
110
121
|
const tracesDir = await computeTracesDir(this.config, clientInfo);
|
|
@@ -114,15 +125,16 @@ class IsolatedContextFactory extends BaseContextFactory {
|
|
|
114
125
|
tracesDir,
|
|
115
126
|
...this.config.browser.launchOptions,
|
|
116
127
|
handleSIGINT: false,
|
|
117
|
-
handleSIGTERM: false
|
|
128
|
+
handleSIGTERM: false,
|
|
129
|
+
...options.forceHeadless !== void 0 ? { headless: options.forceHeadless === "headless" } : {}
|
|
118
130
|
}).catch((error) => {
|
|
119
131
|
if (error.message.includes("Executable doesn't exist"))
|
|
120
132
|
throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);
|
|
121
133
|
throw error;
|
|
122
134
|
});
|
|
123
135
|
}
|
|
124
|
-
async _doCreateContext(browser) {
|
|
125
|
-
return browser.newContext(this.config
|
|
136
|
+
async _doCreateContext(browser, clientInfo) {
|
|
137
|
+
return browser.newContext(await browserContextOptionsFromConfig(this.config, clientInfo));
|
|
126
138
|
}
|
|
127
139
|
}
|
|
128
140
|
class CdpContextFactory extends BaseContextFactory {
|
|
@@ -130,7 +142,10 @@ class CdpContextFactory extends BaseContextFactory {
|
|
|
130
142
|
super("cdp", config);
|
|
131
143
|
}
|
|
132
144
|
async _doObtainBrowser() {
|
|
133
|
-
return playwright.chromium.connectOverCDP(this.config.browser.cdpEndpoint, {
|
|
145
|
+
return playwright.chromium.connectOverCDP(this.config.browser.cdpEndpoint, {
|
|
146
|
+
headers: this.config.browser.cdpHeaders,
|
|
147
|
+
timeout: this.config.browser.cdpTimeout
|
|
148
|
+
});
|
|
134
149
|
}
|
|
135
150
|
async _doCreateContext(browser) {
|
|
136
151
|
return this.config.browser.isolated ? await browser.newContext() : browser.contexts()[0];
|
|
@@ -158,7 +173,7 @@ class PersistentContextFactory {
|
|
|
158
173
|
this._userDataDirs = /* @__PURE__ */ new Set();
|
|
159
174
|
this.config = config;
|
|
160
175
|
}
|
|
161
|
-
async createContext(clientInfo) {
|
|
176
|
+
async createContext(clientInfo, abortSignal, options) {
|
|
162
177
|
await injectCdpPort(this.config.browser);
|
|
163
178
|
(0, import_log.testDebug)("create browser context (persistent)");
|
|
164
179
|
const userDataDir = this.config.browser.userDataDir ?? await this._createUserDataDir(clientInfo);
|
|
@@ -172,23 +187,29 @@ class PersistentContextFactory {
|
|
|
172
187
|
const launchOptions = {
|
|
173
188
|
tracesDir,
|
|
174
189
|
...this.config.browser.launchOptions,
|
|
175
|
-
...this.config
|
|
190
|
+
...await browserContextOptionsFromConfig(this.config, clientInfo),
|
|
176
191
|
handleSIGINT: false,
|
|
177
192
|
handleSIGTERM: false,
|
|
178
193
|
ignoreDefaultArgs: [
|
|
179
194
|
"--disable-extensions"
|
|
180
195
|
],
|
|
181
|
-
assistantMode: true
|
|
196
|
+
assistantMode: true,
|
|
197
|
+
...options.forceHeadless !== void 0 ? { headless: options.forceHeadless === "headless" } : {}
|
|
182
198
|
};
|
|
183
199
|
try {
|
|
184
200
|
const browserContext = await browserType.launchPersistentContext(userDataDir, launchOptions);
|
|
185
201
|
await addInitScript(browserContext, this.config.browser.initScript);
|
|
186
|
-
const close = (
|
|
202
|
+
const close = () => this._closeBrowserContext(browserContext, userDataDir);
|
|
187
203
|
return { browserContext, close };
|
|
188
204
|
} catch (error) {
|
|
189
205
|
if (error.message.includes("Executable doesn't exist"))
|
|
190
206
|
throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);
|
|
191
|
-
if (error.message.includes("
|
|
207
|
+
if (error.message.includes("cannot open shared object file: No such file or directory")) {
|
|
208
|
+
const browserName = launchOptions.channel ?? this.config.browser.browserName;
|
|
209
|
+
throw new Error(`Missing system dependencies required to run browser ${browserName}. Install them with: sudo npx playwright install-deps ${browserName}`);
|
|
210
|
+
}
|
|
211
|
+
if (error.message.includes("ProcessSingleton") || // On Windows the process exits silently with code 21 when the profile is in use.
|
|
212
|
+
error.message.includes("exitCode=21")) {
|
|
192
213
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
193
214
|
continue;
|
|
194
215
|
}
|
|
@@ -197,13 +218,14 @@ class PersistentContextFactory {
|
|
|
197
218
|
}
|
|
198
219
|
throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);
|
|
199
220
|
}
|
|
200
|
-
async _closeBrowserContext(browserContext, userDataDir
|
|
221
|
+
async _closeBrowserContext(browserContext, userDataDir) {
|
|
201
222
|
(0, import_log.testDebug)("close browser context (persistent)");
|
|
202
223
|
(0, import_log.testDebug)("release user data dir", userDataDir);
|
|
203
224
|
await browserContext.close().catch(() => {
|
|
204
225
|
});
|
|
205
|
-
await afterClose();
|
|
206
226
|
this._userDataDirs.delete(userDataDir);
|
|
227
|
+
if (process.env.PWMCP_PROFILES_DIR_FOR_TEST && userDataDir.startsWith(process.env.PWMCP_PROFILES_DIR_FOR_TEST))
|
|
228
|
+
await import_fs.default.promises.rm(userDataDir, { recursive: true }).catch(import_log.logUnhandledError);
|
|
207
229
|
(0, import_log.testDebug)("close browser context complete (persistent)");
|
|
208
230
|
}
|
|
209
231
|
async _createUserDataDir(clientInfo) {
|
|
@@ -257,10 +279,10 @@ class SharedContextFactory {
|
|
|
257
279
|
constructor(baseFactory) {
|
|
258
280
|
this._baseFactory = baseFactory;
|
|
259
281
|
}
|
|
260
|
-
async createContext(clientInfo, abortSignal,
|
|
282
|
+
async createContext(clientInfo, abortSignal, options) {
|
|
261
283
|
if (!this._contextPromise) {
|
|
262
284
|
(0, import_log.testDebug)("create shared browser context");
|
|
263
|
-
this._contextPromise = this._baseFactory.createContext(clientInfo, abortSignal,
|
|
285
|
+
this._contextPromise = this._baseFactory.createContext(clientInfo, abortSignal, options);
|
|
264
286
|
}
|
|
265
287
|
const { browserContext } = await this._contextPromise;
|
|
266
288
|
(0, import_log.testDebug)(`shared context client connected`);
|
|
@@ -280,17 +302,28 @@ class SharedContextFactory {
|
|
|
280
302
|
if (!contextPromise)
|
|
281
303
|
return;
|
|
282
304
|
const { close } = await contextPromise;
|
|
283
|
-
await close(
|
|
284
|
-
});
|
|
305
|
+
await close();
|
|
285
306
|
}
|
|
286
307
|
}
|
|
287
308
|
async function computeTracesDir(config, clientInfo) {
|
|
288
309
|
if (!config.saveTrace && !config.capabilities?.includes("tracing"))
|
|
289
310
|
return;
|
|
290
|
-
return await (0, import_config.outputFile)(config, clientInfo, `traces`, { origin: "code",
|
|
311
|
+
return await (0, import_config.outputFile)(config, clientInfo, `traces`, { origin: "code", title: "Collecting trace" });
|
|
312
|
+
}
|
|
313
|
+
async function browserContextOptionsFromConfig(config, clientInfo) {
|
|
314
|
+
const result = { ...config.browser.contextOptions };
|
|
315
|
+
if (config.saveVideo) {
|
|
316
|
+
const dir = await (0, import_config.outputFile)(config, clientInfo, `videos`, { origin: "code", title: "Saving video" });
|
|
317
|
+
result.recordVideo = {
|
|
318
|
+
dir,
|
|
319
|
+
size: config.saveVideo
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
291
323
|
}
|
|
292
324
|
// Annotate the CommonJS export names for ESM import in node:
|
|
293
325
|
0 && (module.exports = {
|
|
294
326
|
SharedContextFactory,
|
|
295
|
-
contextFactory
|
|
327
|
+
contextFactory,
|
|
328
|
+
identityBrowserContextFactory
|
|
296
329
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/mcp/browser/browserContextFactory.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 crypto from 'crypto';\nimport fs from 'fs';\nimport net from 'net';\nimport path from 'path';\n\nimport * as playwright from 'playwright-core';\nimport { registryDirectory } from 'playwright-core/lib/server/registry/index';\nimport { startTraceViewerServer } from 'playwright-core/lib/server';\nimport { logUnhandledError, testDebug } from '../log';\nimport { outputFile } from './config';\nimport { firstRootPath } from '../sdk/server';\n\nimport type { FullConfig } from './config';\nimport type { LaunchOptions, BrowserContextOptions } from '../../../../playwright-core/src/client/types';\nimport type { ClientInfo } from '../sdk/server';\n\nexport function contextFactory(config: FullConfig): BrowserContextFactory {\n if (config.sharedBrowserContext)\n return SharedContextFactory.create(config);\n if (config.browser.remoteEndpoint)\n return new RemoteContextFactory(config);\n if (config.browser.cdpEndpoint)\n return new CdpContextFactory(config);\n if (config.browser.isolated)\n return new IsolatedContextFactory(config);\n return new PersistentContextFactory(config);\n}\n\nexport type BrowserContextFactoryResult = {\n browserContext: playwright.BrowserContext;\n close: (afterClose: () => Promise<void>) => Promise<void>;\n};\n\nexport interface BrowserContextFactory {\n createContext(clientInfo: ClientInfo, abortSignal: AbortSignal, toolName: string | undefined): Promise<BrowserContextFactoryResult>;\n}\n\nclass BaseContextFactory implements BrowserContextFactory {\n readonly config: FullConfig;\n private _logName: string;\n protected _browserPromise: Promise<playwright.Browser> | undefined;\n\n constructor(name: string, config: FullConfig) {\n this._logName = name;\n this.config = config;\n }\n\n protected async _obtainBrowser(clientInfo: ClientInfo): Promise<playwright.Browser> {\n if (this._browserPromise)\n return this._browserPromise;\n testDebug(`obtain browser (${this._logName})`);\n this._browserPromise = this._doObtainBrowser(clientInfo);\n void this._browserPromise.then(browser => {\n browser.on('disconnected', () => {\n this._browserPromise = undefined;\n });\n }).catch(() => {\n this._browserPromise = undefined;\n });\n return this._browserPromise;\n }\n\n protected async _doObtainBrowser(clientInfo: ClientInfo): Promise<playwright.Browser> {\n throw new Error('Not implemented');\n }\n\n async createContext(clientInfo: ClientInfo): Promise<BrowserContextFactoryResult> {\n testDebug(`create browser context (${this._logName})`);\n const browser = await this._obtainBrowser(clientInfo);\n const browserContext = await this._doCreateContext(browser);\n await addInitScript(browserContext, this.config.browser.initScript);\n return {\n browserContext,\n close: (afterClose: () => Promise<void>) => this._closeBrowserContext(browserContext, browser, afterClose)\n };\n }\n\n protected async _doCreateContext(browser: playwright.Browser): Promise<playwright.BrowserContext> {\n throw new Error('Not implemented');\n }\n\n private async _closeBrowserContext(browserContext: playwright.BrowserContext, browser: playwright.Browser, afterClose: () => Promise<void>) {\n testDebug(`close browser context (${this._logName})`);\n if (browser.contexts().length === 1)\n this._browserPromise = undefined;\n await browserContext.close().catch(logUnhandledError);\n await afterClose();\n if (browser.contexts().length === 0) {\n testDebug(`close browser (${this._logName})`);\n await browser.close().catch(logUnhandledError);\n }\n }\n}\n\nclass IsolatedContextFactory extends BaseContextFactory {\n constructor(config: FullConfig) {\n super('isolated', config);\n }\n\n protected override async _doObtainBrowser(clientInfo: ClientInfo): Promise<playwright.Browser> {\n await injectCdpPort(this.config.browser);\n const browserType = playwright[this.config.browser.browserName];\n const tracesDir = await computeTracesDir(this.config, clientInfo);\n if (tracesDir && this.config.saveTrace)\n await startTraceServer(this.config, tracesDir);\n return browserType.launch({\n tracesDir,\n ...this.config.browser.launchOptions,\n handleSIGINT: false,\n handleSIGTERM: false,\n }).catch(error => {\n if (error.message.includes('Executable doesn\\'t exist'))\n throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);\n throw error;\n });\n }\n\n protected override async _doCreateContext(browser: playwright.Browser): Promise<playwright.BrowserContext> {\n return browser.newContext(this.config.browser.contextOptions);\n }\n}\n\nclass CdpContextFactory extends BaseContextFactory {\n constructor(config: FullConfig) {\n super('cdp', config);\n }\n\n protected override async _doObtainBrowser(): Promise<playwright.Browser> {\n return playwright.chromium.connectOverCDP(this.config.browser.cdpEndpoint!, { headers: this.config.browser.cdpHeaders });\n }\n\n protected override async _doCreateContext(browser: playwright.Browser): Promise<playwright.BrowserContext> {\n return this.config.browser.isolated ? await browser.newContext() : browser.contexts()[0];\n }\n}\n\nclass RemoteContextFactory extends BaseContextFactory {\n constructor(config: FullConfig) {\n super('remote', config);\n }\n\n protected override async _doObtainBrowser(): Promise<playwright.Browser> {\n const url = new URL(this.config.browser.remoteEndpoint!);\n url.searchParams.set('browser', this.config.browser.browserName);\n if (this.config.browser.launchOptions)\n url.searchParams.set('launch-options', JSON.stringify(this.config.browser.launchOptions));\n return playwright[this.config.browser.browserName].connect(String(url));\n }\n\n protected override async _doCreateContext(browser: playwright.Browser): Promise<playwright.BrowserContext> {\n return browser.newContext();\n }\n}\n\nclass PersistentContextFactory implements BrowserContextFactory {\n readonly config: FullConfig;\n readonly name = 'persistent';\n readonly description = 'Create a new persistent browser context';\n\n private _userDataDirs = new Set<string>();\n\n constructor(config: FullConfig) {\n this.config = config;\n }\n\n async createContext(clientInfo: ClientInfo): Promise<BrowserContextFactoryResult> {\n await injectCdpPort(this.config.browser);\n testDebug('create browser context (persistent)');\n const userDataDir = this.config.browser.userDataDir ?? await this._createUserDataDir(clientInfo);\n const tracesDir = await computeTracesDir(this.config, clientInfo);\n if (tracesDir && this.config.saveTrace)\n await startTraceServer(this.config, tracesDir);\n\n this._userDataDirs.add(userDataDir);\n testDebug('lock user data dir', userDataDir);\n\n const browserType = playwright[this.config.browser.browserName];\n for (let i = 0; i < 5; i++) {\n const launchOptions: LaunchOptions & BrowserContextOptions = {\n tracesDir,\n ...this.config.browser.launchOptions,\n ...this.config.browser.contextOptions,\n handleSIGINT: false,\n handleSIGTERM: false,\n ignoreDefaultArgs: [\n '--disable-extensions',\n ],\n assistantMode: true,\n };\n try {\n const browserContext = await browserType.launchPersistentContext(userDataDir, launchOptions);\n await addInitScript(browserContext, this.config.browser.initScript);\n const close = (afterClose: () => Promise<void>) => this._closeBrowserContext(browserContext, userDataDir, afterClose);\n return { browserContext, close };\n } catch (error: any) {\n if (error.message.includes('Executable doesn\\'t exist'))\n throw new Error(`Browser specified in your config is not installed. Either install it (likely) or change the config.`);\n if (error.message.includes('ProcessSingleton') || error.message.includes('Invalid URL')) {\n // User data directory is already in use, try again.\n await new Promise(resolve => setTimeout(resolve, 1000));\n continue;\n }\n throw error;\n }\n }\n throw new Error(`Browser is already in use for ${userDataDir}, use --isolated to run multiple instances of the same browser`);\n }\n\n private async _closeBrowserContext(browserContext: playwright.BrowserContext, userDataDir: string, afterClose: () => Promise<void>) {\n testDebug('close browser context (persistent)');\n testDebug('release user data dir', userDataDir);\n await browserContext.close().catch(() => {});\n await afterClose();\n this._userDataDirs.delete(userDataDir);\n testDebug('close browser context complete (persistent)');\n }\n\n private async _createUserDataDir(clientInfo: ClientInfo) {\n const dir = process.env.PWMCP_PROFILES_DIR_FOR_TEST ?? registryDirectory;\n const browserToken = this.config.browser.launchOptions?.channel ?? this.config.browser?.browserName;\n // Hesitant putting hundreds of files into the user's workspace, so using it for hashing instead.\n const rootPath = firstRootPath(clientInfo);\n const rootPathToken = rootPath ? `-${createHash(rootPath)}` : '';\n const result = path.join(dir, `mcp-${browserToken}${rootPathToken}`);\n await fs.promises.mkdir(result, { recursive: true });\n return result;\n }\n}\n\nasync function injectCdpPort(browserConfig: FullConfig['browser']) {\n if (browserConfig.browserName === 'chromium')\n (browserConfig.launchOptions as any).cdpPort = await findFreePort();\n}\n\nasync function findFreePort(): Promise<number> {\n return new Promise((resolve, reject) => {\n const server = net.createServer();\n server.listen(0, () => {\n const { port } = server.address() as net.AddressInfo;\n server.close(() => resolve(port));\n });\n server.on('error', reject);\n });\n}\n\nasync function startTraceServer(config: FullConfig, tracesDir: string): Promise<string | undefined> {\n if (!config.saveTrace)\n return;\n\n const server = await startTraceViewerServer();\n const urlPrefix = server.urlPrefix('human-readable');\n const url = urlPrefix + '/trace/index.html?trace=' + tracesDir + '/trace.json';\n // eslint-disable-next-line no-console\n console.error('\\nTrace viewer listening on ' + url);\n}\n\nfunction createHash(data: string): string {\n return crypto.createHash('sha256').update(data).digest('hex').slice(0, 7);\n}\n\nasync function addInitScript(browserContext: playwright.BrowserContext, initScript: string[] | undefined) {\n for (const scriptPath of initScript ?? [])\n await browserContext.addInitScript({ path: path.resolve(scriptPath) });\n}\n\nexport class SharedContextFactory implements BrowserContextFactory {\n private _contextPromise: Promise<BrowserContextFactoryResult> | undefined;\n private _baseFactory: BrowserContextFactory;\n private static _instance: SharedContextFactory | undefined;\n\n static create(config: FullConfig) {\n if (SharedContextFactory._instance)\n throw new Error('SharedContextFactory already exists');\n const baseConfig = { ...config, sharedBrowserContext: false };\n const baseFactory = contextFactory(baseConfig);\n SharedContextFactory._instance = new SharedContextFactory(baseFactory);\n return SharedContextFactory._instance;\n }\n\n private constructor(baseFactory: BrowserContextFactory) {\n this._baseFactory = baseFactory;\n }\n\n async createContext(clientInfo: ClientInfo, abortSignal: AbortSignal, toolName: string | undefined): Promise<{ browserContext: playwright.BrowserContext, close: () => Promise<void> }> {\n if (!this._contextPromise) {\n testDebug('create shared browser context');\n this._contextPromise = this._baseFactory.createContext(clientInfo, abortSignal, toolName);\n }\n\n const { browserContext } = await this._contextPromise;\n testDebug(`shared context client connected`);\n return {\n browserContext,\n close: async () => {\n testDebug(`shared context client disconnected`);\n },\n };\n }\n\n static async dispose() {\n await SharedContextFactory._instance?._dispose();\n }\n\n private async _dispose() {\n const contextPromise = this._contextPromise;\n this._contextPromise = undefined;\n if (!contextPromise)\n return;\n const { close } = await contextPromise;\n await close(async () => {});\n }\n}\n\nasync function computeTracesDir(config: FullConfig, clientInfo: ClientInfo): Promise<string | undefined> {\n if (!config.saveTrace && !config.capabilities?.includes('tracing'))\n return;\n return await outputFile(config, clientInfo, `traces`, { origin: 'code', reason: 'Collecting trace' });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_server", "path", "fs", "net", "crypto"]
|
|
7
|
+
}
|
|
@@ -47,24 +47,32 @@ class BrowserServerBackend {
|
|
|
47
47
|
}
|
|
48
48
|
async callTool(name, rawArguments) {
|
|
49
49
|
const tool = this._tools.find((tool2) => tool2.schema.name === name);
|
|
50
|
-
if (!tool)
|
|
51
|
-
|
|
50
|
+
if (!tool) {
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text: `### Error
|
|
53
|
+
Tool "${name}" not found` }],
|
|
54
|
+
isError: true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
52
57
|
const parsedArguments = tool.schema.inputSchema.parse(rawArguments || {});
|
|
53
58
|
const context = this._context;
|
|
54
|
-
const response =
|
|
55
|
-
response.logBegin();
|
|
59
|
+
const response = import_response.Response.create(context, name, parsedArguments);
|
|
56
60
|
context.setRunningTool(name);
|
|
61
|
+
let responseObject;
|
|
57
62
|
try {
|
|
58
63
|
await tool.handle(context, parsedArguments, response);
|
|
59
|
-
await response.
|
|
60
|
-
this._sessionLog?.logResponse(
|
|
64
|
+
responseObject = await response.build();
|
|
65
|
+
this._sessionLog?.logResponse(name, parsedArguments, responseObject);
|
|
61
66
|
} catch (error) {
|
|
62
|
-
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: "text", text: `### Error
|
|
69
|
+
${String(error)}` }],
|
|
70
|
+
isError: true
|
|
71
|
+
};
|
|
63
72
|
} finally {
|
|
64
73
|
context.setRunningTool(void 0);
|
|
65
74
|
}
|
|
66
|
-
|
|
67
|
-
return response.serialize();
|
|
75
|
+
return responseObject;
|
|
68
76
|
}
|
|
69
77
|
serverClosed() {
|
|
70
78
|
void this._context?.dispose().catch(import_log.logUnhandledError);
|
|
@@ -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(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,YAAiD;AAChE,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,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
|
+
}
|
|
@@ -32,13 +32,15 @@ __export(config_exports, {
|
|
|
32
32
|
configFromCLIOptions: () => configFromCLIOptions,
|
|
33
33
|
defaultConfig: () => defaultConfig,
|
|
34
34
|
dotenvFileLoader: () => dotenvFileLoader,
|
|
35
|
+
enumParser: () => enumParser,
|
|
35
36
|
headerParser: () => headerParser,
|
|
36
37
|
numberParser: () => numberParser,
|
|
37
38
|
outputDir: () => outputDir,
|
|
38
39
|
outputFile: () => outputFile,
|
|
39
40
|
resolutionParser: () => resolutionParser,
|
|
40
41
|
resolveCLIConfig: () => resolveCLIConfig,
|
|
41
|
-
resolveConfig: () => resolveConfig
|
|
42
|
+
resolveConfig: () => resolveConfig,
|
|
43
|
+
semicolonSeparatedList: () => semicolonSeparatedList
|
|
42
44
|
});
|
|
43
45
|
module.exports = __toCommonJS(config_exports);
|
|
44
46
|
var import_fs = __toESM(require("fs"));
|
|
@@ -60,8 +62,19 @@ const defaultConfig = {
|
|
|
60
62
|
viewport: null
|
|
61
63
|
}
|
|
62
64
|
},
|
|
65
|
+
console: {
|
|
66
|
+
level: "info"
|
|
67
|
+
},
|
|
68
|
+
network: {
|
|
69
|
+
allowedOrigins: void 0,
|
|
70
|
+
blockedOrigins: void 0
|
|
71
|
+
},
|
|
63
72
|
server: {},
|
|
64
73
|
saveTrace: false,
|
|
74
|
+
snapshot: {
|
|
75
|
+
mode: "incremental",
|
|
76
|
+
output: "stdout"
|
|
77
|
+
},
|
|
65
78
|
timeouts: {
|
|
66
79
|
action: 5e3,
|
|
67
80
|
navigation: 6e4
|
|
@@ -88,6 +101,12 @@ async function validateConfig(config) {
|
|
|
88
101
|
throw new Error(`Init script file does not exist: ${script}`);
|
|
89
102
|
}
|
|
90
103
|
}
|
|
104
|
+
if (config.browser.initPage) {
|
|
105
|
+
for (const page of config.browser.initPage) {
|
|
106
|
+
if (!await (0, import_util.fileExistsAsync)(page))
|
|
107
|
+
throw new Error(`Init page file does not exist: ${page}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
91
110
|
if (config.sharedBrowserContext && config.saveVideo)
|
|
92
111
|
throw new Error("saveVideo is not supported when sharedBrowserContext is true");
|
|
93
112
|
}
|
|
@@ -143,13 +162,6 @@ function configFromCLIOptions(cliOptions) {
|
|
|
143
162
|
contextOptions.serviceWorkers = "block";
|
|
144
163
|
if (cliOptions.grantPermissions)
|
|
145
164
|
contextOptions.permissions = cliOptions.grantPermissions;
|
|
146
|
-
if (cliOptions.saveVideo) {
|
|
147
|
-
contextOptions.recordVideo = {
|
|
148
|
-
// Videos are moved to output directory on saveAs.
|
|
149
|
-
dir: tmpDir(),
|
|
150
|
-
size: cliOptions.saveVideo
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
165
|
const result = {
|
|
154
166
|
browser: {
|
|
155
167
|
browserName,
|
|
@@ -168,11 +180,22 @@ function configFromCLIOptions(cliOptions) {
|
|
|
168
180
|
allowedHosts: cliOptions.allowedHosts
|
|
169
181
|
},
|
|
170
182
|
capabilities: cliOptions.caps,
|
|
183
|
+
console: {
|
|
184
|
+
level: cliOptions.consoleLevel
|
|
185
|
+
},
|
|
186
|
+
network: {
|
|
187
|
+
allowedOrigins: cliOptions.allowedOrigins,
|
|
188
|
+
blockedOrigins: cliOptions.blockedOrigins
|
|
189
|
+
},
|
|
190
|
+
allowUnrestrictedFileAccess: cliOptions.allowUnrestrictedFileAccess,
|
|
191
|
+
codegen: cliOptions.codegen,
|
|
171
192
|
saveSession: cliOptions.saveSession,
|
|
172
193
|
saveTrace: cliOptions.saveTrace,
|
|
173
194
|
saveVideo: cliOptions.saveVideo,
|
|
174
195
|
secrets: cliOptions.secrets,
|
|
175
196
|
sharedBrowserContext: cliOptions.sharedBrowserContext,
|
|
197
|
+
snapshot: cliOptions.snapshotMode ? { mode: cliOptions.snapshotMode } : void 0,
|
|
198
|
+
outputMode: cliOptions.outputMode,
|
|
176
199
|
outputDir: cliOptions.outputDir,
|
|
177
200
|
imageResponses: cliOptions.imageResponses,
|
|
178
201
|
testIdAttribute: cliOptions.testIdAttribute,
|
|
@@ -186,12 +209,17 @@ function configFromCLIOptions(cliOptions) {
|
|
|
186
209
|
function configFromEnv() {
|
|
187
210
|
const options = {};
|
|
188
211
|
options.allowedHosts = commaSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_HOSTNAMES);
|
|
212
|
+
options.allowedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_ALLOWED_ORIGINS);
|
|
213
|
+
options.allowUnrestrictedFileAccess = envToBoolean(process.env.PLAYWRIGHT_MCP_ALLOW_UNRESTRICTED_FILE_ACCESS);
|
|
214
|
+
options.blockedOrigins = semicolonSeparatedList(process.env.PLAYWRIGHT_MCP_BLOCKED_ORIGINS);
|
|
189
215
|
options.blockServiceWorkers = envToBoolean(process.env.PLAYWRIGHT_MCP_BLOCK_SERVICE_WORKERS);
|
|
190
216
|
options.browser = envToString(process.env.PLAYWRIGHT_MCP_BROWSER);
|
|
191
217
|
options.caps = commaSeparatedList(process.env.PLAYWRIGHT_MCP_CAPS);
|
|
192
218
|
options.cdpEndpoint = envToString(process.env.PLAYWRIGHT_MCP_CDP_ENDPOINT);
|
|
193
219
|
options.cdpHeader = headerParser(process.env.PLAYWRIGHT_MCP_CDP_HEADERS, {});
|
|
194
220
|
options.config = envToString(process.env.PLAYWRIGHT_MCP_CONFIG);
|
|
221
|
+
if (process.env.PLAYWRIGHT_MCP_CONSOLE_LEVEL)
|
|
222
|
+
options.consoleLevel = enumParser("--console-level", ["error", "warning", "info", "debug"], process.env.PLAYWRIGHT_MCP_CONSOLE_LEVEL);
|
|
195
223
|
options.device = envToString(process.env.PLAYWRIGHT_MCP_DEVICE);
|
|
196
224
|
options.executablePath = envToString(process.env.PLAYWRIGHT_MCP_EXECUTABLE_PATH);
|
|
197
225
|
options.grantPermissions = commaSeparatedList(process.env.PLAYWRIGHT_MCP_GRANT_PERMISSIONS);
|
|
@@ -205,8 +233,8 @@ function configFromEnv() {
|
|
|
205
233
|
if (initScript)
|
|
206
234
|
options.initScript = [initScript];
|
|
207
235
|
options.isolated = envToBoolean(process.env.PLAYWRIGHT_MCP_ISOLATED);
|
|
208
|
-
if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES
|
|
209
|
-
options.imageResponses = "omit";
|
|
236
|
+
if (process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES)
|
|
237
|
+
options.imageResponses = enumParser("--image-responses", ["allow", "omit"], process.env.PLAYWRIGHT_MCP_IMAGE_RESPONSES);
|
|
210
238
|
options.sandbox = envToBoolean(process.env.PLAYWRIGHT_MCP_SANDBOX);
|
|
211
239
|
options.outputDir = envToString(process.env.PLAYWRIGHT_MCP_OUTPUT_DIR);
|
|
212
240
|
options.port = numberParser(process.env.PLAYWRIGHT_MCP_PORT);
|
|
@@ -242,7 +270,8 @@ function outputDir(config, clientInfo) {
|
|
|
242
270
|
}
|
|
243
271
|
async function outputFile(config, clientInfo, fileName, options) {
|
|
244
272
|
const file = await resolveFile(config, clientInfo, fileName, options);
|
|
245
|
-
|
|
273
|
+
await import_fs.default.promises.mkdir(import_path.default.dirname(file), { recursive: true });
|
|
274
|
+
(0, import_utilsBundle.debug)("pw:mcp:file")(options.title, file);
|
|
246
275
|
return file;
|
|
247
276
|
}
|
|
248
277
|
async function resolveFile(config, clientInfo, fileName, options) {
|
|
@@ -285,16 +314,33 @@ function mergeConfig(base, overrides) {
|
|
|
285
314
|
...pickDefined(base),
|
|
286
315
|
...pickDefined(overrides),
|
|
287
316
|
browser,
|
|
317
|
+
console: {
|
|
318
|
+
...pickDefined(base.console),
|
|
319
|
+
...pickDefined(overrides.console)
|
|
320
|
+
},
|
|
321
|
+
network: {
|
|
322
|
+
...pickDefined(base.network),
|
|
323
|
+
...pickDefined(overrides.network)
|
|
324
|
+
},
|
|
288
325
|
server: {
|
|
289
326
|
...pickDefined(base.server),
|
|
290
327
|
...pickDefined(overrides.server)
|
|
291
328
|
},
|
|
329
|
+
snapshot: {
|
|
330
|
+
...pickDefined(base.snapshot),
|
|
331
|
+
...pickDefined(overrides.snapshot)
|
|
332
|
+
},
|
|
292
333
|
timeouts: {
|
|
293
334
|
...pickDefined(base.timeouts),
|
|
294
335
|
...pickDefined(overrides.timeouts)
|
|
295
336
|
}
|
|
296
337
|
};
|
|
297
338
|
}
|
|
339
|
+
function semicolonSeparatedList(value) {
|
|
340
|
+
if (!value)
|
|
341
|
+
return void 0;
|
|
342
|
+
return value.split(";").map((v) => v.trim());
|
|
343
|
+
}
|
|
298
344
|
function commaSeparatedList(value) {
|
|
299
345
|
if (!value)
|
|
300
346
|
return void 0;
|
|
@@ -335,6 +381,11 @@ function headerParser(arg, previous) {
|
|
|
335
381
|
result[name] = value;
|
|
336
382
|
return result;
|
|
337
383
|
}
|
|
384
|
+
function enumParser(name, options, value) {
|
|
385
|
+
if (!options.includes(value))
|
|
386
|
+
throw new Error(`Invalid ${name}: ${value}. Valid values are: ${options.join(", ")}`);
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
338
389
|
function envToBoolean(value) {
|
|
339
390
|
if (value === "true" || value === "1")
|
|
340
391
|
return true;
|
|
@@ -358,11 +409,13 @@ function sanitizeForFilePath(s) {
|
|
|
358
409
|
configFromCLIOptions,
|
|
359
410
|
defaultConfig,
|
|
360
411
|
dotenvFileLoader,
|
|
412
|
+
enumParser,
|
|
361
413
|
headerParser,
|
|
362
414
|
numberParser,
|
|
363
415
|
outputDir,
|
|
364
416
|
outputFile,
|
|
365
417
|
resolutionParser,
|
|
366
418
|
resolveCLIConfig,
|
|
367
|
-
resolveConfig
|
|
419
|
+
resolveConfig,
|
|
420
|
+
semicolonSeparatedList
|
|
368
421
|
});
|
|
@@ -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 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 initPage?: 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 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 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 initPage: cliOptions.initPage,\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 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.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 initPage = envToString(process.env.PLAYWRIGHT_MCP_INIT_PAGE);\n if (initPage)\n options.initPage = [initPage];\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\nfunction 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 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 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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["os", "fs", "path", "s"]
|
|
7
|
+
}
|