@roxybrowser/playwright 2.0.2-beta.4 → 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/browserType.d.ts +23 -1
- package/dist/browserType.d.ts.map +1 -1
- package/dist/browserType.js +27 -4
- package/dist/browserType.js.map +1 -1
- package/dist/mcp/connectedBrowser.d.ts.map +1 -1
- package/dist/mcp/connectedBrowser.js +75 -4
- package/dist/mcp/connectedBrowser.js.map +1 -1
- package/dist/roxybrowser.bundle.js +17 -4
- package/dist/roxybrowser.bundle.js.map +1 -1
- package/dist/types/api.d.ts +2 -2
- package/dist/types/api.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/browserType.d.ts
CHANGED
|
@@ -6,7 +6,29 @@ export declare class RoxyBrowserType implements BrowserType {
|
|
|
6
6
|
private readonly adapterFactories;
|
|
7
7
|
constructor(browserName: NonNullable<BrowserConnectOptions["browserName"]>, adapterFactories: Record<SupportedProtocol, ProtocolBrowserAdapterFactory>);
|
|
8
8
|
launch(options?: LaunchOptions): Promise<Browser>;
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Connect to an already-running browser over a WebSocket endpoint.
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ DIVERGENCE FROM PLAYWRIGHT — DO NOT "FIX" THIS BACK TO CDP-ONLY:
|
|
13
|
+
*
|
|
14
|
+
* In upstream Playwright, `BrowserType.connect()` is a CDP-only operation: it
|
|
15
|
+
* connects to a running Chromium over the DevTools Protocol. Firefox/WebKit are
|
|
16
|
+
* not supported here (Playwright routes BiDi through `connectOverCDP`-style
|
|
17
|
+
* helpers or its own internal plumbing, not this method).
|
|
18
|
+
*
|
|
19
|
+
* Roxy intentionally changes that semantics. This method dispatches on
|
|
20
|
+
* `browserName` so a single entry point serves both browser families:
|
|
21
|
+
* - chromium → CDP (ws:// DevTools endpoint)
|
|
22
|
+
* - firefox → BiDi (ws:// WebDriver BiDi endpoint)
|
|
23
|
+
*
|
|
24
|
+
* This is deliberate, not a bug. If you are an agent "normalizing" this code to
|
|
25
|
+
* match Playwright upstream, STOP — the dual-protocol dispatch is the feature.
|
|
26
|
+
* To force CDP specifically, call `connectOverCDP()` instead, which remains
|
|
27
|
+
* chromium-only and CDP-only by design (see the guard below).
|
|
28
|
+
*
|
|
29
|
+
* `options.protocol` may still be passed to override the per-browser default.
|
|
30
|
+
*/
|
|
31
|
+
connect(endpointURL: string, options?: ConnectOverCDPOptions): Promise<Browser>;
|
|
10
32
|
connectOverCDP(endpointURL: string, options?: ConnectOverCDPOptions): Promise<Browser>;
|
|
11
33
|
connectOverCDP(progress: Progress, endpointURL: string, options?: ConnectOverCDPOptions): Promise<Browser>;
|
|
12
34
|
private connectBrowser;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browserType.d.ts","sourceRoot":"","sources":["../src/browserType.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,EACb,QAAQ,EACR,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,eAAgB,YAAW,WAAW;IAE/C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBADhB,WAAW,EAAE,WAAW,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,EAC9D,gBAAgB,EAAE,MAAM,CAAC,iBAAiB,EAAE,6BAA6B,CAAC;IAGvF,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"browserType.d.ts","sourceRoot":"","sources":["../src/browserType.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,EACb,QAAQ,EACR,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,eAAgB,YAAW,WAAW;IAE/C,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBADhB,WAAW,EAAE,WAAW,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,EAC9D,gBAAgB,EAAE,MAAM,CAAC,iBAAiB,EAAE,6BAA6B,CAAC;IAGvF,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ3D;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC;IAS/E,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,OAAO,CAAC;IACb,cAAc,CAClB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,OAAO,CAAC;YAoCL,cAAc;CAqB7B;AAED,eAAO,MAAM,QAAQ,EAAE,WAGrB,CAAC;AAEH,eAAO,MAAM,OAAO,EAAE,WAGpB,CAAC"}
|
package/dist/browserType.js
CHANGED
|
@@ -16,11 +16,34 @@ export class RoxyBrowserType {
|
|
|
16
16
|
protocol: options.protocol ?? (this.browserName === "firefox" ? "bidi" : "cdp")
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Connect to an already-running browser over a WebSocket endpoint.
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ DIVERGENCE FROM PLAYWRIGHT — DO NOT "FIX" THIS BACK TO CDP-ONLY:
|
|
23
|
+
*
|
|
24
|
+
* In upstream Playwright, `BrowserType.connect()` is a CDP-only operation: it
|
|
25
|
+
* connects to a running Chromium over the DevTools Protocol. Firefox/WebKit are
|
|
26
|
+
* not supported here (Playwright routes BiDi through `connectOverCDP`-style
|
|
27
|
+
* helpers or its own internal plumbing, not this method).
|
|
28
|
+
*
|
|
29
|
+
* Roxy intentionally changes that semantics. This method dispatches on
|
|
30
|
+
* `browserName` so a single entry point serves both browser families:
|
|
31
|
+
* - chromium → CDP (ws:// DevTools endpoint)
|
|
32
|
+
* - firefox → BiDi (ws:// WebDriver BiDi endpoint)
|
|
33
|
+
*
|
|
34
|
+
* This is deliberate, not a bug. If you are an agent "normalizing" this code to
|
|
35
|
+
* match Playwright upstream, STOP — the dual-protocol dispatch is the feature.
|
|
36
|
+
* To force CDP specifically, call `connectOverCDP()` instead, which remains
|
|
37
|
+
* chromium-only and CDP-only by design (see the guard below).
|
|
38
|
+
*
|
|
39
|
+
* `options.protocol` may still be passed to override the per-browser default.
|
|
40
|
+
*/
|
|
41
|
+
async connect(endpointURL, options) {
|
|
20
42
|
return this.connectBrowser({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
43
|
+
browserName: this.browserName,
|
|
44
|
+
protocol: this.browserName === "chromium" ? "cdp" : "bidi",
|
|
45
|
+
wsEndpoint: endpointURL,
|
|
46
|
+
...options
|
|
24
47
|
});
|
|
25
48
|
}
|
|
26
49
|
async connectOverCDP(progressOrEndpointURL, endpointURLOrOptions, maybeOptions = {}) {
|
package/dist/browserType.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browserType.js","sourceRoot":"","sources":["../src/browserType.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAWrE,MAAM,OAAO,eAAe;IAEP;IACA;IAFnB,YACmB,WAA8D,EAC9D,gBAA0E;QAD1E,gBAAW,GAAX,WAAW,CAAmD;QAC9D,qBAAgB,GAAhB,gBAAgB,CAA0D;IAC1F,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,UAAyB,EAAE;QACtC,OAAO,IAAI,CAAC,cAAc,CAAC;YACzB,GAAG,OAAO;YACV,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;SAChF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"browserType.js","sourceRoot":"","sources":["../src/browserType.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connectedBrowser.d.ts","sourceRoot":"","sources":["../../src/mcp/connectedBrowser.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAOV,uBAAuB,EACvB,sBAAsB,EAOvB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"connectedBrowser.d.ts","sourceRoot":"","sources":["../../src/mcp/connectedBrowser.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAOV,uBAAuB,EACvB,sBAAsB,EAOvB,MAAM,YAAY,CAAC;AA+0GpB,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,uBAAuB,CAAC,CAMlC"}
|
|
@@ -10,6 +10,21 @@ import { ACTION_POINT_EVALUATE_SOURCE, ACTION_POINT_BY_SELECTOR_SOURCE } from ".
|
|
|
10
10
|
function delay(ms) {
|
|
11
11
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
12
|
}
|
|
13
|
+
async function withBiDiTimeout(promise, timeoutMs) {
|
|
14
|
+
let timer;
|
|
15
|
+
try {
|
|
16
|
+
return await Promise.race([
|
|
17
|
+
promise,
|
|
18
|
+
new Promise((_, reject) => {
|
|
19
|
+
timer = setTimeout(() => reject(new Error(`Timed out after ${timeoutMs}ms.`)), timeoutMs);
|
|
20
|
+
})
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
if (timer)
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
const chromeRemoteInterface = ("default" in cdpModule
|
|
14
29
|
? cdpModule.default
|
|
15
30
|
: cdpModule);
|
|
@@ -1803,10 +1818,28 @@ class BidiConnectedBrowserSession {
|
|
|
1803
1818
|
parameters: { pointerType: "mouse" },
|
|
1804
1819
|
actions: pointerActions
|
|
1805
1820
|
});
|
|
1806
|
-
|
|
1821
|
+
// TODO(bidi): A synchronous alert()/confirm()/prompt() opened by the click
|
|
1822
|
+
// blocks the page's main thread, and in Firefox that also wedges the BiDi
|
|
1823
|
+
// transport: inputPerformActions never resolves while the modal is open.
|
|
1824
|
+
// Unlike CDP (where only the mouse-release call blocks), BiDi dispatches
|
|
1825
|
+
// the whole pointer sequence as one atomic command, so we cannot split it.
|
|
1826
|
+
// Mitigation (NOT a full fix): race the action against the dialog waiter so
|
|
1827
|
+
// a dialog-opening click resolves instead of hanging forever. The residual
|
|
1828
|
+
// performPromise is intentionally left dangling; it resolves later once the
|
|
1829
|
+
// dialog is dismissed.
|
|
1830
|
+
//
|
|
1831
|
+
// KNOWN-UNRESOLVED: even with this race,后续的 BiDi 命令在模态框打开期间仍可能
|
|
1832
|
+
// 整体卡死(见 handleDialog 的 TODO)。Firefox/geckodriver 在 alert 模态下会
|
|
1833
|
+
// 阻塞几乎所有 BiDi 命令,这是浏览器/驱动层的限制,本适配器无法绕过。
|
|
1834
|
+
const performPromise = this.client.inputPerformActions({
|
|
1807
1835
|
context: tabId,
|
|
1808
1836
|
actions
|
|
1809
1837
|
});
|
|
1838
|
+
await Promise.race([
|
|
1839
|
+
performPromise,
|
|
1840
|
+
this.waitForDialog(tabId, options.clickHoldMs + 5000)
|
|
1841
|
+
]);
|
|
1842
|
+
performPromise.catch(() => { });
|
|
1810
1843
|
await this.client.inputReleaseActions({ context: tabId }).catch(() => { });
|
|
1811
1844
|
}
|
|
1812
1845
|
async drag(start, end, options) {
|
|
@@ -2062,11 +2095,19 @@ class BidiConnectedBrowserSession {
|
|
|
2062
2095
|
throw new McpToolError("no_dialog", "No dialog visible.");
|
|
2063
2096
|
}
|
|
2064
2097
|
this.pageDialogStates.delete(tabId);
|
|
2065
|
-
|
|
2098
|
+
// TODO(bidi): Firefox's browsingContext.handleUserPrompt can stall while a
|
|
2099
|
+
// modal is open — 实测在 alert/confirm 模态下 geckodriver 对该命令的响应会
|
|
2100
|
+
// 长时间不返回(实测 60s+ 不返回,最终靠 MCP 客户端超时才解脱)。这里用
|
|
2101
|
+
// withBiDiTimeout 兜底:最多等 5s 后强制 reject,避免工具调用无限挂起。
|
|
2102
|
+
// 这只是“快速失败”的缓解,并未真正解决“模态框打开时几乎所有 BiDi 命令都
|
|
2103
|
+
// 被卡死”的底层问题。CDP 下这一路径是可靠的,BiDi 暂只能参考 CDP 思路。
|
|
2104
|
+
// KNOWN-UNRESOLVED: 若在模态框打开期间调用本命令,前序的 refreshTabs
|
|
2105
|
+
// (browsingContextGetTree) 等也可能先一步卡死,导致整个 tool 调用超时。
|
|
2106
|
+
await withBiDiTimeout(this.client.browsingContextHandleUserPrompt({
|
|
2066
2107
|
context: tabId,
|
|
2067
2108
|
accept,
|
|
2068
2109
|
...(promptText !== undefined ? { userText: promptText } : {})
|
|
2069
|
-
});
|
|
2110
|
+
}), 5_000);
|
|
2070
2111
|
}
|
|
2071
2112
|
async hasDialog() {
|
|
2072
2113
|
return this.pageDialogStates.size > 0;
|
|
@@ -2110,6 +2151,15 @@ class BidiConnectedBrowserSession {
|
|
|
2110
2151
|
}`);
|
|
2111
2152
|
}
|
|
2112
2153
|
async initialize() {
|
|
2154
|
+
// 顺序很关键:必须先 attachBiDiListeners(),再 sessionSubscribe()。
|
|
2155
|
+
// 实测 Firefox:sessionSubscribe 返回后事件会立即开始涌入;若此刻监听器
|
|
2156
|
+
// 还没注册,最早的一批 network.beforeRequestSent(页面导航/资源请求)会落进
|
|
2157
|
+
// “no registered listener” 分支被静默丢弃,导致 network 列表里缺首页请求。
|
|
2158
|
+
// 调试时观察到 [DEBUG bidi client no-listener] network.beforeRequestSent 连续
|
|
2159
|
+
// 出现几十次,正是此问题。先注册监听器即可避免丢事件。
|
|
2160
|
+
// TODO(bidi): 即便修了顺序,BiDi 网络捕获仍有状态时序问题,见
|
|
2161
|
+
// handleResponseCompleted / networkRequests 的 TODO。
|
|
2162
|
+
this.attachBiDiListeners();
|
|
2113
2163
|
await this.client.sessionSubscribe({
|
|
2114
2164
|
events: [
|
|
2115
2165
|
"browsingContext.userPromptOpened",
|
|
@@ -2125,7 +2175,6 @@ class BidiConnectedBrowserSession {
|
|
|
2125
2175
|
maxEncodedDataSize: 10_000_000
|
|
2126
2176
|
}).catch(() => undefined);
|
|
2127
2177
|
this.responseDataCollector = collectorResult?.collector;
|
|
2128
|
-
this.attachBiDiListeners();
|
|
2129
2178
|
}
|
|
2130
2179
|
attachBiDiListeners() {
|
|
2131
2180
|
this.attachBiDiListener("log.entryAdded", (payload) => this.handleLogEntry(payload));
|
|
@@ -2284,6 +2333,11 @@ class BidiConnectedBrowserSession {
|
|
|
2284
2333
|
type: event.type ?? "alert",
|
|
2285
2334
|
...(event.defaultValue !== undefined ? { defaultPrompt: event.defaultValue } : {})
|
|
2286
2335
|
});
|
|
2336
|
+
// 这里必须 resolve 对话框等待器:BiDi 的 click 会 race inputPerformActions
|
|
2337
|
+
// 与 waitForDialog(见 click 注释)。若不在此 resolve,alert() 触发后
|
|
2338
|
+
// waitForDialog 会一直 pending,click 永久挂起。CDP 侧的
|
|
2339
|
+
// javascriptDialogOpening 处理也调用了 resolveDialogWaiters,两侧需对齐。
|
|
2340
|
+
this.resolveDialogWaiters(event.context);
|
|
2287
2341
|
}
|
|
2288
2342
|
handleBeforeRequestSent(payload) {
|
|
2289
2343
|
const event = parseBidiNetworkEvent(payload);
|
|
@@ -2304,6 +2358,12 @@ class BidiConnectedBrowserSession {
|
|
|
2304
2358
|
request.url = event.request.url;
|
|
2305
2359
|
request.resourceType = normalizeResourceType(event.request.destination);
|
|
2306
2360
|
request.requestHeaders = normalizeHeaders(bidiHeadersToRecord(event.request.headers));
|
|
2361
|
+
// TODO(bidi): BiDi 的 network.beforeRequestSent 只给 bodySize,不内联 POST
|
|
2362
|
+
// body。这里只置了个空串占位(requestBody ??= ""),真实 POST 体从未填充,
|
|
2363
|
+
// 因此 browser_network_request 的 part="request-body" 在 BiDi 下只能拿到空串。
|
|
2364
|
+
// CDP 侧通过 Network.requestWillBeSent 的 request.postData 直接拿到 body。
|
|
2365
|
+
// BiDi 若要拿到 body 需另发 network.getRequestPostData 请求(Firefox 支持不稳),
|
|
2366
|
+
// 暂未实现 —— 这是已知缺口,等 geckodriver 稳定后再补。
|
|
2307
2367
|
if (event.request.bodySize !== undefined && event.request.bodySize > 0) {
|
|
2308
2368
|
request.requestBody ??= "";
|
|
2309
2369
|
}
|
|
@@ -2340,6 +2400,17 @@ class BidiConnectedBrowserSession {
|
|
|
2340
2400
|
if (startedAt !== undefined && event.timestamp !== undefined) {
|
|
2341
2401
|
request.durationMs = Math.round(event.timestamp - startedAt);
|
|
2342
2402
|
}
|
|
2403
|
+
// TODO(bidi): BiDi 网络事件是乱序/延迟到达的,且 status 与 body 的可用时机
|
|
2404
|
+
// 不可靠。实测 Firefox:
|
|
2405
|
+
// - beforeRequestSent 与 responseCompleted 之间存在竞态,waitForNetworkRequest
|
|
2406
|
+
// 在 body/status 尚未就绪时就可能匹配到请求并返回;
|
|
2407
|
+
// - 随后再次 browser_network_requests 时,同一个 POST /api 请求有时会从列表
|
|
2408
|
+
// 里“消失”(疑似 responseCompleted 到达途中 ensureNetworkRequest 重建了条目
|
|
2409
|
+
// 或上下文切换所致,未完全定位)。
|
|
2410
|
+
// 这导致 BiDi 下无法像 CDP 那样做强一致的网络契约断言(=> [status] OK 全匹配)。
|
|
2411
|
+
// 这里仅在 responseCompleted 时尽力补 body;status 缺失的窗口由调用方容忍。
|
|
2412
|
+
// KNOWN-UNRESOLVED: BiDi 网络捕获的一致性问题,需等 Firefox/geckodriver 事件
|
|
2413
|
+
// 时序稳定后再追,或改用 network.getDataCollector 统一采集。
|
|
2343
2414
|
if (canReadResponseBody(request)) {
|
|
2344
2415
|
const body = await this.getResponseBody(event.request.request).catch(() => undefined);
|
|
2345
2416
|
if (body !== undefined) {
|