@szymonrybczak/playwright-mcp 0.0.9 → 0.0.11
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.
- package/lib/cjs/cloudflare/package.json.js +1 -1
- package/lib/cjs/debugStub.js +20 -0
- package/lib/cjs/src/browserContextFactory.js +59 -15
- package/lib/cjs/src/context.js +49 -9
- package/lib/cjs/src/tab.js +18 -2
- package/lib/cjs/src/tools/navigate.js +28 -3
- package/lib/esm/cloudflare/package.json.js +1 -1
- package/lib/esm/debugStub.js +16 -0
- package/lib/esm/src/browserContextFactory.js +59 -15
- package/lib/esm/src/context.js +49 -9
- package/lib/esm/src/tab.js +18 -2
- package/lib/esm/src/tools/navigate.js +28 -3
- package/package.json +1 -1
- package/lib/cjs/_virtual/_commonjsHelpers.js +0 -9
- package/lib/cjs/_virtual/browser.js +0 -11
- package/lib/cjs/_virtual/browser2.js +0 -7
- package/lib/cjs/node_modules/debug/src/browser.js +0 -290
- package/lib/cjs/node_modules/debug/src/common.js +0 -307
- package/lib/cjs/node_modules/ms/index.js +0 -176
- package/lib/esm/_virtual/_commonjsHelpers.js +0 -5
- package/lib/esm/_virtual/browser.js +0 -7
- package/lib/esm/_virtual/browser2.js +0 -3
- package/lib/esm/node_modules/debug/src/browser.js +0 -286
- package/lib/esm/node_modules/debug/src/common.js +0 -303
- package/lib/esm/node_modules/ms/index.js +0 -172
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
|
|
4
|
+
|
|
5
|
+
function createDebug(_namespace) {
|
|
6
|
+
const debug = (..._args) => {
|
|
7
|
+
};
|
|
8
|
+
debug.enabled = false;
|
|
9
|
+
debug.namespace = _namespace;
|
|
10
|
+
debug.extend = (namespace) => createDebug(`${_namespace}:${namespace}`);
|
|
11
|
+
debug.destroy = () => {
|
|
12
|
+
};
|
|
13
|
+
return debug;
|
|
14
|
+
}
|
|
15
|
+
createDebug.enable = (_namespaces) => {
|
|
16
|
+
};
|
|
17
|
+
createDebug.disable = () => "";
|
|
18
|
+
createDebug.enabled = (_namespace) => false;
|
|
19
|
+
|
|
20
|
+
exports.default = createDebug;
|
|
@@ -6,7 +6,7 @@ const __viteBrowserExternal = require('../_virtual/__vite-browser-external.js');
|
|
|
6
6
|
const net = require('node:net');
|
|
7
7
|
const path = require('node:path');
|
|
8
8
|
const os = require('node:os');
|
|
9
|
-
const
|
|
9
|
+
const debugStub = require('../debugStub.js');
|
|
10
10
|
const playwright = require('@szymonrybczak/patchright');
|
|
11
11
|
const fileUtils = require('./fileUtils.js');
|
|
12
12
|
|
|
@@ -29,16 +29,27 @@ function _interopNamespaceDefault(e) {
|
|
|
29
29
|
|
|
30
30
|
const playwright__namespace = /*#__PURE__*/_interopNamespaceDefault(playwright);
|
|
31
31
|
|
|
32
|
-
const testDebug =
|
|
32
|
+
const testDebug = debugStub.default("pw:mcp:test");
|
|
33
33
|
function contextFactory(browserConfig) {
|
|
34
|
-
|
|
34
|
+
console.log("[contextFactory] START");
|
|
35
|
+
console.log("[contextFactory] browserConfig:", JSON.stringify(browserConfig, null, 2));
|
|
36
|
+
if (browserConfig.remoteEndpoint) {
|
|
37
|
+
console.log("[contextFactory] Using RemoteContextFactory");
|
|
35
38
|
return new RemoteContextFactory(browserConfig);
|
|
36
|
-
|
|
39
|
+
}
|
|
40
|
+
if (browserConfig.cdpEndpoint) {
|
|
41
|
+
console.log("[contextFactory] Using CdpContextFactory");
|
|
37
42
|
return new CdpContextFactory(browserConfig);
|
|
38
|
-
|
|
43
|
+
}
|
|
44
|
+
if (browserConfig.isolated) {
|
|
45
|
+
console.log("[contextFactory] Using IsolatedContextFactory");
|
|
39
46
|
return new IsolatedContextFactory(browserConfig);
|
|
40
|
-
|
|
47
|
+
}
|
|
48
|
+
if (browserConfig.browserAgent) {
|
|
49
|
+
console.log("[contextFactory] Using BrowserServerContextFactory");
|
|
41
50
|
return new BrowserServerContextFactory(browserConfig);
|
|
51
|
+
}
|
|
52
|
+
console.log("[contextFactory] Using PersistentContextFactory");
|
|
42
53
|
return new PersistentContextFactory(browserConfig);
|
|
43
54
|
}
|
|
44
55
|
class BaseContextFactory {
|
|
@@ -48,17 +59,26 @@ class BaseContextFactory {
|
|
|
48
59
|
constructor(name, browserConfig) {
|
|
49
60
|
this.name = name;
|
|
50
61
|
this.browserConfig = browserConfig;
|
|
62
|
+
console.log(`[BaseContextFactory] Created factory: ${name}`);
|
|
51
63
|
}
|
|
52
64
|
async _obtainBrowser() {
|
|
53
|
-
|
|
65
|
+
console.log(`[BaseContextFactory._obtainBrowser] START (${this.name})`);
|
|
66
|
+
console.log(`[BaseContextFactory._obtainBrowser] _browserPromise exists:`, !!this._browserPromise);
|
|
67
|
+
if (this._browserPromise) {
|
|
68
|
+
console.log(`[BaseContextFactory._obtainBrowser] Returning existing promise`);
|
|
54
69
|
return this._browserPromise;
|
|
70
|
+
}
|
|
55
71
|
testDebug(`obtain browser (${this.name})`);
|
|
72
|
+
console.log(`[BaseContextFactory._obtainBrowser] Calling _doObtainBrowser...`);
|
|
56
73
|
this._browserPromise = this._doObtainBrowser();
|
|
57
74
|
void this._browserPromise.then((browser) => {
|
|
75
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser obtained successfully`);
|
|
58
76
|
browser.on("disconnected", () => {
|
|
77
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser disconnected`);
|
|
59
78
|
this._browserPromise = void 0;
|
|
60
79
|
});
|
|
61
|
-
}).catch(() => {
|
|
80
|
+
}).catch((err) => {
|
|
81
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser promise rejected:`, err.message);
|
|
62
82
|
this._browserPromise = void 0;
|
|
63
83
|
});
|
|
64
84
|
return this._browserPromise;
|
|
@@ -67,15 +87,22 @@ class BaseContextFactory {
|
|
|
67
87
|
throw new Error("Not implemented");
|
|
68
88
|
}
|
|
69
89
|
async createContext() {
|
|
90
|
+
console.log(`[BaseContextFactory.createContext] START (${this.name})`);
|
|
70
91
|
testDebug(`create browser context (${this.name})`);
|
|
92
|
+
console.log(`[BaseContextFactory.createContext] Calling _obtainBrowser...`);
|
|
71
93
|
const browser = await this._obtainBrowser();
|
|
94
|
+
console.log(`[BaseContextFactory.createContext] Got browser`);
|
|
95
|
+
console.log(`[BaseContextFactory.createContext] Calling _doCreateContext...`);
|
|
72
96
|
const browserContext = await this._doCreateContext(browser);
|
|
97
|
+
console.log(`[BaseContextFactory.createContext] Got browserContext`);
|
|
98
|
+
console.log(`[BaseContextFactory.createContext] END`);
|
|
73
99
|
return { browserContext, close: () => this._closeBrowserContext(browserContext, browser) };
|
|
74
100
|
}
|
|
75
101
|
async _doCreateContext(browser) {
|
|
76
102
|
throw new Error("Not implemented");
|
|
77
103
|
}
|
|
78
104
|
async _closeBrowserContext(browserContext, browser) {
|
|
105
|
+
console.log(`[BaseContextFactory._closeBrowserContext] START (${this.name})`);
|
|
79
106
|
testDebug(`close browser context (${this.name})`);
|
|
80
107
|
if (browser.contexts().length === 1)
|
|
81
108
|
this._browserPromise = void 0;
|
|
@@ -86,6 +113,7 @@ class BaseContextFactory {
|
|
|
86
113
|
await browser.close().catch(() => {
|
|
87
114
|
});
|
|
88
115
|
}
|
|
116
|
+
console.log(`[BaseContextFactory._closeBrowserContext] END`);
|
|
89
117
|
}
|
|
90
118
|
}
|
|
91
119
|
class IsolatedContextFactory extends BaseContextFactory {
|
|
@@ -114,10 +142,31 @@ class CdpContextFactory extends BaseContextFactory {
|
|
|
114
142
|
super("cdp", browserConfig);
|
|
115
143
|
}
|
|
116
144
|
async _doObtainBrowser() {
|
|
117
|
-
|
|
145
|
+
console.log("[CdpContextFactory._doObtainBrowser] START");
|
|
146
|
+
console.log("[CdpContextFactory._doObtainBrowser] cdpEndpoint:", this.browserConfig.cdpEndpoint);
|
|
147
|
+
console.log("[CdpContextFactory._doObtainBrowser] playwright object keys:", Object.keys(playwright__namespace));
|
|
148
|
+
console.log("[CdpContextFactory._doObtainBrowser] playwright.chromium:", typeof playwright__namespace.chromium);
|
|
149
|
+
try {
|
|
150
|
+
console.log("[CdpContextFactory._doObtainBrowser] Calling connectOverCDP...");
|
|
151
|
+
const browser = await playwright__namespace.chromium.connectOverCDP(this.browserConfig.cdpEndpoint);
|
|
152
|
+
console.log("[CdpContextFactory._doObtainBrowser] connectOverCDP completed");
|
|
153
|
+
return browser;
|
|
154
|
+
} catch (err) {
|
|
155
|
+
console.log("[CdpContextFactory._doObtainBrowser] ERROR:", err.message, err.stack);
|
|
156
|
+
throw err;
|
|
157
|
+
}
|
|
118
158
|
}
|
|
119
159
|
async _doCreateContext(browser) {
|
|
120
|
-
|
|
160
|
+
console.log("[CdpContextFactory._doCreateContext] START");
|
|
161
|
+
console.log("[CdpContextFactory._doCreateContext] isolated:", this.browserConfig.isolated);
|
|
162
|
+
try {
|
|
163
|
+
const ctx = this.browserConfig.isolated ? await browser.newContext() : browser.contexts()[0];
|
|
164
|
+
console.log("[CdpContextFactory._doCreateContext] Got context");
|
|
165
|
+
return ctx;
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.log("[CdpContextFactory._doCreateContext] ERROR:", err.message, err.stack);
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
121
170
|
}
|
|
122
171
|
}
|
|
123
172
|
class RemoteContextFactory extends BaseContextFactory {
|
|
@@ -143,10 +192,8 @@ class PersistentContextFactory {
|
|
|
143
192
|
}
|
|
144
193
|
async createContext() {
|
|
145
194
|
await injectCdpPort(this.browserConfig);
|
|
146
|
-
testDebug("create browser context (persistent)");
|
|
147
195
|
const userDataDir2 = this.browserConfig.userDataDir ?? await this._createUserDataDir();
|
|
148
196
|
this._userDataDirs.add(userDataDir2);
|
|
149
|
-
testDebug("lock user data dir", userDataDir2);
|
|
150
197
|
const browserType = playwright__namespace[this.browserConfig.browserName];
|
|
151
198
|
for (let i = 0; i < 5; i++) {
|
|
152
199
|
try {
|
|
@@ -171,12 +218,9 @@ class PersistentContextFactory {
|
|
|
171
218
|
throw new Error(`Browser is already in use for ${userDataDir2}, use --isolated to run multiple instances of the same browser`);
|
|
172
219
|
}
|
|
173
220
|
async _closeBrowserContext(browserContext, userDataDir2) {
|
|
174
|
-
testDebug("close browser context (persistent)");
|
|
175
|
-
testDebug("release user data dir", userDataDir2);
|
|
176
221
|
await browserContext.close().catch(() => {
|
|
177
222
|
});
|
|
178
223
|
this._userDataDirs.delete(userDataDir2);
|
|
179
|
-
testDebug("close browser context complete (persistent)");
|
|
180
224
|
}
|
|
181
225
|
async _createUserDataDir() {
|
|
182
226
|
let cacheDirectory;
|
package/lib/cjs/src/context.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const debugStub = require('../debugStub.js');
|
|
6
6
|
const utils = require('./tools/utils.js');
|
|
7
7
|
const manualPromise = require('./manualPromise.js');
|
|
8
8
|
const tab = require('./tab.js');
|
|
9
9
|
const config = require('./config.js');
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
debugStub.default("pw:mcp:test");
|
|
12
12
|
class Context {
|
|
13
13
|
tools;
|
|
14
14
|
config;
|
|
@@ -24,7 +24,6 @@ class Context {
|
|
|
24
24
|
this.tools = tools;
|
|
25
25
|
this.config = config;
|
|
26
26
|
this._browserContextFactory = browserContextFactory;
|
|
27
|
-
testDebug("create context");
|
|
28
27
|
}
|
|
29
28
|
clientSupportsImages() {
|
|
30
29
|
if (this.config.imageResponses === "allow")
|
|
@@ -71,9 +70,29 @@ class Context {
|
|
|
71
70
|
await this._currentTab.page.bringToFront();
|
|
72
71
|
}
|
|
73
72
|
async ensureTab() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
console.log("[Context.ensureTab] START");
|
|
74
|
+
console.log("[Context.ensureTab] _currentTab exists:", !!this._currentTab);
|
|
75
|
+
console.log("[Context.ensureTab] Calling _ensureBrowserContext()...");
|
|
76
|
+
let browserContext;
|
|
77
|
+
try {
|
|
78
|
+
const result = await this._ensureBrowserContext();
|
|
79
|
+
browserContext = result.browserContext;
|
|
80
|
+
console.log("[Context.ensureTab] _ensureBrowserContext() completed");
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.log("[Context.ensureTab] ERROR in _ensureBrowserContext():", err.message, err.stack);
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
if (!this._currentTab) {
|
|
86
|
+
console.log("[Context.ensureTab] No current tab, creating new page...");
|
|
87
|
+
try {
|
|
88
|
+
await browserContext.newPage();
|
|
89
|
+
console.log("[Context.ensureTab] New page created");
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.log("[Context.ensureTab] ERROR creating new page:", err.message, err.stack);
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
console.log("[Context.ensureTab] END, returning tab");
|
|
77
96
|
return this._currentTab;
|
|
78
97
|
}
|
|
79
98
|
async listTabsMarkdown() {
|
|
@@ -230,7 +249,6 @@ ${code.join("\n")}
|
|
|
230
249
|
async close() {
|
|
231
250
|
if (!this._browserContextPromise)
|
|
232
251
|
return;
|
|
233
|
-
testDebug("close context");
|
|
234
252
|
const promise = this._browserContextPromise;
|
|
235
253
|
this._browserContextPromise = void 0;
|
|
236
254
|
await promise.then(async ({ browserContext, close }) => {
|
|
@@ -251,29 +269,51 @@ ${code.join("\n")}
|
|
|
251
269
|
}
|
|
252
270
|
}
|
|
253
271
|
_ensureBrowserContext() {
|
|
272
|
+
console.log("[Context._ensureBrowserContext] START");
|
|
273
|
+
console.log("[Context._ensureBrowserContext] _browserContextPromise exists:", !!this._browserContextPromise);
|
|
254
274
|
if (!this._browserContextPromise) {
|
|
275
|
+
console.log("[Context._ensureBrowserContext] Creating new browser context promise...");
|
|
255
276
|
this._browserContextPromise = this._setupBrowserContext();
|
|
256
|
-
this._browserContextPromise.catch(() => {
|
|
277
|
+
this._browserContextPromise.catch((err) => {
|
|
278
|
+
console.log("[Context._ensureBrowserContext] Promise rejected:", err.message);
|
|
257
279
|
this._browserContextPromise = void 0;
|
|
258
280
|
});
|
|
259
281
|
}
|
|
282
|
+
console.log("[Context._ensureBrowserContext] END, returning promise");
|
|
260
283
|
return this._browserContextPromise;
|
|
261
284
|
}
|
|
262
285
|
async _setupBrowserContext() {
|
|
263
|
-
|
|
286
|
+
console.log("[Context._setupBrowserContext] START");
|
|
287
|
+
console.log("[Context._setupBrowserContext] Calling _browserContextFactory.createContext()...");
|
|
288
|
+
let result;
|
|
289
|
+
try {
|
|
290
|
+
result = await this._browserContextFactory.createContext();
|
|
291
|
+
console.log("[Context._setupBrowserContext] createContext() completed");
|
|
292
|
+
} catch (err) {
|
|
293
|
+
console.log("[Context._setupBrowserContext] ERROR in createContext():", err.message, err.stack);
|
|
294
|
+
throw err;
|
|
295
|
+
}
|
|
264
296
|
const { browserContext } = result;
|
|
297
|
+
console.log("[Context._setupBrowserContext] Got browserContext");
|
|
298
|
+
console.log("[Context._setupBrowserContext] Setting up request interception...");
|
|
265
299
|
await this._setupRequestInterception(browserContext);
|
|
300
|
+
console.log("[Context._setupBrowserContext] Request interception done");
|
|
301
|
+
console.log("[Context._setupBrowserContext] Processing existing pages...");
|
|
266
302
|
for (const page of browserContext.pages())
|
|
267
303
|
this._onPageCreated(page);
|
|
268
304
|
browserContext.on("page", (page) => this._onPageCreated(page));
|
|
305
|
+
console.log("[Context._setupBrowserContext] Pages processed");
|
|
269
306
|
if (this.config.saveTrace) {
|
|
307
|
+
console.log("[Context._setupBrowserContext] Starting tracing...");
|
|
270
308
|
await browserContext.tracing.start({
|
|
271
309
|
name: "trace",
|
|
272
310
|
screenshots: false,
|
|
273
311
|
snapshots: true,
|
|
274
312
|
sources: false
|
|
275
313
|
});
|
|
314
|
+
console.log("[Context._setupBrowserContext] Tracing started");
|
|
276
315
|
}
|
|
316
|
+
console.log("[Context._setupBrowserContext] END");
|
|
277
317
|
return result;
|
|
278
318
|
}
|
|
279
319
|
}
|
package/lib/cjs/src/tab.js
CHANGED
|
@@ -50,24 +50,40 @@ class Tab {
|
|
|
50
50
|
}));
|
|
51
51
|
}
|
|
52
52
|
async navigate(url) {
|
|
53
|
+
console.log("[Tab.navigate] START, url:", url);
|
|
54
|
+
console.log("[Tab.navigate] Clearing collected artifacts...");
|
|
53
55
|
this._clearCollectedArtifacts();
|
|
56
|
+
console.log("[Tab.navigate] Artifacts cleared");
|
|
57
|
+
console.log("[Tab.navigate] Setting up download event listener...");
|
|
54
58
|
const downloadEvent = utils.callOnPageNoTrace(this.page, (page) => page.waitForEvent("download").catch(() => {
|
|
55
59
|
}));
|
|
60
|
+
console.log("[Tab.navigate] Download event listener ready");
|
|
56
61
|
try {
|
|
62
|
+
console.log("[Tab.navigate] Calling page.goto()...");
|
|
57
63
|
await this.page.goto(url, { waitUntil: "domcontentloaded" });
|
|
64
|
+
console.log("[Tab.navigate] page.goto() completed successfully");
|
|
58
65
|
} catch (_e) {
|
|
59
66
|
const e = _e;
|
|
67
|
+
console.log("[Tab.navigate] page.goto() threw error:", e.message);
|
|
60
68
|
const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
|
|
61
|
-
if (!mightBeDownload)
|
|
69
|
+
if (!mightBeDownload) {
|
|
70
|
+
console.log("[Tab.navigate] Not a download, re-throwing error");
|
|
62
71
|
throw e;
|
|
72
|
+
}
|
|
73
|
+
console.log("[Tab.navigate] Might be download, waiting for download event...");
|
|
63
74
|
const download = await Promise.race([
|
|
64
75
|
downloadEvent,
|
|
65
76
|
new Promise((resolve) => setTimeout(resolve, 1e3))
|
|
66
77
|
]);
|
|
67
|
-
if (!download)
|
|
78
|
+
if (!download) {
|
|
79
|
+
console.log("[Tab.navigate] No download received, re-throwing error");
|
|
68
80
|
throw e;
|
|
81
|
+
}
|
|
82
|
+
console.log("[Tab.navigate] Download detected");
|
|
69
83
|
}
|
|
84
|
+
console.log("[Tab.navigate] Waiting for load state...");
|
|
70
85
|
await this.waitForLoadState("load", { timeout: 5e3 });
|
|
86
|
+
console.log("[Tab.navigate] END");
|
|
71
87
|
}
|
|
72
88
|
hasSnapshot() {
|
|
73
89
|
return !!this._snapshot;
|
|
@@ -5,6 +5,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
|
|
|
5
5
|
const zod = require('zod');
|
|
6
6
|
const tool = require('./tool.js');
|
|
7
7
|
|
|
8
|
+
const log = (msg, data) => {
|
|
9
|
+
console.log(`[browser_navigate] ${msg}`, data !== void 0 ? JSON.stringify(data, null, 2) : "");
|
|
10
|
+
};
|
|
8
11
|
const navigate = (captureSnapshot) => tool.defineTool({
|
|
9
12
|
capability: "core",
|
|
10
13
|
schema: {
|
|
@@ -17,17 +20,39 @@ const navigate = (captureSnapshot) => tool.defineTool({
|
|
|
17
20
|
type: "destructive"
|
|
18
21
|
},
|
|
19
22
|
handle: async (context, params) => {
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
log("=== NAVIGATE HANDLER START ===");
|
|
24
|
+
log("Params received:", params);
|
|
25
|
+
log("captureSnapshot:", captureSnapshot);
|
|
26
|
+
log("About to call context.ensureTab()...");
|
|
27
|
+
let tab;
|
|
28
|
+
try {
|
|
29
|
+
tab = await context.ensureTab();
|
|
30
|
+
log("context.ensureTab() completed successfully");
|
|
31
|
+
log("Tab page URL:", tab.page?.url?.());
|
|
32
|
+
} catch (err) {
|
|
33
|
+
log("ERROR in context.ensureTab():", { message: err.message, stack: err.stack });
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
log(`About to call tab.navigate("${params.url}")...`);
|
|
37
|
+
try {
|
|
38
|
+
await tab.navigate(params.url);
|
|
39
|
+
log("tab.navigate() completed successfully");
|
|
40
|
+
} catch (err) {
|
|
41
|
+
log("ERROR in tab.navigate():", { message: err.message, stack: err.stack });
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
22
44
|
const code = [
|
|
23
45
|
`// Navigate to ${params.url}`,
|
|
24
46
|
`await page.goto('${params.url}');`
|
|
25
47
|
];
|
|
26
|
-
return
|
|
48
|
+
log("About to return result...");
|
|
49
|
+
const result = {
|
|
27
50
|
code,
|
|
28
51
|
captureSnapshot,
|
|
29
52
|
waitForNetwork: false
|
|
30
53
|
};
|
|
54
|
+
log("=== NAVIGATE HANDLER END ===");
|
|
55
|
+
return result;
|
|
31
56
|
}
|
|
32
57
|
});
|
|
33
58
|
const goBack = (captureSnapshot) => tool.defineTool({
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function createDebug(_namespace) {
|
|
2
|
+
const debug = (..._args) => {
|
|
3
|
+
};
|
|
4
|
+
debug.enabled = false;
|
|
5
|
+
debug.namespace = _namespace;
|
|
6
|
+
debug.extend = (namespace) => createDebug(`${_namespace}:${namespace}`);
|
|
7
|
+
debug.destroy = () => {
|
|
8
|
+
};
|
|
9
|
+
return debug;
|
|
10
|
+
}
|
|
11
|
+
createDebug.enable = (_namespaces) => {
|
|
12
|
+
};
|
|
13
|
+
createDebug.disable = () => "";
|
|
14
|
+
createDebug.enabled = (_namespace) => false;
|
|
15
|
+
|
|
16
|
+
export { createDebug as default };
|
|
@@ -2,20 +2,31 @@ import fs from '../_virtual/__vite-browser-external.js';
|
|
|
2
2
|
import net from 'node:net';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import os from 'node:os';
|
|
5
|
-
import
|
|
5
|
+
import createDebug from '../debugStub.js';
|
|
6
6
|
import * as playwright from '@szymonrybczak/patchright';
|
|
7
7
|
import { userDataDir } from './fileUtils.js';
|
|
8
8
|
|
|
9
|
-
const testDebug =
|
|
9
|
+
const testDebug = createDebug("pw:mcp:test");
|
|
10
10
|
function contextFactory(browserConfig) {
|
|
11
|
-
|
|
11
|
+
console.log("[contextFactory] START");
|
|
12
|
+
console.log("[contextFactory] browserConfig:", JSON.stringify(browserConfig, null, 2));
|
|
13
|
+
if (browserConfig.remoteEndpoint) {
|
|
14
|
+
console.log("[contextFactory] Using RemoteContextFactory");
|
|
12
15
|
return new RemoteContextFactory(browserConfig);
|
|
13
|
-
|
|
16
|
+
}
|
|
17
|
+
if (browserConfig.cdpEndpoint) {
|
|
18
|
+
console.log("[contextFactory] Using CdpContextFactory");
|
|
14
19
|
return new CdpContextFactory(browserConfig);
|
|
15
|
-
|
|
20
|
+
}
|
|
21
|
+
if (browserConfig.isolated) {
|
|
22
|
+
console.log("[contextFactory] Using IsolatedContextFactory");
|
|
16
23
|
return new IsolatedContextFactory(browserConfig);
|
|
17
|
-
|
|
24
|
+
}
|
|
25
|
+
if (browserConfig.browserAgent) {
|
|
26
|
+
console.log("[contextFactory] Using BrowserServerContextFactory");
|
|
18
27
|
return new BrowserServerContextFactory(browserConfig);
|
|
28
|
+
}
|
|
29
|
+
console.log("[contextFactory] Using PersistentContextFactory");
|
|
19
30
|
return new PersistentContextFactory(browserConfig);
|
|
20
31
|
}
|
|
21
32
|
class BaseContextFactory {
|
|
@@ -25,17 +36,26 @@ class BaseContextFactory {
|
|
|
25
36
|
constructor(name, browserConfig) {
|
|
26
37
|
this.name = name;
|
|
27
38
|
this.browserConfig = browserConfig;
|
|
39
|
+
console.log(`[BaseContextFactory] Created factory: ${name}`);
|
|
28
40
|
}
|
|
29
41
|
async _obtainBrowser() {
|
|
30
|
-
|
|
42
|
+
console.log(`[BaseContextFactory._obtainBrowser] START (${this.name})`);
|
|
43
|
+
console.log(`[BaseContextFactory._obtainBrowser] _browserPromise exists:`, !!this._browserPromise);
|
|
44
|
+
if (this._browserPromise) {
|
|
45
|
+
console.log(`[BaseContextFactory._obtainBrowser] Returning existing promise`);
|
|
31
46
|
return this._browserPromise;
|
|
47
|
+
}
|
|
32
48
|
testDebug(`obtain browser (${this.name})`);
|
|
49
|
+
console.log(`[BaseContextFactory._obtainBrowser] Calling _doObtainBrowser...`);
|
|
33
50
|
this._browserPromise = this._doObtainBrowser();
|
|
34
51
|
void this._browserPromise.then((browser) => {
|
|
52
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser obtained successfully`);
|
|
35
53
|
browser.on("disconnected", () => {
|
|
54
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser disconnected`);
|
|
36
55
|
this._browserPromise = void 0;
|
|
37
56
|
});
|
|
38
|
-
}).catch(() => {
|
|
57
|
+
}).catch((err) => {
|
|
58
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser promise rejected:`, err.message);
|
|
39
59
|
this._browserPromise = void 0;
|
|
40
60
|
});
|
|
41
61
|
return this._browserPromise;
|
|
@@ -44,15 +64,22 @@ class BaseContextFactory {
|
|
|
44
64
|
throw new Error("Not implemented");
|
|
45
65
|
}
|
|
46
66
|
async createContext() {
|
|
67
|
+
console.log(`[BaseContextFactory.createContext] START (${this.name})`);
|
|
47
68
|
testDebug(`create browser context (${this.name})`);
|
|
69
|
+
console.log(`[BaseContextFactory.createContext] Calling _obtainBrowser...`);
|
|
48
70
|
const browser = await this._obtainBrowser();
|
|
71
|
+
console.log(`[BaseContextFactory.createContext] Got browser`);
|
|
72
|
+
console.log(`[BaseContextFactory.createContext] Calling _doCreateContext...`);
|
|
49
73
|
const browserContext = await this._doCreateContext(browser);
|
|
74
|
+
console.log(`[BaseContextFactory.createContext] Got browserContext`);
|
|
75
|
+
console.log(`[BaseContextFactory.createContext] END`);
|
|
50
76
|
return { browserContext, close: () => this._closeBrowserContext(browserContext, browser) };
|
|
51
77
|
}
|
|
52
78
|
async _doCreateContext(browser) {
|
|
53
79
|
throw new Error("Not implemented");
|
|
54
80
|
}
|
|
55
81
|
async _closeBrowserContext(browserContext, browser) {
|
|
82
|
+
console.log(`[BaseContextFactory._closeBrowserContext] START (${this.name})`);
|
|
56
83
|
testDebug(`close browser context (${this.name})`);
|
|
57
84
|
if (browser.contexts().length === 1)
|
|
58
85
|
this._browserPromise = void 0;
|
|
@@ -63,6 +90,7 @@ class BaseContextFactory {
|
|
|
63
90
|
await browser.close().catch(() => {
|
|
64
91
|
});
|
|
65
92
|
}
|
|
93
|
+
console.log(`[BaseContextFactory._closeBrowserContext] END`);
|
|
66
94
|
}
|
|
67
95
|
}
|
|
68
96
|
class IsolatedContextFactory extends BaseContextFactory {
|
|
@@ -91,10 +119,31 @@ class CdpContextFactory extends BaseContextFactory {
|
|
|
91
119
|
super("cdp", browserConfig);
|
|
92
120
|
}
|
|
93
121
|
async _doObtainBrowser() {
|
|
94
|
-
|
|
122
|
+
console.log("[CdpContextFactory._doObtainBrowser] START");
|
|
123
|
+
console.log("[CdpContextFactory._doObtainBrowser] cdpEndpoint:", this.browserConfig.cdpEndpoint);
|
|
124
|
+
console.log("[CdpContextFactory._doObtainBrowser] playwright object keys:", Object.keys(playwright));
|
|
125
|
+
console.log("[CdpContextFactory._doObtainBrowser] playwright.chromium:", typeof playwright.chromium);
|
|
126
|
+
try {
|
|
127
|
+
console.log("[CdpContextFactory._doObtainBrowser] Calling connectOverCDP...");
|
|
128
|
+
const browser = await playwright.chromium.connectOverCDP(this.browserConfig.cdpEndpoint);
|
|
129
|
+
console.log("[CdpContextFactory._doObtainBrowser] connectOverCDP completed");
|
|
130
|
+
return browser;
|
|
131
|
+
} catch (err) {
|
|
132
|
+
console.log("[CdpContextFactory._doObtainBrowser] ERROR:", err.message, err.stack);
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
95
135
|
}
|
|
96
136
|
async _doCreateContext(browser) {
|
|
97
|
-
|
|
137
|
+
console.log("[CdpContextFactory._doCreateContext] START");
|
|
138
|
+
console.log("[CdpContextFactory._doCreateContext] isolated:", this.browserConfig.isolated);
|
|
139
|
+
try {
|
|
140
|
+
const ctx = this.browserConfig.isolated ? await browser.newContext() : browser.contexts()[0];
|
|
141
|
+
console.log("[CdpContextFactory._doCreateContext] Got context");
|
|
142
|
+
return ctx;
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.log("[CdpContextFactory._doCreateContext] ERROR:", err.message, err.stack);
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
98
147
|
}
|
|
99
148
|
}
|
|
100
149
|
class RemoteContextFactory extends BaseContextFactory {
|
|
@@ -120,10 +169,8 @@ class PersistentContextFactory {
|
|
|
120
169
|
}
|
|
121
170
|
async createContext() {
|
|
122
171
|
await injectCdpPort(this.browserConfig);
|
|
123
|
-
testDebug("create browser context (persistent)");
|
|
124
172
|
const userDataDir2 = this.browserConfig.userDataDir ?? await this._createUserDataDir();
|
|
125
173
|
this._userDataDirs.add(userDataDir2);
|
|
126
|
-
testDebug("lock user data dir", userDataDir2);
|
|
127
174
|
const browserType = playwright[this.browserConfig.browserName];
|
|
128
175
|
for (let i = 0; i < 5; i++) {
|
|
129
176
|
try {
|
|
@@ -148,12 +195,9 @@ class PersistentContextFactory {
|
|
|
148
195
|
throw new Error(`Browser is already in use for ${userDataDir2}, use --isolated to run multiple instances of the same browser`);
|
|
149
196
|
}
|
|
150
197
|
async _closeBrowserContext(browserContext, userDataDir2) {
|
|
151
|
-
testDebug("close browser context (persistent)");
|
|
152
|
-
testDebug("release user data dir", userDataDir2);
|
|
153
198
|
await browserContext.close().catch(() => {
|
|
154
199
|
});
|
|
155
200
|
this._userDataDirs.delete(userDataDir2);
|
|
156
|
-
testDebug("close browser context complete (persistent)");
|
|
157
201
|
}
|
|
158
202
|
async _createUserDataDir() {
|
|
159
203
|
let cacheDirectory;
|