@szymonrybczak/playwright-mcp 0.0.16 → 0.0.18
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/src/browserContextFactory.js +68 -127
- package/lib/cjs/src/context.js +65 -35
- package/lib/cjs/src/tab.js +41 -15
- package/lib/cjs/src/tools/navigate.js +28 -21
- package/lib/esm/cloudflare/package.json.js +1 -1
- package/lib/esm/src/browserContextFactory.js +68 -127
- package/lib/esm/src/context.js +65 -35
- package/lib/esm/src/tab.js +41 -15
- package/lib/esm/src/tools/navigate.js +28 -21
- package/package.json +1 -1
|
@@ -31,25 +31,14 @@ const playwright__namespace = /*#__PURE__*/_interopNamespaceDefault(playwright);
|
|
|
31
31
|
|
|
32
32
|
const testDebug = debugStub.default("pw:mcp:test");
|
|
33
33
|
function contextFactory(browserConfig) {
|
|
34
|
-
|
|
35
|
-
console.log("[contextFactory] browserConfig:", JSON.stringify(browserConfig, null, 2));
|
|
36
|
-
if (browserConfig.remoteEndpoint) {
|
|
37
|
-
console.log("[contextFactory] Using RemoteContextFactory");
|
|
34
|
+
if (browserConfig.remoteEndpoint)
|
|
38
35
|
return new RemoteContextFactory(browserConfig);
|
|
39
|
-
|
|
40
|
-
if (browserConfig.cdpEndpoint) {
|
|
41
|
-
console.log("[contextFactory] Using CdpContextFactory");
|
|
36
|
+
if (browserConfig.cdpEndpoint)
|
|
42
37
|
return new CdpContextFactory(browserConfig);
|
|
43
|
-
|
|
44
|
-
if (browserConfig.isolated) {
|
|
45
|
-
console.log("[contextFactory] Using IsolatedContextFactory");
|
|
38
|
+
if (browserConfig.isolated)
|
|
46
39
|
return new IsolatedContextFactory(browserConfig);
|
|
47
|
-
|
|
48
|
-
if (browserConfig.browserAgent) {
|
|
49
|
-
console.log("[contextFactory] Using BrowserServerContextFactory");
|
|
40
|
+
if (browserConfig.browserAgent)
|
|
50
41
|
return new BrowserServerContextFactory(browserConfig);
|
|
51
|
-
}
|
|
52
|
-
console.log("[contextFactory] Using PersistentContextFactory");
|
|
53
42
|
return new PersistentContextFactory(browserConfig);
|
|
54
43
|
}
|
|
55
44
|
class BaseContextFactory {
|
|
@@ -59,50 +48,66 @@ class BaseContextFactory {
|
|
|
59
48
|
constructor(name, browserConfig) {
|
|
60
49
|
this.name = name;
|
|
61
50
|
this.browserConfig = browserConfig;
|
|
62
|
-
console.log(`[BaseContextFactory] Created factory: ${name}`);
|
|
63
51
|
}
|
|
64
52
|
async _obtainBrowser() {
|
|
65
|
-
console.log(`[BaseContextFactory._obtainBrowser] START (${this.name})
|
|
66
|
-
console.log(`[BaseContextFactory._obtainBrowser]
|
|
53
|
+
console.log(`[BaseContextFactory._obtainBrowser] --------- OBTAIN BROWSER START (${this.name}) ---------`);
|
|
54
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser promise exists: ${!!this._browserPromise}`);
|
|
67
55
|
if (this._browserPromise) {
|
|
68
|
-
console.log(`[BaseContextFactory._obtainBrowser]
|
|
56
|
+
console.log(`[BaseContextFactory._obtainBrowser] Reusing existing browser promise`);
|
|
57
|
+
console.log(`[BaseContextFactory._obtainBrowser] --------- OBTAIN BROWSER END (${this.name}) ---------`);
|
|
69
58
|
return this._browserPromise;
|
|
70
59
|
}
|
|
71
60
|
testDebug(`obtain browser (${this.name})`);
|
|
72
|
-
console.log(`[BaseContextFactory._obtainBrowser]
|
|
61
|
+
console.log(`[BaseContextFactory._obtainBrowser] No existing promise, calling _doObtainBrowser()...`);
|
|
73
62
|
this._browserPromise = this._doObtainBrowser();
|
|
74
63
|
void this._browserPromise.then((browser) => {
|
|
75
64
|
console.log(`[BaseContextFactory._obtainBrowser] Browser obtained successfully`);
|
|
76
65
|
browser.on("disconnected", () => {
|
|
77
|
-
console.log(`[BaseContextFactory._obtainBrowser] Browser disconnected`);
|
|
66
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser disconnected event fired`);
|
|
78
67
|
this._browserPromise = void 0;
|
|
79
68
|
});
|
|
80
|
-
}).catch((
|
|
81
|
-
console.
|
|
69
|
+
}).catch((error) => {
|
|
70
|
+
console.error(`[BaseContextFactory._obtainBrowser] Browser promise rejected:`, error);
|
|
82
71
|
this._browserPromise = void 0;
|
|
83
72
|
});
|
|
73
|
+
console.log(`[BaseContextFactory._obtainBrowser] --------- OBTAIN BROWSER END (${this.name}) ---------`);
|
|
84
74
|
return this._browserPromise;
|
|
85
75
|
}
|
|
86
76
|
async _doObtainBrowser() {
|
|
87
77
|
throw new Error("Not implemented");
|
|
88
78
|
}
|
|
89
79
|
async createContext() {
|
|
90
|
-
console.log(`[BaseContextFactory.createContext] START (${this.name})
|
|
80
|
+
console.log(`[BaseContextFactory.createContext] --------- CREATE CONTEXT START (${this.name}) ---------`);
|
|
91
81
|
testDebug(`create browser context (${this.name})`);
|
|
92
|
-
console.log(`[BaseContextFactory.createContext] Calling _obtainBrowser...`);
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
82
|
+
console.log(`[BaseContextFactory.createContext] Calling _obtainBrowser()...`);
|
|
83
|
+
const obtainStart = Date.now();
|
|
84
|
+
let browser;
|
|
85
|
+
try {
|
|
86
|
+
browser = await this._obtainBrowser();
|
|
87
|
+
console.log(`[BaseContextFactory.createContext] _obtainBrowser() completed in ${Date.now() - obtainStart}ms`);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error(`[BaseContextFactory.createContext] ERROR: _obtainBrowser() failed after ${Date.now() - obtainStart}ms`);
|
|
90
|
+
console.error(`[BaseContextFactory.createContext] Error:`, error);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
console.log(`[BaseContextFactory.createContext] Calling _doCreateContext()...`);
|
|
94
|
+
const createStart = Date.now();
|
|
95
|
+
let browserContext;
|
|
96
|
+
try {
|
|
97
|
+
browserContext = await this._doCreateContext(browser);
|
|
98
|
+
console.log(`[BaseContextFactory.createContext] _doCreateContext() completed in ${Date.now() - createStart}ms`);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`[BaseContextFactory.createContext] ERROR: _doCreateContext() failed after ${Date.now() - createStart}ms`);
|
|
101
|
+
console.error(`[BaseContextFactory.createContext] Error:`, error);
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
console.log(`[BaseContextFactory.createContext] --------- CREATE CONTEXT END (${this.name}) ---------`);
|
|
99
105
|
return { browserContext, close: () => this._closeBrowserContext(browserContext, browser) };
|
|
100
106
|
}
|
|
101
107
|
async _doCreateContext(browser) {
|
|
102
108
|
throw new Error("Not implemented");
|
|
103
109
|
}
|
|
104
110
|
async _closeBrowserContext(browserContext, browser) {
|
|
105
|
-
console.log(`[BaseContextFactory._closeBrowserContext] START (${this.name})`);
|
|
106
111
|
testDebug(`close browser context (${this.name})`);
|
|
107
112
|
if (browser.contexts().length === 1)
|
|
108
113
|
this._browserPromise = void 0;
|
|
@@ -113,7 +118,6 @@ class BaseContextFactory {
|
|
|
113
118
|
await browser.close().catch(() => {
|
|
114
119
|
});
|
|
115
120
|
}
|
|
116
|
-
console.log(`[BaseContextFactory._closeBrowserContext] END`);
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
class IsolatedContextFactory extends BaseContextFactory {
|
|
@@ -142,106 +146,43 @@ class CdpContextFactory extends BaseContextFactory {
|
|
|
142
146
|
super("cdp", browserConfig);
|
|
143
147
|
}
|
|
144
148
|
async _doObtainBrowser() {
|
|
145
|
-
console.log(
|
|
146
|
-
console.log(
|
|
147
|
-
|
|
148
|
-
const endpoint = this.browserConfig.cdpEndpoint;
|
|
149
|
-
const isCloudfareFetcher = typeof endpoint !== "string";
|
|
150
|
-
console.log("[CdpContextFactory._doObtainBrowser] isCloudfareFetcher:", isCloudfareFetcher);
|
|
149
|
+
console.log(`[CdpContextFactory._doObtainBrowser] --------- CDP OBTAIN BROWSER START ---------`);
|
|
150
|
+
console.log(`[CdpContextFactory._doObtainBrowser] CDP endpoint: ${this.browserConfig.cdpEndpoint}`);
|
|
151
|
+
const connectStart = Date.now();
|
|
151
152
|
try {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"https://cloudflare/",
|
|
159
|
-
"wss://cloudflare"
|
|
160
|
-
];
|
|
161
|
-
let socket = null;
|
|
162
|
-
let successUrl = "";
|
|
163
|
-
for (const url of connectUrls) {
|
|
164
|
-
try {
|
|
165
|
-
console.log(`[CdpContextFactory._doObtainBrowser] Trying fetcher.connect("${url}")...`);
|
|
166
|
-
const connection = await fetcher.connect(url);
|
|
167
|
-
console.log("[CdpContextFactory._doObtainBrowser] connect() returned:", typeof connection);
|
|
168
|
-
console.log("[CdpContextFactory._doObtainBrowser] connection keys:", Object.keys(connection || {}));
|
|
169
|
-
console.log("[CdpContextFactory._doObtainBrowser] connection.socket:", typeof connection?.socket);
|
|
170
|
-
if (connection && typeof connection === "object") {
|
|
171
|
-
if ("accept" in connection && typeof connection.accept === "function") {
|
|
172
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection has accept(), calling it...");
|
|
173
|
-
connection.accept();
|
|
174
|
-
}
|
|
175
|
-
if ("send" in connection && "close" in connection) {
|
|
176
|
-
socket = connection;
|
|
177
|
-
successUrl = url;
|
|
178
|
-
console.log("[CdpContextFactory._doObtainBrowser] Got WebSocket-like object directly");
|
|
179
|
-
break;
|
|
180
|
-
}
|
|
181
|
-
if ("socket" in connection) {
|
|
182
|
-
socket = connection.socket;
|
|
183
|
-
successUrl = url;
|
|
184
|
-
console.log("[CdpContextFactory._doObtainBrowser] Got socket from connection.socket");
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
if ("webSocket" in connection) {
|
|
188
|
-
socket = connection.webSocket;
|
|
189
|
-
if (socket && "accept" in socket) {
|
|
190
|
-
socket.accept();
|
|
191
|
-
}
|
|
192
|
-
successUrl = url;
|
|
193
|
-
console.log("[CdpContextFactory._doObtainBrowser] Got socket from connection.webSocket");
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection structure:", JSON.stringify(Object.getOwnPropertyNames(connection)));
|
|
197
|
-
const proto = Object.getPrototypeOf(connection);
|
|
198
|
-
if (proto) {
|
|
199
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection prototype:", Object.getOwnPropertyNames(proto));
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
} catch (e) {
|
|
203
|
-
console.log(`[CdpContextFactory._doObtainBrowser] connect("${url}") error:`, e.message);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (!socket) {
|
|
207
|
-
throw new Error("Could not establish WebSocket via Fetcher.connect(). Check logs above.");
|
|
208
|
-
}
|
|
209
|
-
console.log(`[CdpContextFactory._doObtainBrowser] WebSocket obtained from ${successUrl}`);
|
|
210
|
-
console.log("[CdpContextFactory._doObtainBrowser] Socket type:", typeof socket);
|
|
211
|
-
console.log("[CdpContextFactory._doObtainBrowser] Socket readyState:", socket.readyState);
|
|
212
|
-
console.log("[CdpContextFactory._doObtainBrowser] Socket methods:", Object.getOwnPropertyNames(Object.getPrototypeOf(socket)));
|
|
213
|
-
console.log("[CdpContextFactory._doObtainBrowser] playwright.chromium methods:", Object.keys(playwright__namespace.chromium));
|
|
214
|
-
if (typeof playwright__namespace.chromium.connectOverCDPWithSocket === "function") {
|
|
215
|
-
console.log("[CdpContextFactory._doObtainBrowser] Using connectOverCDPWithSocket...");
|
|
216
|
-
browser = await playwright__namespace.chromium.connectOverCDPWithSocket(socket);
|
|
217
|
-
} else if (typeof playwright__namespace.chromium.connectWithWebSocket === "function") {
|
|
218
|
-
console.log("[CdpContextFactory._doObtainBrowser] Using connectWithWebSocket...");
|
|
219
|
-
browser = await playwright__namespace.chromium.connectWithWebSocket(socket);
|
|
220
|
-
} else {
|
|
221
|
-
throw new Error(`WebSocket connection established but patchright needs a method to accept raw WebSocket for CDP. Available methods: ${Object.keys(playwright__namespace.chromium).join(", ")}`);
|
|
222
|
-
}
|
|
223
|
-
} else {
|
|
224
|
-
console.log("[CdpContextFactory._doObtainBrowser] Using chromium.connectOverCDP() for CDP URL...");
|
|
225
|
-
browser = await playwright__namespace.chromium.connectOverCDP(endpoint);
|
|
226
|
-
}
|
|
227
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection completed");
|
|
153
|
+
const browser = await playwright__namespace.chromium.connectOverCDP(this.browserConfig.cdpEndpoint);
|
|
154
|
+
console.log(`[CdpContextFactory._doObtainBrowser] connectOverCDP() completed in ${Date.now() - connectStart}ms`);
|
|
155
|
+
console.log(`[CdpContextFactory._doObtainBrowser] Browser connected: ${browser.isConnected()}`);
|
|
156
|
+
console.log(`[CdpContextFactory._doObtainBrowser] Browser version: ${browser.version()}`);
|
|
157
|
+
console.log(`[CdpContextFactory._doObtainBrowser] Existing contexts: ${browser.contexts().length}`);
|
|
158
|
+
console.log(`[CdpContextFactory._doObtainBrowser] --------- CDP OBTAIN BROWSER END ---------`);
|
|
228
159
|
return browser;
|
|
229
|
-
} catch (
|
|
230
|
-
console.
|
|
231
|
-
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(`[CdpContextFactory._doObtainBrowser] ERROR: connectOverCDP() failed after ${Date.now() - connectStart}ms`);
|
|
162
|
+
console.error(`[CdpContextFactory._doObtainBrowser] Error type: ${error.constructor.name}`);
|
|
163
|
+
console.error(`[CdpContextFactory._doObtainBrowser] Error message: ${error.message}`);
|
|
164
|
+
console.error(`[CdpContextFactory._doObtainBrowser] Error stack:`, error.stack);
|
|
165
|
+
throw error;
|
|
232
166
|
}
|
|
233
167
|
}
|
|
234
168
|
async _doCreateContext(browser) {
|
|
235
|
-
console.log(
|
|
236
|
-
console.log(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
169
|
+
console.log(`[CdpContextFactory._doCreateContext] --------- CDP CREATE CONTEXT START ---------`);
|
|
170
|
+
console.log(`[CdpContextFactory._doCreateContext] Isolated mode: ${this.browserConfig.isolated}`);
|
|
171
|
+
console.log(`[CdpContextFactory._doCreateContext] Existing contexts: ${browser.contexts().length}`);
|
|
172
|
+
let context;
|
|
173
|
+
if (this.browserConfig.isolated) {
|
|
174
|
+
console.log(`[CdpContextFactory._doCreateContext] Creating new isolated context...`);
|
|
175
|
+
const newContextStart = Date.now();
|
|
176
|
+
context = await browser.newContext();
|
|
177
|
+
console.log(`[CdpContextFactory._doCreateContext] New context created in ${Date.now() - newContextStart}ms`);
|
|
178
|
+
} else {
|
|
179
|
+
console.log(`[CdpContextFactory._doCreateContext] Using existing context[0]...`);
|
|
180
|
+
context = browser.contexts()[0];
|
|
181
|
+
console.log(`[CdpContextFactory._doCreateContext] Existing context obtained`);
|
|
244
182
|
}
|
|
183
|
+
console.log(`[CdpContextFactory._doCreateContext] Context pages: ${context.pages().length}`);
|
|
184
|
+
console.log(`[CdpContextFactory._doCreateContext] --------- CDP CREATE CONTEXT END ---------`);
|
|
185
|
+
return context;
|
|
245
186
|
}
|
|
246
187
|
}
|
|
247
188
|
class RemoteContextFactory extends BaseContextFactory {
|
package/lib/cjs/src/context.js
CHANGED
|
@@ -70,29 +70,42 @@ class Context {
|
|
|
70
70
|
await this._currentTab.page.bringToFront();
|
|
71
71
|
}
|
|
72
72
|
async ensureTab() {
|
|
73
|
-
console.log(
|
|
74
|
-
console.log(
|
|
75
|
-
console.log(
|
|
73
|
+
console.log(`[Context.ensureTab] --------- ENSURE TAB START ---------`);
|
|
74
|
+
console.log(`[Context.ensureTab] Current tab exists: ${!!this._currentTab}`);
|
|
75
|
+
console.log(`[Context.ensureTab] Number of tabs: ${this._tabs.length}`);
|
|
76
|
+
console.log(`[Context.ensureTab] Browser context promise exists: ${!!this._browserContextPromise}`);
|
|
77
|
+
console.log(`[Context.ensureTab] Calling _ensureBrowserContext()...`);
|
|
78
|
+
const ensureContextStart = Date.now();
|
|
76
79
|
let browserContext;
|
|
77
80
|
try {
|
|
78
81
|
const result = await this._ensureBrowserContext();
|
|
79
82
|
browserContext = result.browserContext;
|
|
80
|
-
console.log(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
console.log(`[Context.ensureTab] _ensureBrowserContext() completed in ${Date.now() - ensureContextStart}ms`);
|
|
84
|
+
console.log(`[Context.ensureTab] Browser context obtained: ${!!browserContext}`);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(`[Context.ensureTab] ERROR: _ensureBrowserContext() failed after ${Date.now() - ensureContextStart}ms`);
|
|
87
|
+
console.error(`[Context.ensureTab] Error type: ${error.constructor.name}`);
|
|
88
|
+
console.error(`[Context.ensureTab] Error message: ${error.message}`);
|
|
89
|
+
console.error(`[Context.ensureTab] Error stack:`, error.stack);
|
|
90
|
+
throw error;
|
|
84
91
|
}
|
|
85
92
|
if (!this._currentTab) {
|
|
86
|
-
console.log(
|
|
93
|
+
console.log(`[Context.ensureTab] No current tab, creating new page...`);
|
|
94
|
+
const newPageStart = Date.now();
|
|
87
95
|
try {
|
|
88
96
|
await browserContext.newPage();
|
|
89
|
-
console.log(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
console.log(`[Context.ensureTab] New page created in ${Date.now() - newPageStart}ms`);
|
|
98
|
+
console.log(`[Context.ensureTab] Current tab after newPage: ${!!this._currentTab}`);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error(`[Context.ensureTab] ERROR: newPage() failed after ${Date.now() - newPageStart}ms`);
|
|
101
|
+
console.error(`[Context.ensureTab] Error:`, error);
|
|
102
|
+
throw error;
|
|
93
103
|
}
|
|
104
|
+
} else {
|
|
105
|
+
console.log(`[Context.ensureTab] Current tab already exists, skipping newPage()`);
|
|
94
106
|
}
|
|
95
|
-
console.log(
|
|
107
|
+
console.log(`[Context.ensureTab] Returning tab. URL: ${this._currentTab?.page.url() ?? "N/A"}`);
|
|
108
|
+
console.log(`[Context.ensureTab] --------- ENSURE TAB END ---------`);
|
|
96
109
|
return this._currentTab;
|
|
97
110
|
}
|
|
98
111
|
async listTabsMarkdown() {
|
|
@@ -269,51 +282,68 @@ ${code.join("\n")}
|
|
|
269
282
|
}
|
|
270
283
|
}
|
|
271
284
|
_ensureBrowserContext() {
|
|
272
|
-
console.log(
|
|
273
|
-
console.log(
|
|
285
|
+
console.log(`[Context._ensureBrowserContext] --------- ENSURE BROWSER CONTEXT START ---------`);
|
|
286
|
+
console.log(`[Context._ensureBrowserContext] Browser context promise exists: ${!!this._browserContextPromise}`);
|
|
274
287
|
if (!this._browserContextPromise) {
|
|
275
|
-
console.log(
|
|
288
|
+
console.log(`[Context._ensureBrowserContext] No existing promise, calling _setupBrowserContext()...`);
|
|
276
289
|
this._browserContextPromise = this._setupBrowserContext();
|
|
277
|
-
this._browserContextPromise.catch((
|
|
278
|
-
console.
|
|
290
|
+
this._browserContextPromise.catch((error) => {
|
|
291
|
+
console.error(`[Context._ensureBrowserContext] _setupBrowserContext() promise rejected:`, error);
|
|
279
292
|
this._browserContextPromise = void 0;
|
|
280
293
|
});
|
|
294
|
+
} else {
|
|
295
|
+
console.log(`[Context._ensureBrowserContext] Reusing existing browser context promise`);
|
|
281
296
|
}
|
|
282
|
-
console.log(
|
|
297
|
+
console.log(`[Context._ensureBrowserContext] --------- ENSURE BROWSER CONTEXT END ---------`);
|
|
283
298
|
return this._browserContextPromise;
|
|
284
299
|
}
|
|
285
300
|
async _setupBrowserContext() {
|
|
286
|
-
console.log(
|
|
287
|
-
console.log(
|
|
301
|
+
console.log(`[Context._setupBrowserContext] --------- SETUP BROWSER CONTEXT START ---------`);
|
|
302
|
+
console.log(`[Context._setupBrowserContext] Calling browserContextFactory.createContext()...`);
|
|
303
|
+
const createContextStart = Date.now();
|
|
288
304
|
let result;
|
|
289
305
|
try {
|
|
290
306
|
result = await this._browserContextFactory.createContext();
|
|
291
|
-
console.log(
|
|
292
|
-
} catch (
|
|
293
|
-
console.
|
|
294
|
-
|
|
307
|
+
console.log(`[Context._setupBrowserContext] createContext() completed in ${Date.now() - createContextStart}ms`);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error(`[Context._setupBrowserContext] ERROR: createContext() failed after ${Date.now() - createContextStart}ms`);
|
|
310
|
+
console.error(`[Context._setupBrowserContext] Error type: ${error.constructor.name}`);
|
|
311
|
+
console.error(`[Context._setupBrowserContext] Error message: ${error.message}`);
|
|
312
|
+
console.error(`[Context._setupBrowserContext] Error stack:`, error.stack);
|
|
313
|
+
throw error;
|
|
295
314
|
}
|
|
296
315
|
const { browserContext } = result;
|
|
297
|
-
console.log(
|
|
298
|
-
console.log(
|
|
316
|
+
console.log(`[Context._setupBrowserContext] Browser context obtained`);
|
|
317
|
+
console.log(`[Context._setupBrowserContext] Setting up request interception...`);
|
|
318
|
+
const interceptStart = Date.now();
|
|
299
319
|
await this._setupRequestInterception(browserContext);
|
|
300
|
-
console.log(
|
|
301
|
-
console.log(
|
|
302
|
-
|
|
320
|
+
console.log(`[Context._setupBrowserContext] Request interception setup completed in ${Date.now() - interceptStart}ms`);
|
|
321
|
+
console.log(`[Context._setupBrowserContext] Processing existing pages...`);
|
|
322
|
+
const existingPages = browserContext.pages();
|
|
323
|
+
console.log(`[Context._setupBrowserContext] Found ${existingPages.length} existing pages`);
|
|
324
|
+
for (const page of existingPages) {
|
|
325
|
+
console.log(`[Context._setupBrowserContext] Processing existing page: ${page.url()}`);
|
|
303
326
|
this._onPageCreated(page);
|
|
304
|
-
|
|
305
|
-
console.log(
|
|
327
|
+
}
|
|
328
|
+
console.log(`[Context._setupBrowserContext] Setting up 'page' event listener...`);
|
|
329
|
+
browserContext.on("page", (page) => {
|
|
330
|
+
console.log(`[Context._setupBrowserContext] 'page' event fired for: ${page.url()}`);
|
|
331
|
+
this._onPageCreated(page);
|
|
332
|
+
});
|
|
306
333
|
if (this.config.saveTrace) {
|
|
307
|
-
console.log(
|
|
334
|
+
console.log(`[Context._setupBrowserContext] Starting tracing...`);
|
|
335
|
+
const traceStart = Date.now();
|
|
308
336
|
await browserContext.tracing.start({
|
|
309
337
|
name: "trace",
|
|
310
338
|
screenshots: false,
|
|
311
339
|
snapshots: true,
|
|
312
340
|
sources: false
|
|
313
341
|
});
|
|
314
|
-
console.log(
|
|
342
|
+
console.log(`[Context._setupBrowserContext] Tracing started in ${Date.now() - traceStart}ms`);
|
|
315
343
|
}
|
|
316
|
-
console.log(
|
|
344
|
+
console.log(`[Context._setupBrowserContext] Total tabs after setup: ${this._tabs.length}`);
|
|
345
|
+
console.log(`[Context._setupBrowserContext] Current tab: ${this._currentTab ? "set" : "not set"}`);
|
|
346
|
+
console.log(`[Context._setupBrowserContext] --------- SETUP BROWSER CONTEXT END ---------`);
|
|
317
347
|
return result;
|
|
318
348
|
}
|
|
319
349
|
}
|
package/lib/cjs/src/tab.js
CHANGED
|
@@ -50,40 +50,66 @@ class Tab {
|
|
|
50
50
|
}));
|
|
51
51
|
}
|
|
52
52
|
async navigate(url) {
|
|
53
|
-
|
|
54
|
-
console.log(
|
|
53
|
+
const navStartTime = Date.now();
|
|
54
|
+
console.log(`[Tab.navigate] --------- TAB NAVIGATION START ---------`);
|
|
55
|
+
console.log(`[Tab.navigate] URL: ${url}`);
|
|
56
|
+
console.log(`[Tab.navigate] Current page URL: ${this.page.url()}`);
|
|
57
|
+
console.log(`[Tab.navigate] Page is closed: ${this.page.isClosed()}`);
|
|
58
|
+
console.log(`[Tab.navigate] Clearing collected artifacts...`);
|
|
55
59
|
this._clearCollectedArtifacts();
|
|
56
|
-
console.log(
|
|
57
|
-
console.log(
|
|
60
|
+
console.log(`[Tab.navigate] Artifacts cleared. Console messages: ${this._consoleMessages.length}, Requests: ${this._requests.size}`);
|
|
61
|
+
console.log(`[Tab.navigate] Setting up download event listener...`);
|
|
58
62
|
const downloadEvent = utils.callOnPageNoTrace(this.page, (page) => page.waitForEvent("download").catch(() => {
|
|
59
63
|
}));
|
|
60
|
-
console.log(
|
|
64
|
+
console.log(`[Tab.navigate] Download event listener set up`);
|
|
65
|
+
console.log(`[Tab.navigate] Calling page.goto() with waitUntil: 'domcontentloaded'`);
|
|
66
|
+
const gotoStartTime = Date.now();
|
|
61
67
|
try {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.log(
|
|
68
|
+
const response = await this.page.goto(url, { waitUntil: "domcontentloaded" });
|
|
69
|
+
const gotoTime = Date.now() - gotoStartTime;
|
|
70
|
+
console.log(`[Tab.navigate] page.goto() completed in ${gotoTime}ms`);
|
|
71
|
+
if (response) {
|
|
72
|
+
console.log(`[Tab.navigate] Response status: ${response.status()}`);
|
|
73
|
+
console.log(`[Tab.navigate] Response URL: ${response.url()}`);
|
|
74
|
+
console.log(`[Tab.navigate] Response headers:`, JSON.stringify(response.headers(), null, 2));
|
|
75
|
+
} else {
|
|
76
|
+
console.log(`[Tab.navigate] Response is null (might be same-document navigation or cached)`);
|
|
77
|
+
}
|
|
65
78
|
} catch (_e) {
|
|
66
79
|
const e = _e;
|
|
67
|
-
|
|
80
|
+
const gotoTime = Date.now() - gotoStartTime;
|
|
81
|
+
console.log(`[Tab.navigate] page.goto() threw after ${gotoTime}ms`);
|
|
82
|
+
console.log(`[Tab.navigate] Error name: ${e.name}`);
|
|
83
|
+
console.log(`[Tab.navigate] Error message: ${e.message}`);
|
|
68
84
|
const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
|
|
85
|
+
console.log(`[Tab.navigate] Might be download: ${mightBeDownload}`);
|
|
69
86
|
if (!mightBeDownload) {
|
|
70
|
-
console.
|
|
87
|
+
console.error(`[Tab.navigate] ERROR: Not a download, rethrowing error`);
|
|
88
|
+
console.error(`[Tab.navigate] Error stack:`, e.stack);
|
|
71
89
|
throw e;
|
|
72
90
|
}
|
|
73
|
-
console.log(
|
|
91
|
+
console.log(`[Tab.navigate] Waiting for potential download event (up to 1000ms)...`);
|
|
92
|
+
const downloadWaitStart = Date.now();
|
|
74
93
|
const download = await Promise.race([
|
|
75
94
|
downloadEvent,
|
|
76
95
|
new Promise((resolve) => setTimeout(resolve, 1e3))
|
|
77
96
|
]);
|
|
97
|
+
console.log(`[Tab.navigate] Download wait completed in ${Date.now() - downloadWaitStart}ms`);
|
|
98
|
+
console.log(`[Tab.navigate] Download detected: ${!!download}`);
|
|
78
99
|
if (!download) {
|
|
79
|
-
console.
|
|
100
|
+
console.error(`[Tab.navigate] ERROR: No download detected, rethrowing original error`);
|
|
80
101
|
throw e;
|
|
81
102
|
}
|
|
82
|
-
console.log(
|
|
103
|
+
console.log(`[Tab.navigate] Download detected, continuing without error`);
|
|
83
104
|
}
|
|
84
|
-
console.log(
|
|
105
|
+
console.log(`[Tab.navigate] Waiting for 'load' state (timeout: 5000ms)...`);
|
|
106
|
+
const loadWaitStart = Date.now();
|
|
85
107
|
await this.waitForLoadState("load", { timeout: 5e3 });
|
|
86
|
-
console.log(
|
|
108
|
+
console.log(`[Tab.navigate] 'load' state wait completed in ${Date.now() - loadWaitStart}ms`);
|
|
109
|
+
console.log(`[Tab.navigate] Final page URL: ${this.page.url()}`);
|
|
110
|
+
console.log(`[Tab.navigate] Final page title: ${await this.page.title().catch(() => "N/A")}`);
|
|
111
|
+
console.log(`[Tab.navigate] Total navigation time: ${Date.now() - navStartTime}ms`);
|
|
112
|
+
console.log(`[Tab.navigate] --------- TAB NAVIGATION END ---------`);
|
|
87
113
|
}
|
|
88
114
|
hasSnapshot() {
|
|
89
115
|
return !!this._snapshot;
|
|
@@ -5,9 +5,6 @@ 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
|
-
};
|
|
11
8
|
const navigate = (captureSnapshot) => tool.defineTool({
|
|
12
9
|
capability: "core",
|
|
13
10
|
schema: {
|
|
@@ -20,39 +17,49 @@ const navigate = (captureSnapshot) => tool.defineTool({
|
|
|
20
17
|
type: "destructive"
|
|
21
18
|
},
|
|
22
19
|
handle: async (context, params) => {
|
|
23
|
-
|
|
24
|
-
log(
|
|
25
|
-
log(
|
|
26
|
-
log(
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
console.log(`[browser_navigate] ========== NAVIGATION START ==========`);
|
|
22
|
+
console.log(`[browser_navigate] Target URL: ${params.url}`);
|
|
23
|
+
console.log(`[browser_navigate] Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
24
|
+
console.log(`[browser_navigate] captureSnapshot setting: ${captureSnapshot}`);
|
|
25
|
+
console.log(`[browser_navigate] Ensuring tab is available...`);
|
|
26
|
+
const ensureTabStart = Date.now();
|
|
27
27
|
let tab;
|
|
28
28
|
try {
|
|
29
29
|
tab = await context.ensureTab();
|
|
30
|
-
log(
|
|
31
|
-
log(
|
|
32
|
-
} catch (
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
console.log(`[browser_navigate] Tab ensured successfully in ${Date.now() - ensureTabStart}ms`);
|
|
31
|
+
console.log(`[browser_navigate] Current page URL before navigation: ${tab.page.url()}`);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(`[browser_navigate] ERROR: Failed to ensure tab after ${Date.now() - ensureTabStart}ms`);
|
|
34
|
+
console.error(`[browser_navigate] Error details:`, error);
|
|
35
|
+
throw error;
|
|
35
36
|
}
|
|
36
|
-
log(`
|
|
37
|
+
console.log(`[browser_navigate] Starting navigation to: ${params.url}`);
|
|
38
|
+
const navigationStart = Date.now();
|
|
37
39
|
try {
|
|
38
40
|
await tab.navigate(params.url);
|
|
39
|
-
log(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
console.log(`[browser_navigate] Navigation completed successfully in ${Date.now() - navigationStart}ms`);
|
|
42
|
+
console.log(`[browser_navigate] Current page URL after navigation: ${tab.page.url()}`);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(`[browser_navigate] ERROR: Navigation failed after ${Date.now() - navigationStart}ms`);
|
|
45
|
+
console.error(`[browser_navigate] Error type: ${error.constructor.name}`);
|
|
46
|
+
console.error(`[browser_navigate] Error message: ${error.message}`);
|
|
47
|
+
console.error(`[browser_navigate] Error stack:`, error.stack);
|
|
48
|
+
throw error;
|
|
43
49
|
}
|
|
44
50
|
const code = [
|
|
45
51
|
`// Navigate to ${params.url}`,
|
|
46
52
|
`await page.goto('${params.url}');`
|
|
47
53
|
];
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
const totalTime = Date.now() - startTime;
|
|
55
|
+
console.log(`[browser_navigate] Total execution time: ${totalTime}ms`);
|
|
56
|
+
console.log(`[browser_navigate] Returning with captureSnapshot: ${captureSnapshot}, waitForNetwork: false`);
|
|
57
|
+
console.log(`[browser_navigate] ========== NAVIGATION END ==========`);
|
|
58
|
+
return {
|
|
50
59
|
code,
|
|
51
60
|
captureSnapshot,
|
|
52
61
|
waitForNetwork: false
|
|
53
62
|
};
|
|
54
|
-
log("=== NAVIGATE HANDLER END ===");
|
|
55
|
-
return result;
|
|
56
63
|
}
|
|
57
64
|
});
|
|
58
65
|
const goBack = (captureSnapshot) => tool.defineTool({
|
|
@@ -8,25 +8,14 @@ import { userDataDir } from './fileUtils.js';
|
|
|
8
8
|
|
|
9
9
|
const testDebug = createDebug("pw:mcp:test");
|
|
10
10
|
function contextFactory(browserConfig) {
|
|
11
|
-
|
|
12
|
-
console.log("[contextFactory] browserConfig:", JSON.stringify(browserConfig, null, 2));
|
|
13
|
-
if (browserConfig.remoteEndpoint) {
|
|
14
|
-
console.log("[contextFactory] Using RemoteContextFactory");
|
|
11
|
+
if (browserConfig.remoteEndpoint)
|
|
15
12
|
return new RemoteContextFactory(browserConfig);
|
|
16
|
-
|
|
17
|
-
if (browserConfig.cdpEndpoint) {
|
|
18
|
-
console.log("[contextFactory] Using CdpContextFactory");
|
|
13
|
+
if (browserConfig.cdpEndpoint)
|
|
19
14
|
return new CdpContextFactory(browserConfig);
|
|
20
|
-
|
|
21
|
-
if (browserConfig.isolated) {
|
|
22
|
-
console.log("[contextFactory] Using IsolatedContextFactory");
|
|
15
|
+
if (browserConfig.isolated)
|
|
23
16
|
return new IsolatedContextFactory(browserConfig);
|
|
24
|
-
|
|
25
|
-
if (browserConfig.browserAgent) {
|
|
26
|
-
console.log("[contextFactory] Using BrowserServerContextFactory");
|
|
17
|
+
if (browserConfig.browserAgent)
|
|
27
18
|
return new BrowserServerContextFactory(browserConfig);
|
|
28
|
-
}
|
|
29
|
-
console.log("[contextFactory] Using PersistentContextFactory");
|
|
30
19
|
return new PersistentContextFactory(browserConfig);
|
|
31
20
|
}
|
|
32
21
|
class BaseContextFactory {
|
|
@@ -36,50 +25,66 @@ class BaseContextFactory {
|
|
|
36
25
|
constructor(name, browserConfig) {
|
|
37
26
|
this.name = name;
|
|
38
27
|
this.browserConfig = browserConfig;
|
|
39
|
-
console.log(`[BaseContextFactory] Created factory: ${name}`);
|
|
40
28
|
}
|
|
41
29
|
async _obtainBrowser() {
|
|
42
|
-
console.log(`[BaseContextFactory._obtainBrowser] START (${this.name})
|
|
43
|
-
console.log(`[BaseContextFactory._obtainBrowser]
|
|
30
|
+
console.log(`[BaseContextFactory._obtainBrowser] --------- OBTAIN BROWSER START (${this.name}) ---------`);
|
|
31
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser promise exists: ${!!this._browserPromise}`);
|
|
44
32
|
if (this._browserPromise) {
|
|
45
|
-
console.log(`[BaseContextFactory._obtainBrowser]
|
|
33
|
+
console.log(`[BaseContextFactory._obtainBrowser] Reusing existing browser promise`);
|
|
34
|
+
console.log(`[BaseContextFactory._obtainBrowser] --------- OBTAIN BROWSER END (${this.name}) ---------`);
|
|
46
35
|
return this._browserPromise;
|
|
47
36
|
}
|
|
48
37
|
testDebug(`obtain browser (${this.name})`);
|
|
49
|
-
console.log(`[BaseContextFactory._obtainBrowser]
|
|
38
|
+
console.log(`[BaseContextFactory._obtainBrowser] No existing promise, calling _doObtainBrowser()...`);
|
|
50
39
|
this._browserPromise = this._doObtainBrowser();
|
|
51
40
|
void this._browserPromise.then((browser) => {
|
|
52
41
|
console.log(`[BaseContextFactory._obtainBrowser] Browser obtained successfully`);
|
|
53
42
|
browser.on("disconnected", () => {
|
|
54
|
-
console.log(`[BaseContextFactory._obtainBrowser] Browser disconnected`);
|
|
43
|
+
console.log(`[BaseContextFactory._obtainBrowser] Browser disconnected event fired`);
|
|
55
44
|
this._browserPromise = void 0;
|
|
56
45
|
});
|
|
57
|
-
}).catch((
|
|
58
|
-
console.
|
|
46
|
+
}).catch((error) => {
|
|
47
|
+
console.error(`[BaseContextFactory._obtainBrowser] Browser promise rejected:`, error);
|
|
59
48
|
this._browserPromise = void 0;
|
|
60
49
|
});
|
|
50
|
+
console.log(`[BaseContextFactory._obtainBrowser] --------- OBTAIN BROWSER END (${this.name}) ---------`);
|
|
61
51
|
return this._browserPromise;
|
|
62
52
|
}
|
|
63
53
|
async _doObtainBrowser() {
|
|
64
54
|
throw new Error("Not implemented");
|
|
65
55
|
}
|
|
66
56
|
async createContext() {
|
|
67
|
-
console.log(`[BaseContextFactory.createContext] START (${this.name})
|
|
57
|
+
console.log(`[BaseContextFactory.createContext] --------- CREATE CONTEXT START (${this.name}) ---------`);
|
|
68
58
|
testDebug(`create browser context (${this.name})`);
|
|
69
|
-
console.log(`[BaseContextFactory.createContext] Calling _obtainBrowser...`);
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
59
|
+
console.log(`[BaseContextFactory.createContext] Calling _obtainBrowser()...`);
|
|
60
|
+
const obtainStart = Date.now();
|
|
61
|
+
let browser;
|
|
62
|
+
try {
|
|
63
|
+
browser = await this._obtainBrowser();
|
|
64
|
+
console.log(`[BaseContextFactory.createContext] _obtainBrowser() completed in ${Date.now() - obtainStart}ms`);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(`[BaseContextFactory.createContext] ERROR: _obtainBrowser() failed after ${Date.now() - obtainStart}ms`);
|
|
67
|
+
console.error(`[BaseContextFactory.createContext] Error:`, error);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
console.log(`[BaseContextFactory.createContext] Calling _doCreateContext()...`);
|
|
71
|
+
const createStart = Date.now();
|
|
72
|
+
let browserContext;
|
|
73
|
+
try {
|
|
74
|
+
browserContext = await this._doCreateContext(browser);
|
|
75
|
+
console.log(`[BaseContextFactory.createContext] _doCreateContext() completed in ${Date.now() - createStart}ms`);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(`[BaseContextFactory.createContext] ERROR: _doCreateContext() failed after ${Date.now() - createStart}ms`);
|
|
78
|
+
console.error(`[BaseContextFactory.createContext] Error:`, error);
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
console.log(`[BaseContextFactory.createContext] --------- CREATE CONTEXT END (${this.name}) ---------`);
|
|
76
82
|
return { browserContext, close: () => this._closeBrowserContext(browserContext, browser) };
|
|
77
83
|
}
|
|
78
84
|
async _doCreateContext(browser) {
|
|
79
85
|
throw new Error("Not implemented");
|
|
80
86
|
}
|
|
81
87
|
async _closeBrowserContext(browserContext, browser) {
|
|
82
|
-
console.log(`[BaseContextFactory._closeBrowserContext] START (${this.name})`);
|
|
83
88
|
testDebug(`close browser context (${this.name})`);
|
|
84
89
|
if (browser.contexts().length === 1)
|
|
85
90
|
this._browserPromise = void 0;
|
|
@@ -90,7 +95,6 @@ class BaseContextFactory {
|
|
|
90
95
|
await browser.close().catch(() => {
|
|
91
96
|
});
|
|
92
97
|
}
|
|
93
|
-
console.log(`[BaseContextFactory._closeBrowserContext] END`);
|
|
94
98
|
}
|
|
95
99
|
}
|
|
96
100
|
class IsolatedContextFactory extends BaseContextFactory {
|
|
@@ -119,106 +123,43 @@ class CdpContextFactory extends BaseContextFactory {
|
|
|
119
123
|
super("cdp", browserConfig);
|
|
120
124
|
}
|
|
121
125
|
async _doObtainBrowser() {
|
|
122
|
-
console.log(
|
|
123
|
-
console.log(
|
|
124
|
-
|
|
125
|
-
const endpoint = this.browserConfig.cdpEndpoint;
|
|
126
|
-
const isCloudfareFetcher = typeof endpoint !== "string";
|
|
127
|
-
console.log("[CdpContextFactory._doObtainBrowser] isCloudfareFetcher:", isCloudfareFetcher);
|
|
126
|
+
console.log(`[CdpContextFactory._doObtainBrowser] --------- CDP OBTAIN BROWSER START ---------`);
|
|
127
|
+
console.log(`[CdpContextFactory._doObtainBrowser] CDP endpoint: ${this.browserConfig.cdpEndpoint}`);
|
|
128
|
+
const connectStart = Date.now();
|
|
128
129
|
try {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
"https://cloudflare/",
|
|
136
|
-
"wss://cloudflare"
|
|
137
|
-
];
|
|
138
|
-
let socket = null;
|
|
139
|
-
let successUrl = "";
|
|
140
|
-
for (const url of connectUrls) {
|
|
141
|
-
try {
|
|
142
|
-
console.log(`[CdpContextFactory._doObtainBrowser] Trying fetcher.connect("${url}")...`);
|
|
143
|
-
const connection = await fetcher.connect(url);
|
|
144
|
-
console.log("[CdpContextFactory._doObtainBrowser] connect() returned:", typeof connection);
|
|
145
|
-
console.log("[CdpContextFactory._doObtainBrowser] connection keys:", Object.keys(connection || {}));
|
|
146
|
-
console.log("[CdpContextFactory._doObtainBrowser] connection.socket:", typeof connection?.socket);
|
|
147
|
-
if (connection && typeof connection === "object") {
|
|
148
|
-
if ("accept" in connection && typeof connection.accept === "function") {
|
|
149
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection has accept(), calling it...");
|
|
150
|
-
connection.accept();
|
|
151
|
-
}
|
|
152
|
-
if ("send" in connection && "close" in connection) {
|
|
153
|
-
socket = connection;
|
|
154
|
-
successUrl = url;
|
|
155
|
-
console.log("[CdpContextFactory._doObtainBrowser] Got WebSocket-like object directly");
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
if ("socket" in connection) {
|
|
159
|
-
socket = connection.socket;
|
|
160
|
-
successUrl = url;
|
|
161
|
-
console.log("[CdpContextFactory._doObtainBrowser] Got socket from connection.socket");
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
if ("webSocket" in connection) {
|
|
165
|
-
socket = connection.webSocket;
|
|
166
|
-
if (socket && "accept" in socket) {
|
|
167
|
-
socket.accept();
|
|
168
|
-
}
|
|
169
|
-
successUrl = url;
|
|
170
|
-
console.log("[CdpContextFactory._doObtainBrowser] Got socket from connection.webSocket");
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection structure:", JSON.stringify(Object.getOwnPropertyNames(connection)));
|
|
174
|
-
const proto = Object.getPrototypeOf(connection);
|
|
175
|
-
if (proto) {
|
|
176
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection prototype:", Object.getOwnPropertyNames(proto));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
} catch (e) {
|
|
180
|
-
console.log(`[CdpContextFactory._doObtainBrowser] connect("${url}") error:`, e.message);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (!socket) {
|
|
184
|
-
throw new Error("Could not establish WebSocket via Fetcher.connect(). Check logs above.");
|
|
185
|
-
}
|
|
186
|
-
console.log(`[CdpContextFactory._doObtainBrowser] WebSocket obtained from ${successUrl}`);
|
|
187
|
-
console.log("[CdpContextFactory._doObtainBrowser] Socket type:", typeof socket);
|
|
188
|
-
console.log("[CdpContextFactory._doObtainBrowser] Socket readyState:", socket.readyState);
|
|
189
|
-
console.log("[CdpContextFactory._doObtainBrowser] Socket methods:", Object.getOwnPropertyNames(Object.getPrototypeOf(socket)));
|
|
190
|
-
console.log("[CdpContextFactory._doObtainBrowser] playwright.chromium methods:", Object.keys(playwright.chromium));
|
|
191
|
-
if (typeof playwright.chromium.connectOverCDPWithSocket === "function") {
|
|
192
|
-
console.log("[CdpContextFactory._doObtainBrowser] Using connectOverCDPWithSocket...");
|
|
193
|
-
browser = await playwright.chromium.connectOverCDPWithSocket(socket);
|
|
194
|
-
} else if (typeof playwright.chromium.connectWithWebSocket === "function") {
|
|
195
|
-
console.log("[CdpContextFactory._doObtainBrowser] Using connectWithWebSocket...");
|
|
196
|
-
browser = await playwright.chromium.connectWithWebSocket(socket);
|
|
197
|
-
} else {
|
|
198
|
-
throw new Error(`WebSocket connection established but patchright needs a method to accept raw WebSocket for CDP. Available methods: ${Object.keys(playwright.chromium).join(", ")}`);
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
console.log("[CdpContextFactory._doObtainBrowser] Using chromium.connectOverCDP() for CDP URL...");
|
|
202
|
-
browser = await playwright.chromium.connectOverCDP(endpoint);
|
|
203
|
-
}
|
|
204
|
-
console.log("[CdpContextFactory._doObtainBrowser] Connection completed");
|
|
130
|
+
const browser = await playwright.chromium.connectOverCDP(this.browserConfig.cdpEndpoint);
|
|
131
|
+
console.log(`[CdpContextFactory._doObtainBrowser] connectOverCDP() completed in ${Date.now() - connectStart}ms`);
|
|
132
|
+
console.log(`[CdpContextFactory._doObtainBrowser] Browser connected: ${browser.isConnected()}`);
|
|
133
|
+
console.log(`[CdpContextFactory._doObtainBrowser] Browser version: ${browser.version()}`);
|
|
134
|
+
console.log(`[CdpContextFactory._doObtainBrowser] Existing contexts: ${browser.contexts().length}`);
|
|
135
|
+
console.log(`[CdpContextFactory._doObtainBrowser] --------- CDP OBTAIN BROWSER END ---------`);
|
|
205
136
|
return browser;
|
|
206
|
-
} catch (
|
|
207
|
-
console.
|
|
208
|
-
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error(`[CdpContextFactory._doObtainBrowser] ERROR: connectOverCDP() failed after ${Date.now() - connectStart}ms`);
|
|
139
|
+
console.error(`[CdpContextFactory._doObtainBrowser] Error type: ${error.constructor.name}`);
|
|
140
|
+
console.error(`[CdpContextFactory._doObtainBrowser] Error message: ${error.message}`);
|
|
141
|
+
console.error(`[CdpContextFactory._doObtainBrowser] Error stack:`, error.stack);
|
|
142
|
+
throw error;
|
|
209
143
|
}
|
|
210
144
|
}
|
|
211
145
|
async _doCreateContext(browser) {
|
|
212
|
-
console.log(
|
|
213
|
-
console.log(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
146
|
+
console.log(`[CdpContextFactory._doCreateContext] --------- CDP CREATE CONTEXT START ---------`);
|
|
147
|
+
console.log(`[CdpContextFactory._doCreateContext] Isolated mode: ${this.browserConfig.isolated}`);
|
|
148
|
+
console.log(`[CdpContextFactory._doCreateContext] Existing contexts: ${browser.contexts().length}`);
|
|
149
|
+
let context;
|
|
150
|
+
if (this.browserConfig.isolated) {
|
|
151
|
+
console.log(`[CdpContextFactory._doCreateContext] Creating new isolated context...`);
|
|
152
|
+
const newContextStart = Date.now();
|
|
153
|
+
context = await browser.newContext();
|
|
154
|
+
console.log(`[CdpContextFactory._doCreateContext] New context created in ${Date.now() - newContextStart}ms`);
|
|
155
|
+
} else {
|
|
156
|
+
console.log(`[CdpContextFactory._doCreateContext] Using existing context[0]...`);
|
|
157
|
+
context = browser.contexts()[0];
|
|
158
|
+
console.log(`[CdpContextFactory._doCreateContext] Existing context obtained`);
|
|
221
159
|
}
|
|
160
|
+
console.log(`[CdpContextFactory._doCreateContext] Context pages: ${context.pages().length}`);
|
|
161
|
+
console.log(`[CdpContextFactory._doCreateContext] --------- CDP CREATE CONTEXT END ---------`);
|
|
162
|
+
return context;
|
|
222
163
|
}
|
|
223
164
|
}
|
|
224
165
|
class RemoteContextFactory extends BaseContextFactory {
|
package/lib/esm/src/context.js
CHANGED
|
@@ -66,29 +66,42 @@ class Context {
|
|
|
66
66
|
await this._currentTab.page.bringToFront();
|
|
67
67
|
}
|
|
68
68
|
async ensureTab() {
|
|
69
|
-
console.log(
|
|
70
|
-
console.log(
|
|
71
|
-
console.log(
|
|
69
|
+
console.log(`[Context.ensureTab] --------- ENSURE TAB START ---------`);
|
|
70
|
+
console.log(`[Context.ensureTab] Current tab exists: ${!!this._currentTab}`);
|
|
71
|
+
console.log(`[Context.ensureTab] Number of tabs: ${this._tabs.length}`);
|
|
72
|
+
console.log(`[Context.ensureTab] Browser context promise exists: ${!!this._browserContextPromise}`);
|
|
73
|
+
console.log(`[Context.ensureTab] Calling _ensureBrowserContext()...`);
|
|
74
|
+
const ensureContextStart = Date.now();
|
|
72
75
|
let browserContext;
|
|
73
76
|
try {
|
|
74
77
|
const result = await this._ensureBrowserContext();
|
|
75
78
|
browserContext = result.browserContext;
|
|
76
|
-
console.log(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
console.log(`[Context.ensureTab] _ensureBrowserContext() completed in ${Date.now() - ensureContextStart}ms`);
|
|
80
|
+
console.log(`[Context.ensureTab] Browser context obtained: ${!!browserContext}`);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error(`[Context.ensureTab] ERROR: _ensureBrowserContext() failed after ${Date.now() - ensureContextStart}ms`);
|
|
83
|
+
console.error(`[Context.ensureTab] Error type: ${error.constructor.name}`);
|
|
84
|
+
console.error(`[Context.ensureTab] Error message: ${error.message}`);
|
|
85
|
+
console.error(`[Context.ensureTab] Error stack:`, error.stack);
|
|
86
|
+
throw error;
|
|
80
87
|
}
|
|
81
88
|
if (!this._currentTab) {
|
|
82
|
-
console.log(
|
|
89
|
+
console.log(`[Context.ensureTab] No current tab, creating new page...`);
|
|
90
|
+
const newPageStart = Date.now();
|
|
83
91
|
try {
|
|
84
92
|
await browserContext.newPage();
|
|
85
|
-
console.log(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
console.log(`[Context.ensureTab] New page created in ${Date.now() - newPageStart}ms`);
|
|
94
|
+
console.log(`[Context.ensureTab] Current tab after newPage: ${!!this._currentTab}`);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(`[Context.ensureTab] ERROR: newPage() failed after ${Date.now() - newPageStart}ms`);
|
|
97
|
+
console.error(`[Context.ensureTab] Error:`, error);
|
|
98
|
+
throw error;
|
|
89
99
|
}
|
|
100
|
+
} else {
|
|
101
|
+
console.log(`[Context.ensureTab] Current tab already exists, skipping newPage()`);
|
|
90
102
|
}
|
|
91
|
-
console.log(
|
|
103
|
+
console.log(`[Context.ensureTab] Returning tab. URL: ${this._currentTab?.page.url() ?? "N/A"}`);
|
|
104
|
+
console.log(`[Context.ensureTab] --------- ENSURE TAB END ---------`);
|
|
92
105
|
return this._currentTab;
|
|
93
106
|
}
|
|
94
107
|
async listTabsMarkdown() {
|
|
@@ -265,51 +278,68 @@ ${code.join("\n")}
|
|
|
265
278
|
}
|
|
266
279
|
}
|
|
267
280
|
_ensureBrowserContext() {
|
|
268
|
-
console.log(
|
|
269
|
-
console.log(
|
|
281
|
+
console.log(`[Context._ensureBrowserContext] --------- ENSURE BROWSER CONTEXT START ---------`);
|
|
282
|
+
console.log(`[Context._ensureBrowserContext] Browser context promise exists: ${!!this._browserContextPromise}`);
|
|
270
283
|
if (!this._browserContextPromise) {
|
|
271
|
-
console.log(
|
|
284
|
+
console.log(`[Context._ensureBrowserContext] No existing promise, calling _setupBrowserContext()...`);
|
|
272
285
|
this._browserContextPromise = this._setupBrowserContext();
|
|
273
|
-
this._browserContextPromise.catch((
|
|
274
|
-
console.
|
|
286
|
+
this._browserContextPromise.catch((error) => {
|
|
287
|
+
console.error(`[Context._ensureBrowserContext] _setupBrowserContext() promise rejected:`, error);
|
|
275
288
|
this._browserContextPromise = void 0;
|
|
276
289
|
});
|
|
290
|
+
} else {
|
|
291
|
+
console.log(`[Context._ensureBrowserContext] Reusing existing browser context promise`);
|
|
277
292
|
}
|
|
278
|
-
console.log(
|
|
293
|
+
console.log(`[Context._ensureBrowserContext] --------- ENSURE BROWSER CONTEXT END ---------`);
|
|
279
294
|
return this._browserContextPromise;
|
|
280
295
|
}
|
|
281
296
|
async _setupBrowserContext() {
|
|
282
|
-
console.log(
|
|
283
|
-
console.log(
|
|
297
|
+
console.log(`[Context._setupBrowserContext] --------- SETUP BROWSER CONTEXT START ---------`);
|
|
298
|
+
console.log(`[Context._setupBrowserContext] Calling browserContextFactory.createContext()...`);
|
|
299
|
+
const createContextStart = Date.now();
|
|
284
300
|
let result;
|
|
285
301
|
try {
|
|
286
302
|
result = await this._browserContextFactory.createContext();
|
|
287
|
-
console.log(
|
|
288
|
-
} catch (
|
|
289
|
-
console.
|
|
290
|
-
|
|
303
|
+
console.log(`[Context._setupBrowserContext] createContext() completed in ${Date.now() - createContextStart}ms`);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.error(`[Context._setupBrowserContext] ERROR: createContext() failed after ${Date.now() - createContextStart}ms`);
|
|
306
|
+
console.error(`[Context._setupBrowserContext] Error type: ${error.constructor.name}`);
|
|
307
|
+
console.error(`[Context._setupBrowserContext] Error message: ${error.message}`);
|
|
308
|
+
console.error(`[Context._setupBrowserContext] Error stack:`, error.stack);
|
|
309
|
+
throw error;
|
|
291
310
|
}
|
|
292
311
|
const { browserContext } = result;
|
|
293
|
-
console.log(
|
|
294
|
-
console.log(
|
|
312
|
+
console.log(`[Context._setupBrowserContext] Browser context obtained`);
|
|
313
|
+
console.log(`[Context._setupBrowserContext] Setting up request interception...`);
|
|
314
|
+
const interceptStart = Date.now();
|
|
295
315
|
await this._setupRequestInterception(browserContext);
|
|
296
|
-
console.log(
|
|
297
|
-
console.log(
|
|
298
|
-
|
|
316
|
+
console.log(`[Context._setupBrowserContext] Request interception setup completed in ${Date.now() - interceptStart}ms`);
|
|
317
|
+
console.log(`[Context._setupBrowserContext] Processing existing pages...`);
|
|
318
|
+
const existingPages = browserContext.pages();
|
|
319
|
+
console.log(`[Context._setupBrowserContext] Found ${existingPages.length} existing pages`);
|
|
320
|
+
for (const page of existingPages) {
|
|
321
|
+
console.log(`[Context._setupBrowserContext] Processing existing page: ${page.url()}`);
|
|
299
322
|
this._onPageCreated(page);
|
|
300
|
-
|
|
301
|
-
console.log(
|
|
323
|
+
}
|
|
324
|
+
console.log(`[Context._setupBrowserContext] Setting up 'page' event listener...`);
|
|
325
|
+
browserContext.on("page", (page) => {
|
|
326
|
+
console.log(`[Context._setupBrowserContext] 'page' event fired for: ${page.url()}`);
|
|
327
|
+
this._onPageCreated(page);
|
|
328
|
+
});
|
|
302
329
|
if (this.config.saveTrace) {
|
|
303
|
-
console.log(
|
|
330
|
+
console.log(`[Context._setupBrowserContext] Starting tracing...`);
|
|
331
|
+
const traceStart = Date.now();
|
|
304
332
|
await browserContext.tracing.start({
|
|
305
333
|
name: "trace",
|
|
306
334
|
screenshots: false,
|
|
307
335
|
snapshots: true,
|
|
308
336
|
sources: false
|
|
309
337
|
});
|
|
310
|
-
console.log(
|
|
338
|
+
console.log(`[Context._setupBrowserContext] Tracing started in ${Date.now() - traceStart}ms`);
|
|
311
339
|
}
|
|
312
|
-
console.log(
|
|
340
|
+
console.log(`[Context._setupBrowserContext] Total tabs after setup: ${this._tabs.length}`);
|
|
341
|
+
console.log(`[Context._setupBrowserContext] Current tab: ${this._currentTab ? "set" : "not set"}`);
|
|
342
|
+
console.log(`[Context._setupBrowserContext] --------- SETUP BROWSER CONTEXT END ---------`);
|
|
313
343
|
return result;
|
|
314
344
|
}
|
|
315
345
|
}
|
package/lib/esm/src/tab.js
CHANGED
|
@@ -46,40 +46,66 @@ class Tab {
|
|
|
46
46
|
}));
|
|
47
47
|
}
|
|
48
48
|
async navigate(url) {
|
|
49
|
-
|
|
50
|
-
console.log(
|
|
49
|
+
const navStartTime = Date.now();
|
|
50
|
+
console.log(`[Tab.navigate] --------- TAB NAVIGATION START ---------`);
|
|
51
|
+
console.log(`[Tab.navigate] URL: ${url}`);
|
|
52
|
+
console.log(`[Tab.navigate] Current page URL: ${this.page.url()}`);
|
|
53
|
+
console.log(`[Tab.navigate] Page is closed: ${this.page.isClosed()}`);
|
|
54
|
+
console.log(`[Tab.navigate] Clearing collected artifacts...`);
|
|
51
55
|
this._clearCollectedArtifacts();
|
|
52
|
-
console.log(
|
|
53
|
-
console.log(
|
|
56
|
+
console.log(`[Tab.navigate] Artifacts cleared. Console messages: ${this._consoleMessages.length}, Requests: ${this._requests.size}`);
|
|
57
|
+
console.log(`[Tab.navigate] Setting up download event listener...`);
|
|
54
58
|
const downloadEvent = callOnPageNoTrace(this.page, (page) => page.waitForEvent("download").catch(() => {
|
|
55
59
|
}));
|
|
56
|
-
console.log(
|
|
60
|
+
console.log(`[Tab.navigate] Download event listener set up`);
|
|
61
|
+
console.log(`[Tab.navigate] Calling page.goto() with waitUntil: 'domcontentloaded'`);
|
|
62
|
+
const gotoStartTime = Date.now();
|
|
57
63
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.log(
|
|
64
|
+
const response = await this.page.goto(url, { waitUntil: "domcontentloaded" });
|
|
65
|
+
const gotoTime = Date.now() - gotoStartTime;
|
|
66
|
+
console.log(`[Tab.navigate] page.goto() completed in ${gotoTime}ms`);
|
|
67
|
+
if (response) {
|
|
68
|
+
console.log(`[Tab.navigate] Response status: ${response.status()}`);
|
|
69
|
+
console.log(`[Tab.navigate] Response URL: ${response.url()}`);
|
|
70
|
+
console.log(`[Tab.navigate] Response headers:`, JSON.stringify(response.headers(), null, 2));
|
|
71
|
+
} else {
|
|
72
|
+
console.log(`[Tab.navigate] Response is null (might be same-document navigation or cached)`);
|
|
73
|
+
}
|
|
61
74
|
} catch (_e) {
|
|
62
75
|
const e = _e;
|
|
63
|
-
|
|
76
|
+
const gotoTime = Date.now() - gotoStartTime;
|
|
77
|
+
console.log(`[Tab.navigate] page.goto() threw after ${gotoTime}ms`);
|
|
78
|
+
console.log(`[Tab.navigate] Error name: ${e.name}`);
|
|
79
|
+
console.log(`[Tab.navigate] Error message: ${e.message}`);
|
|
64
80
|
const mightBeDownload = e.message.includes("net::ERR_ABORTED") || e.message.includes("Download is starting");
|
|
81
|
+
console.log(`[Tab.navigate] Might be download: ${mightBeDownload}`);
|
|
65
82
|
if (!mightBeDownload) {
|
|
66
|
-
console.
|
|
83
|
+
console.error(`[Tab.navigate] ERROR: Not a download, rethrowing error`);
|
|
84
|
+
console.error(`[Tab.navigate] Error stack:`, e.stack);
|
|
67
85
|
throw e;
|
|
68
86
|
}
|
|
69
|
-
console.log(
|
|
87
|
+
console.log(`[Tab.navigate] Waiting for potential download event (up to 1000ms)...`);
|
|
88
|
+
const downloadWaitStart = Date.now();
|
|
70
89
|
const download = await Promise.race([
|
|
71
90
|
downloadEvent,
|
|
72
91
|
new Promise((resolve) => setTimeout(resolve, 1e3))
|
|
73
92
|
]);
|
|
93
|
+
console.log(`[Tab.navigate] Download wait completed in ${Date.now() - downloadWaitStart}ms`);
|
|
94
|
+
console.log(`[Tab.navigate] Download detected: ${!!download}`);
|
|
74
95
|
if (!download) {
|
|
75
|
-
console.
|
|
96
|
+
console.error(`[Tab.navigate] ERROR: No download detected, rethrowing original error`);
|
|
76
97
|
throw e;
|
|
77
98
|
}
|
|
78
|
-
console.log(
|
|
99
|
+
console.log(`[Tab.navigate] Download detected, continuing without error`);
|
|
79
100
|
}
|
|
80
|
-
console.log(
|
|
101
|
+
console.log(`[Tab.navigate] Waiting for 'load' state (timeout: 5000ms)...`);
|
|
102
|
+
const loadWaitStart = Date.now();
|
|
81
103
|
await this.waitForLoadState("load", { timeout: 5e3 });
|
|
82
|
-
console.log(
|
|
104
|
+
console.log(`[Tab.navigate] 'load' state wait completed in ${Date.now() - loadWaitStart}ms`);
|
|
105
|
+
console.log(`[Tab.navigate] Final page URL: ${this.page.url()}`);
|
|
106
|
+
console.log(`[Tab.navigate] Final page title: ${await this.page.title().catch(() => "N/A")}`);
|
|
107
|
+
console.log(`[Tab.navigate] Total navigation time: ${Date.now() - navStartTime}ms`);
|
|
108
|
+
console.log(`[Tab.navigate] --------- TAB NAVIGATION END ---------`);
|
|
83
109
|
}
|
|
84
110
|
hasSnapshot() {
|
|
85
111
|
return !!this._snapshot;
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { defineTool } from './tool.js';
|
|
3
3
|
|
|
4
|
-
const log = (msg, data) => {
|
|
5
|
-
console.log(`[browser_navigate] ${msg}`, data !== void 0 ? JSON.stringify(data, null, 2) : "");
|
|
6
|
-
};
|
|
7
4
|
const navigate = (captureSnapshot) => defineTool({
|
|
8
5
|
capability: "core",
|
|
9
6
|
schema: {
|
|
@@ -16,39 +13,49 @@ const navigate = (captureSnapshot) => defineTool({
|
|
|
16
13
|
type: "destructive"
|
|
17
14
|
},
|
|
18
15
|
handle: async (context, params) => {
|
|
19
|
-
|
|
20
|
-
log(
|
|
21
|
-
log(
|
|
22
|
-
log(
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
console.log(`[browser_navigate] ========== NAVIGATION START ==========`);
|
|
18
|
+
console.log(`[browser_navigate] Target URL: ${params.url}`);
|
|
19
|
+
console.log(`[browser_navigate] Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
20
|
+
console.log(`[browser_navigate] captureSnapshot setting: ${captureSnapshot}`);
|
|
21
|
+
console.log(`[browser_navigate] Ensuring tab is available...`);
|
|
22
|
+
const ensureTabStart = Date.now();
|
|
23
23
|
let tab;
|
|
24
24
|
try {
|
|
25
25
|
tab = await context.ensureTab();
|
|
26
|
-
log(
|
|
27
|
-
log(
|
|
28
|
-
} catch (
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
console.log(`[browser_navigate] Tab ensured successfully in ${Date.now() - ensureTabStart}ms`);
|
|
27
|
+
console.log(`[browser_navigate] Current page URL before navigation: ${tab.page.url()}`);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(`[browser_navigate] ERROR: Failed to ensure tab after ${Date.now() - ensureTabStart}ms`);
|
|
30
|
+
console.error(`[browser_navigate] Error details:`, error);
|
|
31
|
+
throw error;
|
|
31
32
|
}
|
|
32
|
-
log(`
|
|
33
|
+
console.log(`[browser_navigate] Starting navigation to: ${params.url}`);
|
|
34
|
+
const navigationStart = Date.now();
|
|
33
35
|
try {
|
|
34
36
|
await tab.navigate(params.url);
|
|
35
|
-
log(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
console.log(`[browser_navigate] Navigation completed successfully in ${Date.now() - navigationStart}ms`);
|
|
38
|
+
console.log(`[browser_navigate] Current page URL after navigation: ${tab.page.url()}`);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`[browser_navigate] ERROR: Navigation failed after ${Date.now() - navigationStart}ms`);
|
|
41
|
+
console.error(`[browser_navigate] Error type: ${error.constructor.name}`);
|
|
42
|
+
console.error(`[browser_navigate] Error message: ${error.message}`);
|
|
43
|
+
console.error(`[browser_navigate] Error stack:`, error.stack);
|
|
44
|
+
throw error;
|
|
39
45
|
}
|
|
40
46
|
const code = [
|
|
41
47
|
`// Navigate to ${params.url}`,
|
|
42
48
|
`await page.goto('${params.url}');`
|
|
43
49
|
];
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
const totalTime = Date.now() - startTime;
|
|
51
|
+
console.log(`[browser_navigate] Total execution time: ${totalTime}ms`);
|
|
52
|
+
console.log(`[browser_navigate] Returning with captureSnapshot: ${captureSnapshot}, waitForNetwork: false`);
|
|
53
|
+
console.log(`[browser_navigate] ========== NAVIGATION END ==========`);
|
|
54
|
+
return {
|
|
46
55
|
code,
|
|
47
56
|
captureSnapshot,
|
|
48
57
|
waitForNetwork: false
|
|
49
58
|
};
|
|
50
|
-
log("=== NAVIGATE HANDLER END ===");
|
|
51
|
-
return result;
|
|
52
59
|
}
|
|
53
60
|
});
|
|
54
61
|
const goBack = (captureSnapshot) => defineTool({
|