@roxybrowser/playwright 2.0.2-beta.2 → 2.0.2-beta.5
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/dist/browser.d.ts +33 -5
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +127 -15
- package/dist/browser.js.map +1 -1
- package/dist/browserType.d.ts +23 -1
- package/dist/browserType.d.ts.map +1 -1
- package/dist/browserType.js +29 -5
- package/dist/browserType.js.map +1 -1
- package/dist/mcp/backend/network.d.ts.map +1 -1
- package/dist/mcp/backend/network.js +30 -4
- package/dist/mcp/backend/network.js.map +1 -1
- package/dist/mcp/backend/response.d.ts +2 -0
- package/dist/mcp/backend/response.d.ts.map +1 -1
- package/dist/mcp/backend/response.js +28 -4
- package/dist/mcp/backend/response.js.map +1 -1
- package/dist/mcp/connectedBrowser.d.ts.map +1 -1
- package/dist/mcp/connectedBrowser.js +402 -22
- package/dist/mcp/connectedBrowser.js.map +1 -1
- package/dist/mcp/runtime.d.ts +2 -0
- package/dist/mcp/runtime.d.ts.map +1 -1
- package/dist/mcp/runtime.js +20 -1
- package/dist/mcp/runtime.js.map +1 -1
- package/dist/mcp/types.d.ts +3 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/page.d.ts +2 -0
- package/dist/page.d.ts.map +1 -1
- package/dist/page.js +12 -0
- package/dist/page.js.map +1 -1
- package/dist/roxybrowser.bundle.js +454 -42
- package/dist/roxybrowser.bundle.js.map +1 -1
- package/dist/types/api.d.ts +23 -4
- package/dist/types/api.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -5124,6 +5124,7 @@ var RoxyPage = class RoxyPage {
|
|
|
5124
5124
|
closed = false;
|
|
5125
5125
|
closePromise = null;
|
|
5126
5126
|
closeReason;
|
|
5127
|
+
ownedContext;
|
|
5127
5128
|
defaultTimeoutMs = DEFAULT_EVENT_TIMEOUT_MS;
|
|
5128
5129
|
defaultNavigationTimeoutMs = DEFAULT_EVENT_TIMEOUT_MS;
|
|
5129
5130
|
currentViewportSize = null;
|
|
@@ -6111,6 +6112,10 @@ waiting for navigation${navigationTargetDescription} until "${waitUntil}"\n=====
|
|
|
6111
6112
|
}
|
|
6112
6113
|
this.closeReason = options.reason;
|
|
6113
6114
|
this.closePromise = (async () => {
|
|
6115
|
+
if (this.ownedContext) {
|
|
6116
|
+
await this.ownedContext.close().catch(() => {});
|
|
6117
|
+
return;
|
|
6118
|
+
}
|
|
6114
6119
|
await this.dismissActiveDialogsForClose();
|
|
6115
6120
|
await this.finalizeVideoRecording();
|
|
6116
6121
|
await this.adapter.close(options).catch(() => {});
|
|
@@ -6122,6 +6127,9 @@ waiting for navigation${navigationTargetDescription} until "${waitUntil}"\n=====
|
|
|
6122
6127
|
this.closePromise = null;
|
|
6123
6128
|
}
|
|
6124
6129
|
}
|
|
6130
|
+
setOwnedContext(context) {
|
|
6131
|
+
this.ownedContext = context;
|
|
6132
|
+
}
|
|
6125
6133
|
defaultTimeout() {
|
|
6126
6134
|
return this.defaultTimeoutMs;
|
|
6127
6135
|
}
|
|
@@ -10650,12 +10658,74 @@ var RoxyBrowser = class {
|
|
|
10650
10658
|
session;
|
|
10651
10659
|
adapter;
|
|
10652
10660
|
humanDefaults;
|
|
10653
|
-
|
|
10654
|
-
|
|
10661
|
+
_browserName;
|
|
10662
|
+
_browserType;
|
|
10663
|
+
_version;
|
|
10664
|
+
_contexts = [];
|
|
10665
|
+
_listeners = /* @__PURE__ */ new Map();
|
|
10666
|
+
_connected = true;
|
|
10667
|
+
constructor(session, adapter, humanDefaults, _browserName, _browserType, _version) {
|
|
10655
10668
|
this.session = session;
|
|
10656
10669
|
this.adapter = adapter;
|
|
10657
10670
|
this.humanDefaults = humanDefaults;
|
|
10658
|
-
this.
|
|
10671
|
+
this._browserName = _browserName;
|
|
10672
|
+
this._browserType = _browserType;
|
|
10673
|
+
this._version = _version;
|
|
10674
|
+
}
|
|
10675
|
+
on(event, listener) {
|
|
10676
|
+
return this._addListenerInternal(event, listener);
|
|
10677
|
+
}
|
|
10678
|
+
once(event, listener) {
|
|
10679
|
+
const wrapped = (payload) => {
|
|
10680
|
+
this._removeListenerInternal(event, listener);
|
|
10681
|
+
listener(payload);
|
|
10682
|
+
};
|
|
10683
|
+
this._ensureListenerSet(event).add({
|
|
10684
|
+
original: listener,
|
|
10685
|
+
wrapped
|
|
10686
|
+
});
|
|
10687
|
+
return this;
|
|
10688
|
+
}
|
|
10689
|
+
addListener(event, listener) {
|
|
10690
|
+
return this._addListenerInternal(event, listener);
|
|
10691
|
+
}
|
|
10692
|
+
removeListener(event, listener) {
|
|
10693
|
+
return this._removeListenerInternal(event, listener);
|
|
10694
|
+
}
|
|
10695
|
+
off(event, listener) {
|
|
10696
|
+
return this._removeListenerInternal(event, listener);
|
|
10697
|
+
}
|
|
10698
|
+
prependListener(event, listener) {
|
|
10699
|
+
const entry = {
|
|
10700
|
+
original: listener,
|
|
10701
|
+
wrapped: listener
|
|
10702
|
+
};
|
|
10703
|
+
const existing = this._listeners.get(event);
|
|
10704
|
+
if (!existing) {
|
|
10705
|
+
const s = new Set([entry]);
|
|
10706
|
+
this._listeners.set(event, s);
|
|
10707
|
+
} else {
|
|
10708
|
+
const s = new Set([entry, ...Array.from(existing)]);
|
|
10709
|
+
this._listeners.set(event, s);
|
|
10710
|
+
}
|
|
10711
|
+
return this;
|
|
10712
|
+
}
|
|
10713
|
+
removeAllListeners(type) {
|
|
10714
|
+
if (type === void 0) this._listeners.clear();
|
|
10715
|
+
else this._listeners.delete(type);
|
|
10716
|
+
return this;
|
|
10717
|
+
}
|
|
10718
|
+
browserType() {
|
|
10719
|
+
return this._browserType;
|
|
10720
|
+
}
|
|
10721
|
+
contexts() {
|
|
10722
|
+
return [...this._contexts];
|
|
10723
|
+
}
|
|
10724
|
+
isConnected() {
|
|
10725
|
+
return this._connected;
|
|
10726
|
+
}
|
|
10727
|
+
version() {
|
|
10728
|
+
return this._version;
|
|
10659
10729
|
}
|
|
10660
10730
|
async newContext(options = {}) {
|
|
10661
10731
|
const normalizedOptions = {
|
|
@@ -10666,26 +10736,66 @@ var RoxyBrowser = class {
|
|
|
10666
10736
|
...options.recordVideo.dir ? { dir: resolve(options.recordVideo.dir) } : {}
|
|
10667
10737
|
} } : {}
|
|
10668
10738
|
};
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10739
|
+
const context = new RoxyBrowserContext(await this.session.newContext(normalizedOptions), resolveHumanizationOptions(normalizedOptions.human, this.humanDefaults), normalizedOptions, this._browserName);
|
|
10740
|
+
this._contexts.push(context);
|
|
10741
|
+
context.on("close", () => {
|
|
10742
|
+
const index = this._contexts.indexOf(context);
|
|
10743
|
+
if (index !== -1) this._contexts.splice(index, 1);
|
|
10744
|
+
});
|
|
10745
|
+
this._emit("context", context);
|
|
10746
|
+
return context;
|
|
10747
|
+
}
|
|
10748
|
+
async newPage(options) {
|
|
10749
|
+
const context = await this.newContext(options);
|
|
10750
|
+
const page = await context.newPage();
|
|
10751
|
+
const roxyPage = page;
|
|
10752
|
+
if (typeof roxyPage.setOwnedContext === "function") roxyPage.setOwnedContext(context);
|
|
10753
|
+
else page.once("close", () => context.close().catch(() => {}));
|
|
10754
|
+
return page;
|
|
10673
10755
|
}
|
|
10674
|
-
async close() {
|
|
10756
|
+
async close(options) {
|
|
10757
|
+
if (!this._connected) return;
|
|
10758
|
+
this._connected = false;
|
|
10675
10759
|
try {
|
|
10676
10760
|
await withCloseTimeout$1(this.session.close(), BROWSER_SESSION_CLOSE_TIMEOUT_MS);
|
|
10677
10761
|
} finally {
|
|
10678
10762
|
await this.adapter.close();
|
|
10763
|
+
this._emit("disconnected", this);
|
|
10679
10764
|
}
|
|
10680
10765
|
}
|
|
10766
|
+
_addListenerInternal(event, listener) {
|
|
10767
|
+
this._ensureListenerSet(event).add({
|
|
10768
|
+
original: listener,
|
|
10769
|
+
wrapped: listener
|
|
10770
|
+
});
|
|
10771
|
+
return this;
|
|
10772
|
+
}
|
|
10773
|
+
_removeListenerInternal(event, listener) {
|
|
10774
|
+
const entries = this._listeners.get(event);
|
|
10775
|
+
if (!entries) return this;
|
|
10776
|
+
for (const entry of Array.from(entries)) if (entry.original === listener) entries.delete(entry);
|
|
10777
|
+
if (entries.size === 0) this._listeners.delete(event);
|
|
10778
|
+
return this;
|
|
10779
|
+
}
|
|
10780
|
+
_ensureListenerSet(event) {
|
|
10781
|
+
const existing = this._listeners.get(event);
|
|
10782
|
+
if (existing) return existing;
|
|
10783
|
+
const created = /* @__PURE__ */ new Set();
|
|
10784
|
+
this._listeners.set(event, created);
|
|
10785
|
+
return created;
|
|
10786
|
+
}
|
|
10787
|
+
_emit(event, payload) {
|
|
10788
|
+
const entries = this._listeners.get(event);
|
|
10789
|
+
if (!entries?.size) return false;
|
|
10790
|
+
for (const entry of Array.from(entries)) entry.wrapped(payload);
|
|
10791
|
+
return true;
|
|
10792
|
+
}
|
|
10681
10793
|
};
|
|
10682
10794
|
async function withCloseTimeout$1(promise, timeoutMs) {
|
|
10683
10795
|
let timer;
|
|
10684
10796
|
try {
|
|
10685
10797
|
return await Promise.race([promise, new Promise((_, reject) => {
|
|
10686
|
-
timer = setTimeout(() => {
|
|
10687
|
-
reject(/* @__PURE__ */ new Error(`Timed out closing browser session after ${timeoutMs}ms.`));
|
|
10688
|
-
}, timeoutMs);
|
|
10798
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Timed out closing browser session after ${timeoutMs}ms.`)), timeoutMs);
|
|
10689
10799
|
})]);
|
|
10690
10800
|
} finally {
|
|
10691
10801
|
if (timer) clearTimeout(timer);
|
|
@@ -53334,7 +53444,9 @@ var RoxyBrowserType = class {
|
|
|
53334
53444
|
protocol
|
|
53335
53445
|
});
|
|
53336
53446
|
await adapter.connect();
|
|
53337
|
-
|
|
53447
|
+
const session = await adapter.browser();
|
|
53448
|
+
const versionStr = await session.version();
|
|
53449
|
+
return new RoxyBrowser(session, adapter, resolveHumanizationOptions(options.human), options.browserName ?? this.browserName, this, versionStr);
|
|
53338
53450
|
}
|
|
53339
53451
|
};
|
|
53340
53452
|
var chromium = new RoxyBrowserType("chromium", {
|
|
@@ -73317,6 +73429,7 @@ var Response$1 = class {
|
|
|
73317
73429
|
includeSnapshot = "none";
|
|
73318
73430
|
fullSnapshot;
|
|
73319
73431
|
isClose = false;
|
|
73432
|
+
rawResults = false;
|
|
73320
73433
|
constructor(context, toolName, toolArgs) {
|
|
73321
73434
|
this.context = context;
|
|
73322
73435
|
this.toolName = toolName;
|
|
@@ -73340,6 +73453,9 @@ var Response$1 = class {
|
|
|
73340
73453
|
setClose() {
|
|
73341
73454
|
this.isClose = true;
|
|
73342
73455
|
}
|
|
73456
|
+
setRawResults() {
|
|
73457
|
+
this.rawResults = true;
|
|
73458
|
+
}
|
|
73343
73459
|
setIncludeSnapshot() {
|
|
73344
73460
|
this.includeSnapshot = this.context.config.snapshot?.mode ?? "full";
|
|
73345
73461
|
}
|
|
@@ -73355,6 +73471,21 @@ var Response$1 = class {
|
|
|
73355
73471
|
async serialize() {
|
|
73356
73472
|
const sections = [];
|
|
73357
73473
|
if (this.errors.length) sections.push("### Error", ...this.errors);
|
|
73474
|
+
if (this.rawResults) {
|
|
73475
|
+
if (this.results.length) sections.push(...this.results);
|
|
73476
|
+
return {
|
|
73477
|
+
content: [{
|
|
73478
|
+
type: "text",
|
|
73479
|
+
text: sections.join("\n")
|
|
73480
|
+
}, ...this.images.map((image) => ({
|
|
73481
|
+
type: "image",
|
|
73482
|
+
data: image.data,
|
|
73483
|
+
mimeType: image.mimeType
|
|
73484
|
+
}))],
|
|
73485
|
+
...this.isClose ? { isClose: true } : {},
|
|
73486
|
+
...this.errors.length ? { isError: true } : {}
|
|
73487
|
+
};
|
|
73488
|
+
}
|
|
73358
73489
|
if (this.results.length) {
|
|
73359
73490
|
if (sections.length) sections.push("");
|
|
73360
73491
|
sections.push("### Result", ...this.results);
|
|
@@ -73364,9 +73495,11 @@ var Response$1 = class {
|
|
|
73364
73495
|
sections.push("### Code", "```js", ...this.code, "```");
|
|
73365
73496
|
}
|
|
73366
73497
|
if (this.includeSnapshot === "full") {
|
|
73367
|
-
|
|
73368
|
-
|
|
73369
|
-
|
|
73498
|
+
if (!await this.context.runtime.hasDialog()) {
|
|
73499
|
+
const snapshot = await reconcileSnapshotWithTabs(this.context, await this.context.runtime.snapshot());
|
|
73500
|
+
if (sections.length) sections.push("");
|
|
73501
|
+
sections.push(formatSnapshot(snapshot));
|
|
73502
|
+
}
|
|
73370
73503
|
}
|
|
73371
73504
|
if (this.fullSnapshot) {
|
|
73372
73505
|
let snapshot = await reconcileSnapshotWithTabs(this.context, await this.context.runtime.snapshot({
|
|
@@ -73374,7 +73507,7 @@ var Response$1 = class {
|
|
|
73374
73507
|
...this.fullSnapshot.depth !== void 0 ? { depth: this.fullSnapshot.depth } : {},
|
|
73375
73508
|
...this.fullSnapshot.boxes !== void 0 ? { boxes: this.fullSnapshot.boxes } : {}
|
|
73376
73509
|
}));
|
|
73377
|
-
if (!this.fullSnapshot.filename && snapshot.text.trim().length === 0 && snapshot.url && snapshot.url !== "about:blank") snapshot = await reconcileSnapshotWithTabs(this.context, await this.context.runtime.snapshot({
|
|
73510
|
+
if (!this.fullSnapshot.filename && snapshot.retryable && snapshot.text.trim().length === 0 && snapshot.url && snapshot.url !== "about:blank") snapshot = await reconcileSnapshotWithTabs(this.context, await this.context.runtime.snapshot({
|
|
73378
73511
|
...this.fullSnapshot.target !== void 0 ? { target: this.fullSnapshot.target } : {},
|
|
73379
73512
|
...this.fullSnapshot.depth !== void 0 ? { depth: this.fullSnapshot.depth } : {},
|
|
73380
73513
|
...this.fullSnapshot.boxes !== void 0 ? { boxes: this.fullSnapshot.boxes } : {}
|
|
@@ -73968,7 +74101,17 @@ var networkRequest = defineTool$1({
|
|
|
73968
74101
|
response.addError(`Request #${args.index} not found. Use browser_network_requests to see available indexes.`);
|
|
73969
74102
|
return;
|
|
73970
74103
|
}
|
|
73971
|
-
|
|
74104
|
+
if (args.part) {
|
|
74105
|
+
response.setRawResults();
|
|
74106
|
+
const partText = args.part === "response-body" ? await context.runtime.fetchResponseBody(args.index) ?? "" : renderRequestPart(request, args.part);
|
|
74107
|
+
if (args.filename) {
|
|
74108
|
+
const resolvedFilename = await context.resolveOutputFile(args.filename);
|
|
74109
|
+
await writeFile(resolvedFilename, partText);
|
|
74110
|
+
response.addTextResult(`Saved network request to "${resolvedFilename}".`);
|
|
74111
|
+
} else response.addTextResult(partText);
|
|
74112
|
+
return;
|
|
74113
|
+
}
|
|
74114
|
+
const text = renderRequestDetails(request);
|
|
73972
74115
|
if (args.filename) {
|
|
73973
74116
|
const resolvedFilename = await context.resolveOutputFile(args.filename);
|
|
73974
74117
|
await writeFile(resolvedFilename, text);
|
|
@@ -74002,8 +74145,10 @@ function renderRequestDetails(request) {
|
|
|
74002
74145
|
if (request.mimeType) lines.push(` mimeType: ${request.mimeType}`);
|
|
74003
74146
|
appendHeaders(lines, "Request headers", request.requestHeaders);
|
|
74004
74147
|
if (request.responseHeaders) appendHeaders(lines, "Response headers", request.responseHeaders);
|
|
74005
|
-
|
|
74006
|
-
if (request.
|
|
74148
|
+
const hints = [];
|
|
74149
|
+
if (request.requestBody) hints.push(`Call browser_network_request with part="request-body" to read the request body.`);
|
|
74150
|
+
if (canHaveResponseBody(request)) hints.push(`Call browser_network_request with part="response-body" to read the response body.`);
|
|
74151
|
+
if (hints.length) lines.push("", ...hints);
|
|
74007
74152
|
return lines.join("\n");
|
|
74008
74153
|
}
|
|
74009
74154
|
function renderRequestPart(request, part) {
|
|
@@ -74022,6 +74167,10 @@ function appendHeaders(lines, title, headers) {
|
|
|
74022
74167
|
function renderHeaders(headers) {
|
|
74023
74168
|
return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
|
|
74024
74169
|
}
|
|
74170
|
+
function canHaveResponseBody(request) {
|
|
74171
|
+
if (request.failureText || request.status === void 0) return false;
|
|
74172
|
+
return request.status !== 204 && request.status !== 304 && !(request.status >= 100 && request.status < 200);
|
|
74173
|
+
}
|
|
74025
74174
|
var network_default = [networkRequests, networkRequest];
|
|
74026
74175
|
var runCode_default = [defineTool$1({
|
|
74027
74176
|
capability: "devtools",
|
|
@@ -74249,6 +74398,16 @@ var allTools = [...mouse_default, ...form_default];
|
|
|
74249
74398
|
function delay$1(ms) {
|
|
74250
74399
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
74251
74400
|
}
|
|
74401
|
+
async function withBiDiTimeout(promise, timeoutMs) {
|
|
74402
|
+
let timer;
|
|
74403
|
+
try {
|
|
74404
|
+
return await Promise.race([promise, new Promise((_, reject) => {
|
|
74405
|
+
timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Timed out after ${timeoutMs}ms.`)), timeoutMs);
|
|
74406
|
+
})]);
|
|
74407
|
+
} finally {
|
|
74408
|
+
if (timer) clearTimeout(timer);
|
|
74409
|
+
}
|
|
74410
|
+
}
|
|
74252
74411
|
var chromeRemoteInterface = "default" in import_chrome_remote_interface ? import_chrome_remote_interface.default : import_chrome_remote_interface;
|
|
74253
74412
|
function buildConnectionFromWsEndpoint(browserWsEndpoint) {
|
|
74254
74413
|
const parsed = new URL(browserWsEndpoint);
|
|
@@ -74759,6 +74918,7 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
74759
74918
|
pageConsoleStates = /* @__PURE__ */ new Map();
|
|
74760
74919
|
pageNetworkStates = /* @__PURE__ */ new Map();
|
|
74761
74920
|
pageDialogStates = /* @__PURE__ */ new Map();
|
|
74921
|
+
dialogWaiters = /* @__PURE__ */ new Map();
|
|
74762
74922
|
activeTabId;
|
|
74763
74923
|
versionString = "Chromium/unknown";
|
|
74764
74924
|
constructor(browserClient, connection) {
|
|
@@ -74774,7 +74934,7 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
74774
74934
|
});
|
|
74775
74935
|
const session = new CdpConnectedBrowserSession(await chromeRemoteInterface({ target: connection.browserWsEndpoint }), connection);
|
|
74776
74936
|
session.versionString = version.Browser;
|
|
74777
|
-
|
|
74937
|
+
await session.refreshTabs();
|
|
74778
74938
|
await session.getActivePageClient().catch(() => void 0);
|
|
74779
74939
|
return session;
|
|
74780
74940
|
}
|
|
@@ -74826,6 +74986,7 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
74826
74986
|
async click(target, options) {
|
|
74827
74987
|
const pageClient = await this.getActivePageClient();
|
|
74828
74988
|
const contextId = await this.getActiveUtilityContextId(pageClient);
|
|
74989
|
+
const tabId = await this.getActiveTabId();
|
|
74829
74990
|
const point = await evaluateCdp(pageClient, "nodeToken" in target ? ACTION_POINT_EVALUATE_SOURCE : ACTION_POINT_BY_SELECTOR_SOURCE, "nodeToken" in target ? { nodeToken: target.nodeToken } : { selector: target.selector }, contextId);
|
|
74830
74991
|
if (!point.ok || point.x === void 0 || point.y === void 0) {
|
|
74831
74992
|
const isSelector = "selector" in target;
|
|
@@ -74859,7 +75020,7 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
74859
75020
|
modifiers: modifiersMask
|
|
74860
75021
|
});
|
|
74861
75022
|
await delay$1(options.clickHoldMs);
|
|
74862
|
-
|
|
75023
|
+
const releasePromise = pageClient.Input.dispatchMouseEvent({
|
|
74863
75024
|
type: "mouseReleased",
|
|
74864
75025
|
x: point.x,
|
|
74865
75026
|
y: point.y,
|
|
@@ -74867,6 +75028,7 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
74867
75028
|
clickCount,
|
|
74868
75029
|
modifiers: modifiersMask
|
|
74869
75030
|
});
|
|
75031
|
+
await Promise.race([releasePromise, this.waitForDialog(tabId, options.clickHoldMs + 1e3)]);
|
|
74870
75032
|
}
|
|
74871
75033
|
}
|
|
74872
75034
|
async drag(start, end, options) {
|
|
@@ -75122,24 +75284,72 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
75122
75284
|
}
|
|
75123
75285
|
}
|
|
75124
75286
|
async handleDialog(accept, promptText) {
|
|
75125
|
-
const tabId =
|
|
75287
|
+
const tabId = this.dialogTabId();
|
|
75126
75288
|
if (!this.pageDialogStates.has(tabId)) throw new McpToolError("no_dialog", "No dialog visible.");
|
|
75127
|
-
const pageClient = await this.getActivePageClient();
|
|
75289
|
+
const pageClient = this.pageClients.get(tabId) ?? await this.getActivePageClient();
|
|
75128
75290
|
this.pageDialogStates.delete(tabId);
|
|
75129
75291
|
await pageClient.Page.handleJavaScriptDialog({
|
|
75130
75292
|
accept,
|
|
75131
75293
|
...promptText !== void 0 ? { promptText } : {}
|
|
75132
75294
|
});
|
|
75133
75295
|
}
|
|
75296
|
+
async hasDialog() {
|
|
75297
|
+
return this.pageDialogStates.size > 0;
|
|
75298
|
+
}
|
|
75299
|
+
waitForDialog(tabId, timeoutMs) {
|
|
75300
|
+
if (this.pageDialogStates.has(tabId)) return Promise.resolve();
|
|
75301
|
+
return new Promise((resolve) => {
|
|
75302
|
+
const waiter = { resolve: () => {
|
|
75303
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
75304
|
+
this.removeDialogWaiter(tabId, waiter);
|
|
75305
|
+
resolve();
|
|
75306
|
+
} };
|
|
75307
|
+
waiter.timer = setTimeout(() => waiter.resolve(), timeoutMs);
|
|
75308
|
+
const waiters = this.dialogWaiters.get(tabId) ?? /* @__PURE__ */ new Set();
|
|
75309
|
+
waiters.add(waiter);
|
|
75310
|
+
this.dialogWaiters.set(tabId, waiters);
|
|
75311
|
+
});
|
|
75312
|
+
}
|
|
75313
|
+
resolveDialogWaiters(tabId) {
|
|
75314
|
+
const waiters = this.dialogWaiters.get(tabId);
|
|
75315
|
+
if (!waiters) return;
|
|
75316
|
+
this.dialogWaiters.delete(tabId);
|
|
75317
|
+
for (const waiter of waiters) waiter.resolve();
|
|
75318
|
+
}
|
|
75319
|
+
removeDialogWaiter(tabId, waiter) {
|
|
75320
|
+
const waiters = this.dialogWaiters.get(tabId);
|
|
75321
|
+
if (!waiters) return;
|
|
75322
|
+
waiters.delete(waiter);
|
|
75323
|
+
if (waiters.size === 0) this.dialogWaiters.delete(tabId);
|
|
75324
|
+
}
|
|
75134
75325
|
async networkRequests() {
|
|
75135
75326
|
const tabId = await this.getActiveTabId();
|
|
75327
|
+
await this.hydratePerformanceResourceRequests(tabId);
|
|
75136
75328
|
return this.ensureNetworkState(tabId).requests.map(cloneNetworkRequest);
|
|
75137
75329
|
}
|
|
75138
75330
|
async networkRequest(index) {
|
|
75139
75331
|
const tabId = await this.getActiveTabId();
|
|
75332
|
+
await this.hydratePerformanceResourceRequests(tabId);
|
|
75140
75333
|
const request = this.ensureNetworkState(tabId).requests[index - 1];
|
|
75141
75334
|
return request ? cloneNetworkRequest(request) : void 0;
|
|
75142
75335
|
}
|
|
75336
|
+
async fetchResponseBody(index) {
|
|
75337
|
+
const tabId = await this.getActiveTabId();
|
|
75338
|
+
const state = this.ensureNetworkState(tabId);
|
|
75339
|
+
const request = state.requests[index - 1];
|
|
75340
|
+
if (!request || !request.requestId) return request?.responseBody;
|
|
75341
|
+
if (!canReadResponseBody(request)) return;
|
|
75342
|
+
if (request.responseBody !== void 0) return request.responseBody;
|
|
75343
|
+
await waitForLoadingDone(state, request.requestId, 5e3).catch(() => void 0);
|
|
75344
|
+
if (request.responseBody !== void 0) return request.responseBody;
|
|
75345
|
+
if (state.bodyRead.has(request.requestId)) return;
|
|
75346
|
+
state.bodyRead.add(request.requestId);
|
|
75347
|
+
const clientNetwork = (this.pageClients.get(tabId) ?? await this.getActivePageClient()).Network;
|
|
75348
|
+
if (!clientNetwork) return;
|
|
75349
|
+
const body = await clientNetwork.getResponseBody({ requestId: request.requestId }).catch(() => void 0);
|
|
75350
|
+
if (body) request.responseBody = body.base64Encoded ? Buffer.from(body.body, "base64").toString("utf8") : body.body;
|
|
75351
|
+
return request.responseBody;
|
|
75352
|
+
}
|
|
75143
75353
|
async runCodeUnsafe(code) {
|
|
75144
75354
|
const pageClient = await this.getActivePageClient();
|
|
75145
75355
|
const contextId = await this.getActiveUtilityContextId(pageClient);
|
|
@@ -75199,6 +75409,12 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
75199
75409
|
if (!activeTab) throw new McpToolError("no_active_tab", "No active tab is available.");
|
|
75200
75410
|
return activeTab.id;
|
|
75201
75411
|
}
|
|
75412
|
+
dialogTabId() {
|
|
75413
|
+
if (this.activeTabId && this.pageDialogStates.has(this.activeTabId)) return this.activeTabId;
|
|
75414
|
+
const tabId = this.pageDialogStates.keys().next().value;
|
|
75415
|
+
if (!tabId) throw new McpToolError("no_dialog", "No dialog visible.");
|
|
75416
|
+
return tabId;
|
|
75417
|
+
}
|
|
75202
75418
|
async getActivePageClient() {
|
|
75203
75419
|
const activeTab = (await this.refreshTabs()).find((tab) => tab.active);
|
|
75204
75420
|
if (!activeTab) throw new McpToolError("no_active_tab", "No active tab is available.");
|
|
@@ -75280,6 +75496,7 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
75280
75496
|
...event.defaultPrompt !== void 0 ? { defaultPrompt: event.defaultPrompt } : {},
|
|
75281
75497
|
...event.url !== void 0 ? { url: event.url } : {}
|
|
75282
75498
|
});
|
|
75499
|
+
this.resolveDialogWaiters(tabId);
|
|
75283
75500
|
});
|
|
75284
75501
|
this.installNetworkCollection(tabId, client);
|
|
75285
75502
|
}
|
|
@@ -75318,20 +75535,29 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
75318
75535
|
});
|
|
75319
75536
|
client.Network.loadingFinished(async (event) => {
|
|
75320
75537
|
const request = state.byRequestId.get(event.requestId);
|
|
75321
|
-
if (!request)
|
|
75538
|
+
if (!request) {
|
|
75539
|
+
resolveLoadingDone(state, event.requestId, true);
|
|
75540
|
+
return;
|
|
75541
|
+
}
|
|
75322
75542
|
const startedAt = state.startedAt.get(event.requestId);
|
|
75323
75543
|
if (startedAt !== void 0 && event.timestamp !== void 0) request.durationMs = Math.round(event.timestamp * 1e3 - startedAt);
|
|
75324
|
-
if (canReadResponseBody(request)) {
|
|
75544
|
+
if (canReadResponseBody(request) && !state.bodyRead.has(event.requestId)) {
|
|
75545
|
+
state.bodyRead.add(event.requestId);
|
|
75325
75546
|
const body = await client.Network?.getResponseBody({ requestId: event.requestId }).catch(() => void 0);
|
|
75326
75547
|
if (body) request.responseBody = body.base64Encoded ? Buffer.from(body.body, "base64").toString("utf8") : body.body;
|
|
75327
75548
|
}
|
|
75549
|
+
resolveLoadingDone(state, event.requestId, true);
|
|
75328
75550
|
});
|
|
75329
75551
|
client.Network.loadingFailed((event) => {
|
|
75330
75552
|
const request = state.byRequestId.get(event.requestId);
|
|
75331
|
-
if (!request)
|
|
75553
|
+
if (!request) {
|
|
75554
|
+
resolveLoadingDone(state, event.requestId, false);
|
|
75555
|
+
return;
|
|
75556
|
+
}
|
|
75332
75557
|
request.failureText = event.errorText ?? "Unknown error";
|
|
75333
75558
|
const startedAt = state.startedAt.get(event.requestId);
|
|
75334
75559
|
if (startedAt !== void 0 && event.timestamp !== void 0) request.durationMs = Math.round(event.timestamp * 1e3 - startedAt);
|
|
75560
|
+
resolveLoadingDone(state, event.requestId, false);
|
|
75335
75561
|
});
|
|
75336
75562
|
}
|
|
75337
75563
|
ensureConsoleState(tabId) {
|
|
@@ -75353,7 +75579,10 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
75353
75579
|
state = {
|
|
75354
75580
|
requests: [],
|
|
75355
75581
|
byRequestId: /* @__PURE__ */ new Map(),
|
|
75356
|
-
startedAt: /* @__PURE__ */ new Map()
|
|
75582
|
+
startedAt: /* @__PURE__ */ new Map(),
|
|
75583
|
+
hydratedPerformanceResources: false,
|
|
75584
|
+
loadingDone: /* @__PURE__ */ new Map(),
|
|
75585
|
+
bodyRead: /* @__PURE__ */ new Set()
|
|
75357
75586
|
};
|
|
75358
75587
|
this.pageNetworkStates.set(tabId, state);
|
|
75359
75588
|
}
|
|
@@ -75369,10 +75598,79 @@ var CdpConnectedBrowserSession = class CdpConnectedBrowserSession {
|
|
|
75369
75598
|
this.pageNetworkStates.set(tabId, {
|
|
75370
75599
|
requests: [],
|
|
75371
75600
|
byRequestId: /* @__PURE__ */ new Map(),
|
|
75372
|
-
startedAt: /* @__PURE__ */ new Map()
|
|
75601
|
+
startedAt: /* @__PURE__ */ new Map(),
|
|
75602
|
+
hydratedPerformanceResources: false,
|
|
75603
|
+
loadingDone: /* @__PURE__ */ new Map(),
|
|
75604
|
+
bodyRead: /* @__PURE__ */ new Set()
|
|
75373
75605
|
});
|
|
75374
75606
|
this.pageDialogStates.delete(tabId);
|
|
75375
75607
|
}
|
|
75608
|
+
async hydratePerformanceResourceRequests(tabId) {
|
|
75609
|
+
const state = this.ensureNetworkState(tabId);
|
|
75610
|
+
if (state.hydratedPerformanceResources) return;
|
|
75611
|
+
state.hydratedPerformanceResources = true;
|
|
75612
|
+
const pageClient = await this.getActivePageClient();
|
|
75613
|
+
const contextId = await this.getActiveUtilityContextId(pageClient);
|
|
75614
|
+
const documentRequest = await evaluateCdp(pageClient, String.raw`() => {
|
|
75615
|
+
const navigation = performance.getEntriesByType("navigation")[0];
|
|
75616
|
+
return {
|
|
75617
|
+
url: String(location.href || ""),
|
|
75618
|
+
duration: navigation ? Math.round(Number(navigation.duration || 0)) : undefined
|
|
75619
|
+
};
|
|
75620
|
+
}`, void 0, contextId).catch(() => void 0);
|
|
75621
|
+
if (documentRequest?.url && !Array.from(state.byRequestId.values()).some((request) => request.url === documentRequest.url)) {
|
|
75622
|
+
const requestId = `performance:navigation:${documentRequest.url}`;
|
|
75623
|
+
const request = {
|
|
75624
|
+
index: state.requests.length + 1,
|
|
75625
|
+
requestId,
|
|
75626
|
+
method: "GET",
|
|
75627
|
+
url: documentRequest.url,
|
|
75628
|
+
resourceType: "document",
|
|
75629
|
+
requestHeaders: {},
|
|
75630
|
+
status: 200,
|
|
75631
|
+
statusText: "OK",
|
|
75632
|
+
...documentRequest.duration !== void 0 ? { durationMs: documentRequest.duration } : {}
|
|
75633
|
+
};
|
|
75634
|
+
state.requests.push(request);
|
|
75635
|
+
state.byRequestId.set(requestId, request);
|
|
75636
|
+
}
|
|
75637
|
+
const resources = await evaluateCdp(pageClient, String.raw`() => performance.getEntriesByType("resource").map((entry) => ({
|
|
75638
|
+
name: String(entry.name || ""),
|
|
75639
|
+
initiatorType: String(entry.initiatorType || "other"),
|
|
75640
|
+
duration: Math.round(Number(entry.duration || 0)),
|
|
75641
|
+
responseStatus: typeof entry.responseStatus === "number" ? entry.responseStatus : undefined
|
|
75642
|
+
}))`, void 0, contextId).catch(() => []);
|
|
75643
|
+
for (const resource of resources) {
|
|
75644
|
+
if (!resource.name || Array.from(state.byRequestId.values()).some((request) => request.url === resource.name)) continue;
|
|
75645
|
+
const status = resource.responseStatus && resource.responseStatus > 0 ? resource.responseStatus : await this.probeResourceStatus(pageClient, contextId, resource.name);
|
|
75646
|
+
const requestId = `performance:${resource.name}`;
|
|
75647
|
+
const request = {
|
|
75648
|
+
index: state.requests.length + 1,
|
|
75649
|
+
requestId,
|
|
75650
|
+
method: "GET",
|
|
75651
|
+
url: resource.name,
|
|
75652
|
+
resourceType: normalizeResourceType(resource.initiatorType),
|
|
75653
|
+
requestHeaders: {},
|
|
75654
|
+
...status !== void 0 ? {
|
|
75655
|
+
status,
|
|
75656
|
+
statusText: statusTextForStatus(status)
|
|
75657
|
+
} : {},
|
|
75658
|
+
...resource.duration !== void 0 ? { durationMs: resource.duration } : {}
|
|
75659
|
+
};
|
|
75660
|
+
state.requests.push(request);
|
|
75661
|
+
state.byRequestId.set(requestId, request);
|
|
75662
|
+
}
|
|
75663
|
+
}
|
|
75664
|
+
async probeResourceStatus(pageClient, contextId, url) {
|
|
75665
|
+
return evaluateCdp(pageClient, String.raw`async (url) => {
|
|
75666
|
+
try {
|
|
75667
|
+
const response = await fetch(url, { method: "HEAD", cache: "no-store" });
|
|
75668
|
+
return response.status;
|
|
75669
|
+
} catch {
|
|
75670
|
+
return undefined;
|
|
75671
|
+
}
|
|
75672
|
+
}`, url, contextId).catch(() => void 0);
|
|
75673
|
+
}
|
|
75376
75674
|
addConsoleMessage(tabId, message) {
|
|
75377
75675
|
const state = this.ensureConsoleState(tabId);
|
|
75378
75676
|
if (!shouldIncludeConsoleMessage(message.type)) return;
|
|
@@ -75506,6 +75804,45 @@ function canReadResponseBody(request) {
|
|
|
75506
75804
|
if (request.failureText || request.status === void 0) return false;
|
|
75507
75805
|
return request.status !== 204 && request.status !== 304 && !(request.status >= 100 && request.status < 200);
|
|
75508
75806
|
}
|
|
75807
|
+
function loadingDoneEntry(state, requestId) {
|
|
75808
|
+
let entry = state.loadingDone.get(requestId);
|
|
75809
|
+
if (!entry) {
|
|
75810
|
+
let resolve;
|
|
75811
|
+
let reject;
|
|
75812
|
+
entry = {
|
|
75813
|
+
promise: new Promise((res, rej) => {
|
|
75814
|
+
resolve = res;
|
|
75815
|
+
reject = rej;
|
|
75816
|
+
}),
|
|
75817
|
+
resolve,
|
|
75818
|
+
reject
|
|
75819
|
+
};
|
|
75820
|
+
state.loadingDone.set(requestId, entry);
|
|
75821
|
+
}
|
|
75822
|
+
return entry;
|
|
75823
|
+
}
|
|
75824
|
+
function resolveLoadingDone(state, requestId, success) {
|
|
75825
|
+
const entry = state.loadingDone.get(requestId);
|
|
75826
|
+
if (!entry) return;
|
|
75827
|
+
state.loadingDone.delete(requestId);
|
|
75828
|
+
if (success) entry.resolve();
|
|
75829
|
+
else entry.reject(/* @__PURE__ */ new Error("Request failed before the response body was available."));
|
|
75830
|
+
}
|
|
75831
|
+
async function waitForLoadingDone(state, requestId, timeoutMs) {
|
|
75832
|
+
const entry = loadingDoneEntry(state, requestId);
|
|
75833
|
+
await Promise.race([entry.promise, new Promise((resolve) => setTimeout(resolve, timeoutMs))]);
|
|
75834
|
+
}
|
|
75835
|
+
function statusTextForStatus(status) {
|
|
75836
|
+
if (status === 200) return "OK";
|
|
75837
|
+
if (status === 204) return "No Content";
|
|
75838
|
+
if (status === 304) return "Not Modified";
|
|
75839
|
+
if (status === 400) return "Bad Request";
|
|
75840
|
+
if (status === 401) return "Unauthorized";
|
|
75841
|
+
if (status === 403) return "Forbidden";
|
|
75842
|
+
if (status === 404) return "Not Found";
|
|
75843
|
+
if (status === 500) return "Internal Server Error";
|
|
75844
|
+
return "";
|
|
75845
|
+
}
|
|
75509
75846
|
function cloneNetworkRequest(request) {
|
|
75510
75847
|
return {
|
|
75511
75848
|
...request,
|
|
@@ -75584,6 +75921,7 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
75584
75921
|
pageConsoleStates = /* @__PURE__ */ new Map();
|
|
75585
75922
|
pageNetworkStates = /* @__PURE__ */ new Map();
|
|
75586
75923
|
pageDialogStates = /* @__PURE__ */ new Map();
|
|
75924
|
+
dialogWaiters = /* @__PURE__ */ new Map();
|
|
75587
75925
|
bidiListeners = /* @__PURE__ */ new Map();
|
|
75588
75926
|
responseDataCollector;
|
|
75589
75927
|
activeTabId;
|
|
@@ -75602,7 +75940,7 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
75602
75940
|
const session = new BidiConnectedBrowserSession(client);
|
|
75603
75941
|
session.ownsSession = await ensureMcpBiDiSession(client, args.endpoint, args.sessionId);
|
|
75604
75942
|
await session.initialize();
|
|
75605
|
-
|
|
75943
|
+
await session.refreshTabs();
|
|
75606
75944
|
return session;
|
|
75607
75945
|
}
|
|
75608
75946
|
async version() {
|
|
@@ -75645,10 +75983,13 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
75645
75983
|
}
|
|
75646
75984
|
async snapshot(request = {}) {
|
|
75647
75985
|
const tabId = await this.getActiveTabId();
|
|
75648
|
-
return
|
|
75649
|
-
|
|
75650
|
-
|
|
75651
|
-
|
|
75986
|
+
return {
|
|
75987
|
+
...toBrowserSnapshot(await retryUntilReady(() => evaluateBiDi(this.client, tabId, PLAYWRIGHT_ARIA_SNAPSHOT_EVALUATE_SOURCE, toAriaSnapshotPayload(request))), request, {
|
|
75988
|
+
console: this.consoleSummary(tabId),
|
|
75989
|
+
consoleLink: await this.takeConsoleLink(tabId)
|
|
75990
|
+
}),
|
|
75991
|
+
retryable: true
|
|
75992
|
+
};
|
|
75652
75993
|
}
|
|
75653
75994
|
async consoleMessages(level = "info", all = false) {
|
|
75654
75995
|
const activeTabId = await this.getActiveTabId();
|
|
@@ -75751,10 +76092,12 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
75751
76092
|
parameters: { pointerType: "mouse" },
|
|
75752
76093
|
actions: pointerActions
|
|
75753
76094
|
});
|
|
75754
|
-
|
|
76095
|
+
const performPromise = this.client.inputPerformActions({
|
|
75755
76096
|
context: tabId,
|
|
75756
76097
|
actions
|
|
75757
76098
|
});
|
|
76099
|
+
await Promise.race([performPromise, this.waitForDialog(tabId, options.clickHoldMs + 5e3)]);
|
|
76100
|
+
performPromise.catch(() => {});
|
|
75758
76101
|
await this.client.inputReleaseActions({ context: tabId }).catch(() => {});
|
|
75759
76102
|
}
|
|
75760
76103
|
async drag(start, end, options) {
|
|
@@ -76055,14 +76398,17 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76055
76398
|
}
|
|
76056
76399
|
}
|
|
76057
76400
|
async handleDialog(accept, promptText) {
|
|
76058
|
-
const tabId =
|
|
76401
|
+
const tabId = this.dialogTabId();
|
|
76059
76402
|
if (!this.pageDialogStates.has(tabId)) throw new McpToolError("no_dialog", "No dialog visible.");
|
|
76060
76403
|
this.pageDialogStates.delete(tabId);
|
|
76061
|
-
await this.client.browsingContextHandleUserPrompt({
|
|
76404
|
+
await withBiDiTimeout(this.client.browsingContextHandleUserPrompt({
|
|
76062
76405
|
context: tabId,
|
|
76063
76406
|
accept,
|
|
76064
76407
|
...promptText !== void 0 ? { userText: promptText } : {}
|
|
76065
|
-
});
|
|
76408
|
+
}), 5e3);
|
|
76409
|
+
}
|
|
76410
|
+
async hasDialog() {
|
|
76411
|
+
return this.pageDialogStates.size > 0;
|
|
76066
76412
|
}
|
|
76067
76413
|
async networkRequests() {
|
|
76068
76414
|
const tabId = await this.getActiveTabId();
|
|
@@ -76073,6 +76419,15 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76073
76419
|
const request = this.ensureNetworkState(tabId).requests[index - 1];
|
|
76074
76420
|
return request ? cloneNetworkRequest(request) : void 0;
|
|
76075
76421
|
}
|
|
76422
|
+
async fetchResponseBody(index) {
|
|
76423
|
+
const tabId = await this.getActiveTabId();
|
|
76424
|
+
const request = this.ensureNetworkState(tabId).requests[index - 1];
|
|
76425
|
+
if (!request || !request.requestId) return request?.responseBody;
|
|
76426
|
+
if (request.responseBody !== void 0) return request.responseBody;
|
|
76427
|
+
const body = await this.getResponseBody(request.requestId).catch(() => void 0);
|
|
76428
|
+
if (body !== void 0) request.responseBody = body;
|
|
76429
|
+
return request.responseBody;
|
|
76430
|
+
}
|
|
76076
76431
|
async runCodeUnsafe(code) {
|
|
76077
76432
|
return this.evaluate(`async () => {
|
|
76078
76433
|
const fn = eval(${JSON.stringify(`(${code})`)});
|
|
@@ -76088,6 +76443,7 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76088
76443
|
}`);
|
|
76089
76444
|
}
|
|
76090
76445
|
async initialize() {
|
|
76446
|
+
this.attachBiDiListeners();
|
|
76091
76447
|
await this.client.sessionSubscribe({ events: [
|
|
76092
76448
|
"browsingContext.userPromptOpened",
|
|
76093
76449
|
"log.entryAdded",
|
|
@@ -76101,7 +76457,6 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76101
76457
|
maxEncodedDataSize: 1e7
|
|
76102
76458
|
}).catch(() => void 0);
|
|
76103
76459
|
this.responseDataCollector = collectorResult?.collector;
|
|
76104
|
-
this.attachBiDiListeners();
|
|
76105
76460
|
}
|
|
76106
76461
|
attachBiDiListeners() {
|
|
76107
76462
|
this.attachBiDiListener("log.entryAdded", (payload) => this.handleLogEntry(payload));
|
|
@@ -76136,6 +76491,45 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76136
76491
|
targetArg(target) {
|
|
76137
76492
|
return "nodeToken" in target ? { nodeToken: target.nodeToken } : { selector: target.selector };
|
|
76138
76493
|
}
|
|
76494
|
+
dialogTabId() {
|
|
76495
|
+
if (this.activeTabId && this.pageDialogStates.has(this.activeTabId)) return this.activeTabId;
|
|
76496
|
+
const tabId = this.pageDialogStates.keys().next().value;
|
|
76497
|
+
if (!tabId) throw new McpToolError("no_dialog", "No dialog visible.");
|
|
76498
|
+
return tabId;
|
|
76499
|
+
}
|
|
76500
|
+
waitForDialog(tabId, timeoutMs) {
|
|
76501
|
+
if (this.pageDialogStates.has(tabId)) return Promise.resolve();
|
|
76502
|
+
return new Promise((resolve, reject) => {
|
|
76503
|
+
const waiter = {
|
|
76504
|
+
resolve: () => {
|
|
76505
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
76506
|
+
this.removeDialogWaiter(tabId, waiter);
|
|
76507
|
+
resolve();
|
|
76508
|
+
},
|
|
76509
|
+
reject: (error) => {
|
|
76510
|
+
if (waiter.timer) clearTimeout(waiter.timer);
|
|
76511
|
+
this.removeDialogWaiter(tabId, waiter);
|
|
76512
|
+
reject(error);
|
|
76513
|
+
}
|
|
76514
|
+
};
|
|
76515
|
+
waiter.timer = setTimeout(() => waiter.reject?.(/* @__PURE__ */ new Error("Timed out waiting for dialog.")), timeoutMs);
|
|
76516
|
+
const waiters = this.dialogWaiters.get(tabId) ?? /* @__PURE__ */ new Set();
|
|
76517
|
+
waiters.add(waiter);
|
|
76518
|
+
this.dialogWaiters.set(tabId, waiters);
|
|
76519
|
+
});
|
|
76520
|
+
}
|
|
76521
|
+
resolveDialogWaiters(tabId) {
|
|
76522
|
+
const waiters = this.dialogWaiters.get(tabId);
|
|
76523
|
+
if (!waiters) return;
|
|
76524
|
+
this.dialogWaiters.delete(tabId);
|
|
76525
|
+
for (const waiter of waiters) waiter.resolve();
|
|
76526
|
+
}
|
|
76527
|
+
removeDialogWaiter(tabId, waiter) {
|
|
76528
|
+
const waiters = this.dialogWaiters.get(tabId);
|
|
76529
|
+
if (!waiters) return;
|
|
76530
|
+
waiters.delete(waiter);
|
|
76531
|
+
if (waiters.size === 0) this.dialogWaiters.delete(tabId);
|
|
76532
|
+
}
|
|
76139
76533
|
async actionPoint(tabId, target) {
|
|
76140
76534
|
const source = "nodeToken" in target ? ACTION_POINT_EVALUATE_SOURCE : ACTION_POINT_BY_SELECTOR_SOURCE;
|
|
76141
76535
|
const point = await evaluateBiDi(this.client, tabId, source, this.targetArg(target));
|
|
@@ -76192,6 +76586,7 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76192
76586
|
type: event.type ?? "alert",
|
|
76193
76587
|
...event.defaultValue !== void 0 ? { defaultPrompt: event.defaultValue } : {}
|
|
76194
76588
|
});
|
|
76589
|
+
this.resolveDialogWaiters(event.context);
|
|
76195
76590
|
}
|
|
76196
76591
|
handleBeforeRequestSent(payload) {
|
|
76197
76592
|
const event = parseBidiNetworkEvent(payload);
|
|
@@ -76294,7 +76689,10 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76294
76689
|
state = {
|
|
76295
76690
|
requests: [],
|
|
76296
76691
|
byRequestId: /* @__PURE__ */ new Map(),
|
|
76297
|
-
startedAt: /* @__PURE__ */ new Map()
|
|
76692
|
+
startedAt: /* @__PURE__ */ new Map(),
|
|
76693
|
+
hydratedPerformanceResources: false,
|
|
76694
|
+
loadingDone: /* @__PURE__ */ new Map(),
|
|
76695
|
+
bodyRead: /* @__PURE__ */ new Set()
|
|
76298
76696
|
};
|
|
76299
76697
|
this.pageNetworkStates.set(tabId, state);
|
|
76300
76698
|
}
|
|
@@ -76310,7 +76708,10 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76310
76708
|
this.pageNetworkStates.set(tabId, {
|
|
76311
76709
|
requests: [],
|
|
76312
76710
|
byRequestId: /* @__PURE__ */ new Map(),
|
|
76313
|
-
startedAt: /* @__PURE__ */ new Map()
|
|
76711
|
+
startedAt: /* @__PURE__ */ new Map(),
|
|
76712
|
+
hydratedPerformanceResources: false,
|
|
76713
|
+
loadingDone: /* @__PURE__ */ new Map(),
|
|
76714
|
+
bodyRead: /* @__PURE__ */ new Set()
|
|
76314
76715
|
});
|
|
76315
76716
|
this.pageDialogStates.delete(tabId);
|
|
76316
76717
|
}
|
|
@@ -76519,7 +76920,7 @@ var McpRuntime = class {
|
|
|
76519
76920
|
snapshot
|
|
76520
76921
|
};
|
|
76521
76922
|
lastAttempt = captured;
|
|
76522
|
-
if (snapshot.text.trim().length > 0 || currentActiveTab.url === "about:blank") return captured;
|
|
76923
|
+
if (!snapshot.retryable || snapshot.text.trim().length > 0 || currentActiveTab.url === "about:blank") return captured;
|
|
76523
76924
|
await delay(150 * (attempt + 1));
|
|
76524
76925
|
}
|
|
76525
76926
|
if (!lastAttempt) throw new McpToolError("action_failed", "Unable to capture page snapshot.");
|
|
@@ -76542,6 +76943,7 @@ var McpRuntime = class {
|
|
|
76542
76943
|
this.invalidateSnapshot();
|
|
76543
76944
|
this.pendingFileUploadTarget = opensFileChooser ? resolved : void 0;
|
|
76544
76945
|
if (this.snapshotMode === "none") return;
|
|
76946
|
+
if (await session.hasDialog()) return;
|
|
76545
76947
|
return this.snapshot();
|
|
76546
76948
|
}
|
|
76547
76949
|
async hover(target) {
|
|
@@ -76551,13 +76953,16 @@ var McpRuntime = class {
|
|
|
76551
76953
|
this.invalidateSnapshot();
|
|
76552
76954
|
this.pendingFileUploadTarget = void 0;
|
|
76553
76955
|
if (this.snapshotMode === "none") return;
|
|
76956
|
+
if (await session.hasDialog()) return;
|
|
76554
76957
|
return this.snapshot();
|
|
76555
76958
|
}
|
|
76556
76959
|
async navigate(url) {
|
|
76557
|
-
|
|
76960
|
+
const session = this.requireConnected();
|
|
76961
|
+
await session.navigate(normalizeNavigationUrl(url));
|
|
76558
76962
|
this.invalidateSnapshot();
|
|
76559
76963
|
this.pendingFileUploadTarget = void 0;
|
|
76560
76964
|
if (this.snapshotMode === "none") return;
|
|
76965
|
+
if (await session.hasDialog()) return;
|
|
76561
76966
|
return this.snapshot();
|
|
76562
76967
|
}
|
|
76563
76968
|
async type(ref, text, opts) {
|
|
@@ -76706,6 +77111,9 @@ var McpRuntime = class {
|
|
|
76706
77111
|
async networkRequest(index) {
|
|
76707
77112
|
return this.requireConnected().networkRequest(index);
|
|
76708
77113
|
}
|
|
77114
|
+
async fetchResponseBody(index) {
|
|
77115
|
+
return this.requireConnected().fetchResponseBody(index);
|
|
77116
|
+
}
|
|
76709
77117
|
async runCodeUnsafe(code) {
|
|
76710
77118
|
const result = await this.requireConnected().runCodeUnsafe(code);
|
|
76711
77119
|
this.invalidateSnapshot();
|
|
@@ -76742,6 +77150,10 @@ var McpRuntime = class {
|
|
|
76742
77150
|
hasPendingFileUploadTarget() {
|
|
76743
77151
|
return !!this.pendingFileUploadTarget;
|
|
76744
77152
|
}
|
|
77153
|
+
async hasDialog() {
|
|
77154
|
+
if (!this.connection) return false;
|
|
77155
|
+
return this.connection.session.hasDialog();
|
|
77156
|
+
}
|
|
76745
77157
|
async close() {
|
|
76746
77158
|
this.invalidateSnapshot();
|
|
76747
77159
|
this.pendingFileUploadTarget = void 0;
|