@roxybrowser/playwright 2.0.2-beta.1 → 2.0.2-beta.2
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/mcp/backend/connect.d.ts +1 -0
- package/dist/mcp/backend/connect.d.ts.map +1 -1
- package/dist/mcp/backend/connect.js +4 -2
- package/dist/mcp/backend/connect.js.map +1 -1
- package/dist/mcp/backend/response.d.ts.map +1 -1
- package/dist/mcp/backend/response.js +25 -3
- package/dist/mcp/backend/response.js.map +1 -1
- package/dist/mcp/connectedBrowser.d.ts.map +1 -1
- package/dist/mcp/connectedBrowser.js +28 -7
- package/dist/mcp/connectedBrowser.js.map +1 -1
- package/dist/mcp/runtime.d.ts +1 -0
- package/dist/mcp/runtime.d.ts.map +1 -1
- package/dist/mcp/runtime.js +43 -8
- package/dist/mcp/runtime.js.map +1 -1
- package/dist/mcp/transports/inMemory.d.ts.map +1 -1
- package/dist/mcp/transports/inMemory.js +1 -0
- package/dist/mcp/transports/inMemory.js.map +1 -1
- package/dist/mcp/types.d.ts +2 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/protocol/bidi/backend.d.ts +1 -1
- package/dist/protocol/bidi/backend.d.ts.map +1 -1
- package/dist/protocol/bidi/backend.js +6 -2
- package/dist/protocol/bidi/backend.js.map +1 -1
- package/dist/roxybrowser.bundle.js +83 -26
- package/dist/roxybrowser.bundle.js.map +1 -1
- package/package.json +1 -1
|
@@ -16005,7 +16005,7 @@ var BidiPageAdapter = class BidiPageAdapter {
|
|
|
16005
16005
|
resultOwnership: "none"
|
|
16006
16006
|
}));
|
|
16007
16007
|
if (response.type === "exception") throw new Error(response.exceptionDetails.text || "BiDi evaluation failed.");
|
|
16008
|
-
return parseSerializedEvaluationResult(extractBiDiValue(response.result));
|
|
16008
|
+
return parseSerializedEvaluationResult(extractBiDiValue$1(response.result));
|
|
16009
16009
|
}
|
|
16010
16010
|
async evaluateFunction(expression, arg) {
|
|
16011
16011
|
const serializedArg = arg === void 0 ? "" : serializeForEvaluation$1(arg);
|
|
@@ -17249,11 +17249,11 @@ var BidiElementHandleAdapter = class BidiElementHandleAdapter {
|
|
|
17249
17249
|
return this.page.selectOptionReference(this.reference(), values, options);
|
|
17250
17250
|
}
|
|
17251
17251
|
};
|
|
17252
|
-
function extractBiDiValue(value) {
|
|
17253
|
-
if (value.type === "array" && Array.isArray(value.value)) return value.value.map((entry) => extractBiDiValue(entry));
|
|
17252
|
+
function extractBiDiValue$1(value) {
|
|
17253
|
+
if (value.type === "array" && Array.isArray(value.value)) return value.value.map((entry) => extractBiDiValue$1(entry));
|
|
17254
17254
|
if (value.type === "object" && Array.isArray(value.value)) {
|
|
17255
17255
|
const obj = {};
|
|
17256
|
-
for (const [key, val] of value.value) obj[key] = extractBiDiValue(val);
|
|
17256
|
+
for (const [key, val] of value.value) obj[key] = extractBiDiValue$1(val);
|
|
17257
17257
|
return obj;
|
|
17258
17258
|
}
|
|
17259
17259
|
return value.value;
|
|
@@ -17645,9 +17645,9 @@ function buildFirefoxLaunchArgs(options, userDataDir, port) {
|
|
|
17645
17645
|
...options.args ?? []
|
|
17646
17646
|
];
|
|
17647
17647
|
}
|
|
17648
|
-
function resolveFirefoxExecutableCandidates(options, platform = currentPlatform$1(), fileExistsFn = fileExists$1) {
|
|
17648
|
+
function resolveFirefoxExecutableCandidates(options, platform = currentPlatform$1(), playwrightFirefoxExecutablePath, fileExistsFn = fileExists$1) {
|
|
17649
17649
|
if (options.executablePath) return [options.executablePath];
|
|
17650
|
-
return filterExistingFirefoxExecutableCandidates(defaultFirefoxExecutableCandidates(platform), platform, fileExistsFn);
|
|
17650
|
+
return filterExistingFirefoxExecutableCandidates([...playwrightFirefoxExecutablePath ? [playwrightFirefoxExecutablePath] : [], ...defaultFirefoxExecutableCandidates(platform)], platform, fileExistsFn);
|
|
17651
17651
|
}
|
|
17652
17652
|
function defaultFirefoxExecutableCandidates(platform) {
|
|
17653
17653
|
const candidates = [];
|
|
@@ -73364,16 +73364,21 @@ var Response$1 = class {
|
|
|
73364
73364
|
sections.push("### Code", "```js", ...this.code, "```");
|
|
73365
73365
|
}
|
|
73366
73366
|
if (this.includeSnapshot === "full") {
|
|
73367
|
-
const snapshot = await this.context.runtime.snapshot();
|
|
73367
|
+
const snapshot = await reconcileSnapshotWithTabs(this.context, await this.context.runtime.snapshot());
|
|
73368
73368
|
if (sections.length) sections.push("");
|
|
73369
73369
|
sections.push(formatSnapshot(snapshot));
|
|
73370
73370
|
}
|
|
73371
73371
|
if (this.fullSnapshot) {
|
|
73372
|
-
|
|
73372
|
+
let snapshot = await reconcileSnapshotWithTabs(this.context, await this.context.runtime.snapshot({
|
|
73373
73373
|
...this.fullSnapshot.target !== void 0 ? { target: this.fullSnapshot.target } : {},
|
|
73374
73374
|
...this.fullSnapshot.depth !== void 0 ? { depth: this.fullSnapshot.depth } : {},
|
|
73375
73375
|
...this.fullSnapshot.boxes !== void 0 ? { boxes: this.fullSnapshot.boxes } : {}
|
|
73376
|
-
});
|
|
73376
|
+
}));
|
|
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({
|
|
73378
|
+
...this.fullSnapshot.target !== void 0 ? { target: this.fullSnapshot.target } : {},
|
|
73379
|
+
...this.fullSnapshot.depth !== void 0 ? { depth: this.fullSnapshot.depth } : {},
|
|
73380
|
+
...this.fullSnapshot.boxes !== void 0 ? { boxes: this.fullSnapshot.boxes } : {}
|
|
73381
|
+
}));
|
|
73377
73382
|
if (this.fullSnapshot.filename) {
|
|
73378
73383
|
const resolvedFilename = await this.context.resolveOutputFile(this.fullSnapshot.filename);
|
|
73379
73384
|
await writeFile(resolvedFilename, snapshot.text);
|
|
@@ -73400,6 +73405,15 @@ var Response$1 = class {
|
|
|
73400
73405
|
};
|
|
73401
73406
|
}
|
|
73402
73407
|
};
|
|
73408
|
+
async function reconcileSnapshotWithTabs(context, snapshot) {
|
|
73409
|
+
const activeTab = (await context.runtime.listTabs()).find((tab) => tab.active);
|
|
73410
|
+
if (!activeTab) return snapshot;
|
|
73411
|
+
return {
|
|
73412
|
+
...snapshot,
|
|
73413
|
+
title: activeTab.title || snapshot.title,
|
|
73414
|
+
url: activeTab.url || snapshot.url
|
|
73415
|
+
};
|
|
73416
|
+
}
|
|
73403
73417
|
//#endregion
|
|
73404
73418
|
//#region src/mcp/backend/tool.ts
|
|
73405
73419
|
function defineTool$1(tool) {
|
|
@@ -73498,7 +73512,8 @@ var connect_default = [defineTool$1({
|
|
|
73498
73512
|
description: "Attach to an existing browser and seed the active tab snapshot.",
|
|
73499
73513
|
inputSchema: object({
|
|
73500
73514
|
endpoint: string().min(1),
|
|
73501
|
-
browser: _enum(["chrome", "firefox"]).default("chrome")
|
|
73515
|
+
browser: _enum(["chrome", "firefox"]).default("chrome"),
|
|
73516
|
+
sessionId: string().min(1).optional()
|
|
73502
73517
|
}),
|
|
73503
73518
|
type: "action"
|
|
73504
73519
|
},
|
|
@@ -73507,7 +73522,8 @@ var connect_default = [defineTool$1({
|
|
|
73507
73522
|
const result = await context.runtime.connect({
|
|
73508
73523
|
protocol,
|
|
73509
73524
|
endpoint: params.endpoint,
|
|
73510
|
-
browser: params.browser === "chrome" ? "chromium" : params.browser
|
|
73525
|
+
browser: params.browser === "chrome" ? "chromium" : params.browser,
|
|
73526
|
+
...params.sessionId ? { sessionId: params.sessionId } : {}
|
|
73511
73527
|
});
|
|
73512
73528
|
response.addTextResult(formatConnectResult({
|
|
73513
73529
|
...result,
|
|
@@ -74666,13 +74682,13 @@ var CDP_KEY_MAP = {
|
|
|
74666
74682
|
async function evaluateBiDi(client, contextId, functionSource, arg) {
|
|
74667
74683
|
const expression = arg === void 0 ? `(${functionSource})()` : `(${functionSource})(${JSON.stringify(arg)})`;
|
|
74668
74684
|
const response = await client.scriptEvaluate({
|
|
74669
|
-
expression,
|
|
74685
|
+
expression: wrapWithSerializedEvaluationResult(expression),
|
|
74670
74686
|
target: { context: contextId },
|
|
74671
74687
|
awaitPromise: true,
|
|
74672
74688
|
resultOwnership: "none"
|
|
74673
74689
|
});
|
|
74674
74690
|
if (response.type === "exception") throw new Error(response.exceptionDetails?.text || "BiDi runtime evaluation failed.");
|
|
74675
|
-
return response.result
|
|
74691
|
+
return parseSerializedEvaluationResult(extractBiDiValue(response.result));
|
|
74676
74692
|
}
|
|
74677
74693
|
async function evaluateBiDiRef(client, contextId, functionSource, arg) {
|
|
74678
74694
|
const expression = arg === void 0 ? `(${functionSource})()` : `(${functionSource})(${JSON.stringify(arg)})`;
|
|
@@ -74694,6 +74710,16 @@ async function evaluateBiDiRef(client, contextId, functionSource, arg) {
|
|
|
74694
74710
|
...response.result?.value?.handle !== void 0 ? { handle: response.result.value.handle } : {}
|
|
74695
74711
|
};
|
|
74696
74712
|
}
|
|
74713
|
+
function extractBiDiValue(value) {
|
|
74714
|
+
if (!value) return;
|
|
74715
|
+
if (value.type === "array" && Array.isArray(value.value)) return value.value.map((entry) => extractBiDiValue(entry));
|
|
74716
|
+
if (value.type === "object" && Array.isArray(value.value)) {
|
|
74717
|
+
const obj = {};
|
|
74718
|
+
for (const [key, val] of value.value) obj[key] = extractBiDiValue(val);
|
|
74719
|
+
return obj;
|
|
74720
|
+
}
|
|
74721
|
+
return value.value;
|
|
74722
|
+
}
|
|
74697
74723
|
function toAriaSnapshotPayload(request = {}) {
|
|
74698
74724
|
return {
|
|
74699
74725
|
options: normalizeAriaSnapshotOptions({
|
|
@@ -75571,10 +75597,10 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
75571
75597
|
if (parsed.protocol !== "ws:" && parsed.protocol !== "wss:") throw new McpToolError("unsupported_protocol_input", `BiDi endpoint must be a ws(s) URL. Received "${parsed.protocol}".`);
|
|
75572
75598
|
const client = await getBidiClientFactory()({
|
|
75573
75599
|
browserName: "firefox",
|
|
75574
|
-
webSocketUrl: normalizeFirefoxBidiEndpoint(args.endpoint)
|
|
75600
|
+
webSocketUrl: normalizeFirefoxBidiEndpoint(args.endpoint, args.sessionId)
|
|
75575
75601
|
});
|
|
75576
75602
|
const session = new BidiConnectedBrowserSession(client);
|
|
75577
|
-
session.ownsSession = await ensureMcpBiDiSession(client, args.endpoint);
|
|
75603
|
+
session.ownsSession = await ensureMcpBiDiSession(client, args.endpoint, args.sessionId);
|
|
75578
75604
|
await session.initialize();
|
|
75579
75605
|
if ((await session.refreshTabs()).length === 0) await session.newTab();
|
|
75580
75606
|
return session;
|
|
@@ -75619,7 +75645,7 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
75619
75645
|
}
|
|
75620
75646
|
async snapshot(request = {}) {
|
|
75621
75647
|
const tabId = await this.getActiveTabId();
|
|
75622
|
-
return toBrowserSnapshot(await evaluateBiDi(this.client, tabId, PLAYWRIGHT_ARIA_SNAPSHOT_EVALUATE_SOURCE, toAriaSnapshotPayload(request)), request, {
|
|
75648
|
+
return toBrowserSnapshot(await retryUntilReady(() => evaluateBiDi(this.client, tabId, PLAYWRIGHT_ARIA_SNAPSHOT_EVALUATE_SOURCE, toAriaSnapshotPayload(request))), request, {
|
|
75623
75649
|
console: this.consoleSummary(tabId),
|
|
75624
75650
|
consoleLink: await this.takeConsoleLink(tabId)
|
|
75625
75651
|
});
|
|
@@ -76322,14 +76348,18 @@ var BidiConnectedBrowserSession = class BidiConnectedBrowserSession {
|
|
|
76322
76348
|
return `${path.relative(process.cwd(), state.logFile)}${fromLine === state.logLine ? `#L${fromLine}` : `#L${fromLine}-L${state.logLine}`}`;
|
|
76323
76349
|
}
|
|
76324
76350
|
};
|
|
76325
|
-
function normalizeFirefoxBidiEndpoint(endpoint) {
|
|
76351
|
+
function normalizeFirefoxBidiEndpoint(endpoint, sessionId) {
|
|
76326
76352
|
const url = new URL(endpoint);
|
|
76353
|
+
if (sessionId) {
|
|
76354
|
+
url.pathname = `/session/${sessionId}`;
|
|
76355
|
+
return url.toString();
|
|
76356
|
+
}
|
|
76327
76357
|
if (url.pathname === "/" || url.pathname === "") url.pathname = "/session";
|
|
76328
76358
|
return url.toString();
|
|
76329
76359
|
}
|
|
76330
|
-
async function ensureMcpBiDiSession(client, endpoint) {
|
|
76360
|
+
async function ensureMcpBiDiSession(client, endpoint, sessionId) {
|
|
76331
76361
|
await client.sessionStatus({});
|
|
76332
|
-
if (isSessionSpecificFirefoxBidiEndpoint(endpoint)) return false;
|
|
76362
|
+
if (sessionId || isSessionSpecificFirefoxBidiEndpoint(endpoint)) return false;
|
|
76333
76363
|
try {
|
|
76334
76364
|
await client.browsingContextGetTree({});
|
|
76335
76365
|
return false;
|
|
@@ -76414,6 +76444,7 @@ var McpRuntime = class {
|
|
|
76414
76444
|
this.invalidateSnapshot();
|
|
76415
76445
|
this.pendingFileUploadTarget = void 0;
|
|
76416
76446
|
this.tabs = await session.newTab(url);
|
|
76447
|
+
if (this.snapshotMode === "none") return { tabs: this.tabs };
|
|
76417
76448
|
const snapshot = this.tabs.some((tab) => tab.active) ? await this.snapshot() : void 0;
|
|
76418
76449
|
return snapshot ? {
|
|
76419
76450
|
tabs: this.tabs,
|
|
@@ -76427,6 +76458,7 @@ var McpRuntime = class {
|
|
|
76427
76458
|
this.invalidateSnapshot();
|
|
76428
76459
|
this.pendingFileUploadTarget = void 0;
|
|
76429
76460
|
this.tabs = await session.selectTab(tab.id);
|
|
76461
|
+
if (this.snapshotMode === "none") return { tabs: this.tabs };
|
|
76430
76462
|
const snapshot = await this.snapshot();
|
|
76431
76463
|
return {
|
|
76432
76464
|
tabs: this.tabs,
|
|
@@ -76440,6 +76472,7 @@ var McpRuntime = class {
|
|
|
76440
76472
|
this.invalidateSnapshot();
|
|
76441
76473
|
this.pendingFileUploadTarget = void 0;
|
|
76442
76474
|
this.tabs = await session.closeTab(tab.id);
|
|
76475
|
+
if (this.snapshotMode === "none") return { tabs: this.tabs };
|
|
76443
76476
|
const snapshot = this.tabs.some((candidate) => candidate.active) ? await this.snapshot() : void 0;
|
|
76444
76477
|
return snapshot ? {
|
|
76445
76478
|
tabs: this.tabs,
|
|
@@ -76448,26 +76481,49 @@ var McpRuntime = class {
|
|
|
76448
76481
|
}
|
|
76449
76482
|
async snapshot(args = {}) {
|
|
76450
76483
|
const session = this.requireConnected();
|
|
76451
|
-
this.tabs = await session.listTabs();
|
|
76452
|
-
const activeTab = this.requireActiveTab();
|
|
76453
76484
|
const requestKey = this.snapshotRequestKey(args);
|
|
76454
76485
|
const request = {
|
|
76455
76486
|
...args.boxes !== void 0 ? { boxes: args.boxes } : {},
|
|
76456
76487
|
...args.depth !== void 0 ? { depth: args.depth } : {},
|
|
76457
76488
|
...args.target ? { target: this.resolveSnapshotTarget(args.target) } : {}
|
|
76458
76489
|
};
|
|
76459
|
-
const snapshot = await
|
|
76490
|
+
const { activeTab, currentActiveTab, snapshot } = await this.captureStableSnapshot(session, request);
|
|
76460
76491
|
this.snapshotCache = {
|
|
76461
|
-
tabId:
|
|
76492
|
+
tabId: currentActiveTab.id,
|
|
76462
76493
|
requestKey,
|
|
76463
76494
|
text: snapshot.text,
|
|
76464
76495
|
refs: { ...snapshot.refs },
|
|
76465
|
-
title: snapshot.title,
|
|
76466
|
-
url: snapshot.url,
|
|
76496
|
+
title: currentActiveTab.title || snapshot.title,
|
|
76497
|
+
url: currentActiveTab.url || snapshot.url,
|
|
76467
76498
|
...snapshot.console ? { console: { ...snapshot.console } } : {},
|
|
76468
76499
|
...snapshot.consoleLink ? { consoleLink: snapshot.consoleLink } : {}
|
|
76469
76500
|
};
|
|
76470
|
-
return
|
|
76501
|
+
return {
|
|
76502
|
+
...snapshot,
|
|
76503
|
+
title: currentActiveTab.title || snapshot.title,
|
|
76504
|
+
url: currentActiveTab.url || snapshot.url
|
|
76505
|
+
};
|
|
76506
|
+
}
|
|
76507
|
+
async captureStableSnapshot(session, request) {
|
|
76508
|
+
let lastAttempt;
|
|
76509
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
76510
|
+
this.tabs = await session.listTabs();
|
|
76511
|
+
const activeTab = this.requireActiveTab();
|
|
76512
|
+
const snapshot = await session.snapshot(request);
|
|
76513
|
+
const refreshedTabs = await session.listTabs();
|
|
76514
|
+
this.tabs = refreshedTabs;
|
|
76515
|
+
const currentActiveTab = refreshedTabs.find((tab) => tab.active) ?? refreshedTabs.find((tab) => tab.id === activeTab.id) ?? activeTab;
|
|
76516
|
+
const captured = {
|
|
76517
|
+
activeTab,
|
|
76518
|
+
currentActiveTab,
|
|
76519
|
+
snapshot
|
|
76520
|
+
};
|
|
76521
|
+
lastAttempt = captured;
|
|
76522
|
+
if (snapshot.text.trim().length > 0 || currentActiveTab.url === "about:blank") return captured;
|
|
76523
|
+
await delay(150 * (attempt + 1));
|
|
76524
|
+
}
|
|
76525
|
+
if (!lastAttempt) throw new McpToolError("action_failed", "Unable to capture page snapshot.");
|
|
76526
|
+
return lastAttempt;
|
|
76471
76527
|
}
|
|
76472
76528
|
async click(target, opts) {
|
|
76473
76529
|
const session = this.requireConnected();
|
|
@@ -78306,6 +78362,7 @@ async function createRoxyBrowserMcpInMemory(options = {}) {
|
|
|
78306
78362
|
await bundle.server.connect(serverTransport);
|
|
78307
78363
|
return {
|
|
78308
78364
|
server: bundle.server,
|
|
78365
|
+
runtimeManager: bundle.runtimeManager,
|
|
78309
78366
|
serverTransport,
|
|
78310
78367
|
clientTransport,
|
|
78311
78368
|
close: async () => {
|