@pyrokine/mcp-chrome 2.0.1 → 2.1.0
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/README.md +87 -43
- package/dist/core/browser-driver.d.ts +118 -1
- package/dist/core/browser-driver.d.ts.map +1 -1
- package/dist/core/browser-driver.js +11 -0
- package/dist/core/browser-driver.js.map +1 -1
- package/dist/core/error-sanitizer.js +2 -2
- package/dist/core/error-sanitizer.js.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +17 -4
- package/dist/core/errors.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/locator.d.ts.map +1 -1
- package/dist/core/locator.js +4 -3
- package/dist/core/locator.js.map +1 -1
- package/dist/core/session.d.ts +5 -2
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +107 -4
- package/dist/core/session.js.map +1 -1
- package/dist/core/types.d.ts +17 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +57 -4
- package/dist/core/types.js.map +1 -1
- package/dist/core/unified-session.d.ts +29 -9
- package/dist/core/unified-session.d.ts.map +1 -1
- package/dist/core/unified-session.js +226 -18
- package/dist/core/unified-session.js.map +1 -1
- package/dist/core/utils.d.ts +13 -0
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/core/utils.js +121 -0
- package/dist/core/utils.js.map +1 -1
- package/dist/extension/bridge.d.ts +37 -22
- package/dist/extension/bridge.d.ts.map +1 -1
- package/dist/extension/bridge.js +256 -96
- package/dist/extension/bridge.js.map +1 -1
- package/dist/extension/http-server.d.ts.map +1 -1
- package/dist/extension/http-server.js +39 -10
- package/dist/extension/http-server.js.map +1 -1
- package/dist/tools/browse.d.ts.map +1 -1
- package/dist/tools/browse.js +160 -55
- package/dist/tools/browse.js.map +1 -1
- package/dist/tools/cookies.d.ts.map +1 -1
- package/dist/tools/cookies.js +8 -11
- package/dist/tools/cookies.js.map +1 -1
- package/dist/tools/evaluate.d.ts.map +1 -1
- package/dist/tools/evaluate.js +53 -30
- package/dist/tools/evaluate.js.map +1 -1
- package/dist/tools/extract.d.ts +1 -0
- package/dist/tools/extract.d.ts.map +1 -1
- package/dist/tools/extract.js +476 -244
- package/dist/tools/extract.js.map +1 -1
- package/dist/tools/input.d.ts.map +1 -1
- package/dist/tools/input.js +798 -441
- package/dist/tools/input.js.map +1 -1
- package/dist/tools/logs.d.ts.map +1 -1
- package/dist/tools/logs.js +79 -31
- package/dist/tools/logs.js.map +1 -1
- package/dist/tools/manage.d.ts +0 -3
- package/dist/tools/manage.d.ts.map +1 -1
- package/dist/tools/manage.js +339 -285
- package/dist/tools/manage.js.map +1 -1
- package/dist/tools/png.d.ts +16 -0
- package/dist/tools/png.d.ts.map +1 -0
- package/dist/tools/png.js +197 -0
- package/dist/tools/png.js.map +1 -0
- package/dist/tools/schema.d.ts +14 -112
- package/dist/tools/schema.d.ts.map +1 -1
- package/dist/tools/schema.js +21 -12
- package/dist/tools/schema.js.map +1 -1
- package/dist/tools/wait.d.ts.map +1 -1
- package/dist/tools/wait.js +73 -13
- package/dist/tools/wait.js.map +1 -1
- package/package.json +11 -11
package/dist/extension/bridge.js
CHANGED
|
@@ -54,24 +54,25 @@ export class ExtensionBridge {
|
|
|
54
54
|
const result = await this.httpServer.sendCommand('tabs_list', {});
|
|
55
55
|
return result;
|
|
56
56
|
}
|
|
57
|
+
async listWindows() {
|
|
58
|
+
const result = await this.httpServer.sendCommand('tabs_topology', {});
|
|
59
|
+
const topology = result;
|
|
60
|
+
return {
|
|
61
|
+
...topology,
|
|
62
|
+
windows: topology.windows.map((window) => ({
|
|
63
|
+
...window,
|
|
64
|
+
tabs: window.tabs.map((tab) => ({
|
|
65
|
+
...tab,
|
|
66
|
+
targetId: String(tab.id),
|
|
67
|
+
type: tab.type ?? 'page',
|
|
68
|
+
})),
|
|
69
|
+
})),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
57
72
|
/** IBrowserDriver 接口:列出所有 tab,统一为 ListedTarget 形式(id 字符串化以保持跨 driver 兼容) */
|
|
58
73
|
async listTargets() {
|
|
59
74
|
const tabs = await this.listTabs();
|
|
60
|
-
return tabs.map((tab) => (
|
|
61
|
-
id: tab.id,
|
|
62
|
-
targetId: String(tab.id),
|
|
63
|
-
url: tab.url,
|
|
64
|
-
title: tab.title,
|
|
65
|
-
type: 'page',
|
|
66
|
-
active: tab.active,
|
|
67
|
-
windowId: tab.windowId,
|
|
68
|
-
index: tab.index,
|
|
69
|
-
groupId: tab.groupId,
|
|
70
|
-
pinned: tab.pinned,
|
|
71
|
-
incognito: tab.incognito,
|
|
72
|
-
managed: tab.managed,
|
|
73
|
-
status: tab.status,
|
|
74
|
-
}));
|
|
75
|
+
return tabs.map((tab) => this.tabToTarget(tab));
|
|
75
76
|
}
|
|
76
77
|
async createTab(url, timeout) {
|
|
77
78
|
const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
|
|
@@ -84,7 +85,7 @@ export class ExtensionBridge {
|
|
|
84
85
|
const tab = result;
|
|
85
86
|
// 自动切换到新创建的 tab,后续操作立即生效
|
|
86
87
|
this.currentTabId = tab.id;
|
|
87
|
-
this.updateState(tab
|
|
88
|
+
this.updateState(tab);
|
|
88
89
|
return tab;
|
|
89
90
|
}
|
|
90
91
|
/** IBrowserDriver 接口:新建页面(targetId 为字符串化的 chrome tab id) */
|
|
@@ -95,14 +96,16 @@ export class ExtensionBridge {
|
|
|
95
96
|
url: tab.url,
|
|
96
97
|
title: tab.title,
|
|
97
98
|
type: 'page',
|
|
99
|
+
managed: tab.managed,
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
102
|
async closeTab(tabId) {
|
|
101
|
-
await this.httpServer.sendCommand('tabs_close', { tabId });
|
|
103
|
+
const result = (await this.httpServer.sendCommand('tabs_close', { tabId }));
|
|
102
104
|
if (this.currentTabId === tabId) {
|
|
103
105
|
this.currentTabId = null;
|
|
104
106
|
this.state = null;
|
|
105
107
|
}
|
|
108
|
+
return this.normalizePageChange(result);
|
|
106
109
|
}
|
|
107
110
|
/** IBrowserDriver 接口:关闭页面(targetId 是 chrome tab id 的字符串形式,省略时关闭当前 tab) */
|
|
108
111
|
async closePage(targetId) {
|
|
@@ -110,13 +113,104 @@ export class ExtensionBridge {
|
|
|
110
113
|
if (tabId === null) {
|
|
111
114
|
throw new DriverCapabilityError('没有可关闭的页面,请指定 targetId');
|
|
112
115
|
}
|
|
113
|
-
|
|
116
|
+
return this.closeTab(tabId);
|
|
117
|
+
}
|
|
118
|
+
async adoptPage(targetId) {
|
|
119
|
+
const tabId = this.parseTargetId(targetId);
|
|
120
|
+
const result = (await this.httpServer.sendCommand('tabs_adopt', { tabId }));
|
|
121
|
+
this.currentTabId = result.tab.id;
|
|
122
|
+
this.updateState(result.tab);
|
|
123
|
+
return {
|
|
124
|
+
target: this.tabToTarget(result.tab),
|
|
125
|
+
managedBefore: result.managedBefore,
|
|
126
|
+
managedAfter: result.managedAfter,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async releasePage(targetId) {
|
|
130
|
+
const tabId = this.parseTargetId(targetId);
|
|
131
|
+
const result = (await this.httpServer.sendCommand('tabs_release', { tabId }));
|
|
132
|
+
if (this.currentTabId === result.tab.id) {
|
|
133
|
+
this.currentTabId = null;
|
|
134
|
+
this.state = null;
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
target: this.tabToTarget(result.tab),
|
|
138
|
+
managedBefore: result.managedBefore,
|
|
139
|
+
managedAfter: result.managedAfter,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async movePage(targetId, options) {
|
|
143
|
+
const tabId = this.parseTargetId(targetId);
|
|
144
|
+
const result = (await this.httpServer.sendCommand('tabs_move', {
|
|
145
|
+
tabId,
|
|
146
|
+
windowId: options.windowId,
|
|
147
|
+
index: options.index,
|
|
148
|
+
active: options.activate,
|
|
149
|
+
}));
|
|
150
|
+
return this.normalizePageChange(result);
|
|
151
|
+
}
|
|
152
|
+
async reorderPage(targetId, index) {
|
|
153
|
+
const tabId = this.parseTargetId(targetId);
|
|
154
|
+
const result = (await this.httpServer.sendCommand('tabs_reorder', {
|
|
155
|
+
tabId,
|
|
156
|
+
index,
|
|
157
|
+
}));
|
|
158
|
+
return this.normalizePageChange(result);
|
|
159
|
+
}
|
|
160
|
+
async pinPage(targetId, pinned) {
|
|
161
|
+
const tabId = this.parseTargetId(targetId);
|
|
162
|
+
const result = (await this.httpServer.sendCommand('tabs_pin', { tabId, pinned }));
|
|
163
|
+
return this.normalizePageChange(result);
|
|
164
|
+
}
|
|
165
|
+
async focusWindow(windowId) {
|
|
166
|
+
const result = (await this.httpServer.sendCommand('window_focus', { windowId }));
|
|
167
|
+
return this.normalizePageChange(result);
|
|
168
|
+
}
|
|
169
|
+
async resizeWindow(windowId, options) {
|
|
170
|
+
const result = (await this.httpServer.sendCommand('window_resize', {
|
|
171
|
+
windowId,
|
|
172
|
+
...options,
|
|
173
|
+
}));
|
|
174
|
+
return this.normalizePageChange(result);
|
|
175
|
+
}
|
|
176
|
+
async newWindow(options) {
|
|
177
|
+
const result = (await this.httpServer.sendCommand('window_create', options));
|
|
178
|
+
if (result.targetId) {
|
|
179
|
+
this.currentTabId = this.parseTargetId(result.targetId);
|
|
180
|
+
const after = result.after;
|
|
181
|
+
const tab = after?.tabs.find((item) => String(item.id) === result.targetId);
|
|
182
|
+
if (tab) {
|
|
183
|
+
this.updateState(tab);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return this.normalizePageChange(result);
|
|
187
|
+
}
|
|
188
|
+
async closeWindow(windowId) {
|
|
189
|
+
const result = (await this.httpServer.sendCommand('window_close', { windowId }));
|
|
190
|
+
const before = result.before;
|
|
191
|
+
if (before?.tabs.some((tab) => tab.id === this.currentTabId)) {
|
|
192
|
+
this.currentTabId = null;
|
|
193
|
+
this.state = null;
|
|
194
|
+
}
|
|
195
|
+
return this.normalizePageChange(result);
|
|
196
|
+
}
|
|
197
|
+
async activatePageWithAffected(targetId) {
|
|
198
|
+
const tabId = this.parseTargetId(targetId);
|
|
199
|
+
const result = (await this.httpServer.sendCommand('tabs_activate_managed', {
|
|
200
|
+
tabId,
|
|
201
|
+
}));
|
|
202
|
+
this.currentTabId = tabId;
|
|
203
|
+
const after = result.after;
|
|
204
|
+
if (after) {
|
|
205
|
+
this.updateState(after);
|
|
206
|
+
}
|
|
207
|
+
return this.normalizePageChange(result);
|
|
114
208
|
}
|
|
115
209
|
async activateTab(tabId) {
|
|
116
210
|
const result = await this.httpServer.sendCommand('tabs_activate', { tabId });
|
|
117
211
|
const tab = result;
|
|
118
212
|
this.currentTabId = tab.id;
|
|
119
|
-
this.updateState(tab
|
|
213
|
+
this.updateState(tab);
|
|
120
214
|
}
|
|
121
215
|
/** IBrowserDriver 接口:激活页面(切到前台) */
|
|
122
216
|
async activatePage(targetId) {
|
|
@@ -125,7 +219,14 @@ export class ExtensionBridge {
|
|
|
125
219
|
}
|
|
126
220
|
/** IBrowserDriver 接口:选择操作目标 tab(不切换前台,只设置当前 currentTabId) */
|
|
127
221
|
async selectPage(targetId) {
|
|
128
|
-
|
|
222
|
+
const tabId = this.parseTargetId(targetId);
|
|
223
|
+
const tabs = await this.listTabs();
|
|
224
|
+
const tab = tabs.find((item) => item.id === tabId);
|
|
225
|
+
if (!tab) {
|
|
226
|
+
throw new DriverCapabilityError(`Tab ${targetId} 不存在,请先 browse(action="list") 查看可用页面`);
|
|
227
|
+
}
|
|
228
|
+
this.currentTabId = tab.id;
|
|
229
|
+
this.updateState(tab);
|
|
129
230
|
}
|
|
130
231
|
/** IBrowserDriver 接口:获取当前操作目标 ID(chrome tab id 的字符串形式) */
|
|
131
232
|
getCurrentTargetId() {
|
|
@@ -134,70 +235,77 @@ export class ExtensionBridge {
|
|
|
134
235
|
/** IBrowserDriver 接口:设置当前操作目标 ID */
|
|
135
236
|
setCurrentTargetId(targetId) {
|
|
136
237
|
this.currentTabId = targetId !== null ? this.parseTargetId(targetId) : null;
|
|
238
|
+
if (targetId === null) {
|
|
239
|
+
this.state = null;
|
|
240
|
+
}
|
|
137
241
|
}
|
|
138
242
|
async navigate(url, options) {
|
|
243
|
+
if (this.currentTabId === null) {
|
|
244
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
245
|
+
}
|
|
139
246
|
const rpcTimeout = options?.timeout !== undefined ? options.timeout + RPC_MARGIN : undefined;
|
|
140
247
|
const params = {
|
|
248
|
+
tabId: this.requireCurrentTabId(),
|
|
141
249
|
url,
|
|
142
250
|
waitUntil: options?.wait ?? 'load',
|
|
143
251
|
timeout: options?.timeout,
|
|
144
252
|
};
|
|
145
|
-
if (this.currentTabId !== null) {
|
|
146
|
-
params.tabId = this.currentTabId;
|
|
147
|
-
}
|
|
148
253
|
const result = await this.httpServer.sendCommand('navigate', params, rpcTimeout);
|
|
149
254
|
const tab = result;
|
|
150
255
|
this.currentTabId = tab.id;
|
|
151
|
-
this.updateState(tab
|
|
256
|
+
this.updateState(tab);
|
|
152
257
|
}
|
|
153
258
|
// ==================== 导航操作 ====================
|
|
154
259
|
async goBack(timeout) {
|
|
260
|
+
if (this.currentTabId === null) {
|
|
261
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
262
|
+
}
|
|
155
263
|
// 默认:NAV_SIGNAL_WINDOW + 导航等待(默认 30s)+ RPC_MARGIN = 40s
|
|
156
264
|
// 调用方传 timeout 时:timeout 即导航超时 + 信号窗口 + 传输余量
|
|
157
265
|
const rpcTimeout = timeout !== undefined ? timeout + NAV_SIGNAL_WINDOW + RPC_MARGIN : 30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
|
|
158
266
|
const params = {
|
|
267
|
+
tabId: this.requireCurrentTabId(),
|
|
159
268
|
waitUntil: 'load',
|
|
160
269
|
timeout,
|
|
161
270
|
};
|
|
162
|
-
if (this.currentTabId !== null) {
|
|
163
|
-
params.tabId = this.currentTabId;
|
|
164
|
-
}
|
|
165
271
|
const result = (await this.httpServer.sendCommand('go_back', params, rpcTimeout));
|
|
166
|
-
this.updateState(result
|
|
272
|
+
this.updateState(result);
|
|
167
273
|
return result;
|
|
168
274
|
}
|
|
169
275
|
async goForward(timeout) {
|
|
276
|
+
if (this.currentTabId === null) {
|
|
277
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
278
|
+
}
|
|
170
279
|
// 默认:NAV_SIGNAL_WINDOW + 导航等待(默认 30s)+ RPC_MARGIN = 40s
|
|
171
280
|
// 调用方传 timeout 时:timeout 即导航超时 + 信号窗口 + 传输余量
|
|
172
281
|
const rpcTimeout = timeout !== undefined ? timeout + NAV_SIGNAL_WINDOW + RPC_MARGIN : 30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
|
|
173
282
|
const params = {
|
|
283
|
+
tabId: this.requireCurrentTabId(),
|
|
174
284
|
waitUntil: 'load',
|
|
175
285
|
timeout,
|
|
176
286
|
};
|
|
177
|
-
if (this.currentTabId !== null) {
|
|
178
|
-
params.tabId = this.currentTabId;
|
|
179
|
-
}
|
|
180
287
|
const result = (await this.httpServer.sendCommand('go_forward', params, rpcTimeout));
|
|
181
|
-
this.updateState(result
|
|
288
|
+
this.updateState(result);
|
|
182
289
|
return result;
|
|
183
290
|
}
|
|
184
291
|
async reload(ignoreCache = false, waitUntil, timeout) {
|
|
292
|
+
if (this.currentTabId === null) {
|
|
293
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
294
|
+
}
|
|
185
295
|
const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
|
|
186
296
|
const params = {
|
|
297
|
+
tabId: this.requireCurrentTabId(),
|
|
187
298
|
ignoreCache,
|
|
188
299
|
waitUntil: waitUntil ?? 'load',
|
|
189
300
|
timeout,
|
|
190
301
|
};
|
|
191
|
-
if (this.currentTabId !== null) {
|
|
192
|
-
params.tabId = this.currentTabId;
|
|
193
|
-
}
|
|
194
302
|
const result = await this.httpServer.sendCommand('reload', params, rpcTimeout);
|
|
195
303
|
const tab = result;
|
|
196
|
-
this.updateState(tab
|
|
304
|
+
this.updateState(tab);
|
|
197
305
|
}
|
|
198
306
|
async readPage(options) {
|
|
199
307
|
return (await this.httpServer.sendCommand('read_page', {
|
|
200
|
-
tabId: this.
|
|
308
|
+
tabId: this.requireCurrentTabId(),
|
|
201
309
|
frameId: this.currentFrameId || undefined,
|
|
202
310
|
...options,
|
|
203
311
|
}));
|
|
@@ -205,7 +313,7 @@ export class ExtensionBridge {
|
|
|
205
313
|
// ==================== 页面内容 ====================
|
|
206
314
|
async click(refId) {
|
|
207
315
|
const result = (await this.httpServer.sendCommand('click', {
|
|
208
|
-
tabId: this.
|
|
316
|
+
tabId: this.requireCurrentTabId(),
|
|
209
317
|
frameId: this.currentFrameId || undefined,
|
|
210
318
|
refId,
|
|
211
319
|
}));
|
|
@@ -216,15 +324,23 @@ export class ExtensionBridge {
|
|
|
216
324
|
// ==================== DOM 操作 ====================
|
|
217
325
|
async actionableClick(refId, force) {
|
|
218
326
|
return (await this.httpServer.sendCommand('actionable_click', {
|
|
219
|
-
tabId: this.
|
|
327
|
+
tabId: this.requireCurrentTabId(),
|
|
220
328
|
frameId: this.currentFrameId || undefined,
|
|
221
329
|
refId,
|
|
222
330
|
force: force ?? false,
|
|
223
331
|
}));
|
|
224
332
|
}
|
|
333
|
+
async checkActionability(refId) {
|
|
334
|
+
const result = (await this.httpServer.sendCommand('check_actionability', {
|
|
335
|
+
tabId: this.requireCurrentTabId(),
|
|
336
|
+
frameId: this.currentFrameId || undefined,
|
|
337
|
+
refId,
|
|
338
|
+
}));
|
|
339
|
+
return { ...result, success: result.success ?? result.actionable === true };
|
|
340
|
+
}
|
|
225
341
|
async dispatchInput(refId, text) {
|
|
226
342
|
return (await this.httpServer.sendCommand('dispatch_input', {
|
|
227
|
-
tabId: this.
|
|
343
|
+
tabId: this.requireCurrentTabId(),
|
|
228
344
|
frameId: this.currentFrameId || undefined,
|
|
229
345
|
refId,
|
|
230
346
|
text,
|
|
@@ -232,7 +348,7 @@ export class ExtensionBridge {
|
|
|
232
348
|
}
|
|
233
349
|
async dragAndDrop(srcRefId, dstRefId) {
|
|
234
350
|
return (await this.httpServer.sendCommand('drag_and_drop', {
|
|
235
|
-
tabId: this.
|
|
351
|
+
tabId: this.requireCurrentTabId(),
|
|
236
352
|
frameId: this.currentFrameId || undefined,
|
|
237
353
|
srcRefId,
|
|
238
354
|
dstRefId,
|
|
@@ -240,7 +356,7 @@ export class ExtensionBridge {
|
|
|
240
356
|
}
|
|
241
357
|
async getComputedStyle(refId, prop) {
|
|
242
358
|
return (await this.httpServer.sendCommand('get_computed_style', {
|
|
243
|
-
tabId: this.
|
|
359
|
+
tabId: this.requireCurrentTabId(),
|
|
244
360
|
frameId: this.currentFrameId || undefined,
|
|
245
361
|
refId,
|
|
246
362
|
prop,
|
|
@@ -248,7 +364,7 @@ export class ExtensionBridge {
|
|
|
248
364
|
}
|
|
249
365
|
async type(refId, text, clear = false) {
|
|
250
366
|
const result = (await this.httpServer.sendCommand('type', {
|
|
251
|
-
tabId: this.
|
|
367
|
+
tabId: this.requireCurrentTabId(),
|
|
252
368
|
frameId: this.currentFrameId || undefined,
|
|
253
369
|
refId,
|
|
254
370
|
text,
|
|
@@ -264,7 +380,7 @@ export class ExtensionBridge {
|
|
|
264
380
|
}
|
|
265
381
|
async scroll(x, y, refId) {
|
|
266
382
|
await this.httpServer.sendCommand('scroll', {
|
|
267
|
-
tabId: this.
|
|
383
|
+
tabId: this.requireCurrentTabId(),
|
|
268
384
|
frameId: this.currentFrameId || undefined,
|
|
269
385
|
x,
|
|
270
386
|
y,
|
|
@@ -279,7 +395,7 @@ export class ExtensionBridge {
|
|
|
279
395
|
// _args 参数仅满足 IBrowserDriver 接口签名;ExtensionBridge 不消费 args(stealth 路径上层已字符串拼接)
|
|
280
396
|
const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
|
|
281
397
|
const result = (await this.httpServer.sendCommand('evaluate', {
|
|
282
|
-
tabId: this.
|
|
398
|
+
tabId: this.requireCurrentTabId(),
|
|
283
399
|
frameId: this.currentFrameId || undefined,
|
|
284
400
|
code,
|
|
285
401
|
timeout,
|
|
@@ -294,12 +410,12 @@ export class ExtensionBridge {
|
|
|
294
410
|
return JSON.parse(result.result);
|
|
295
411
|
}
|
|
296
412
|
catch (err) {
|
|
297
|
-
throw new Error(`evaluate 结果 JSON 解析失败: ${err}
|
|
413
|
+
throw new Error(`evaluate 结果 JSON 解析失败: ${err}`, { cause: err });
|
|
298
414
|
}
|
|
299
415
|
}
|
|
300
416
|
async find(selector, text, xpath, timeout) {
|
|
301
417
|
return (await this.httpServer.sendCommand('find', {
|
|
302
|
-
tabId: this.
|
|
418
|
+
tabId: this.requireCurrentTabId(),
|
|
303
419
|
frameId: this.currentFrameId || undefined,
|
|
304
420
|
selector,
|
|
305
421
|
text,
|
|
@@ -308,7 +424,7 @@ export class ExtensionBridge {
|
|
|
308
424
|
}
|
|
309
425
|
async getText(selector) {
|
|
310
426
|
const result = (await this.httpServer.sendCommand('get_text', {
|
|
311
|
-
tabId: this.
|
|
427
|
+
tabId: this.requireCurrentTabId(),
|
|
312
428
|
frameId: this.currentFrameId || undefined,
|
|
313
429
|
selector,
|
|
314
430
|
}));
|
|
@@ -316,7 +432,7 @@ export class ExtensionBridge {
|
|
|
316
432
|
}
|
|
317
433
|
async getHtml(selector, outer = true) {
|
|
318
434
|
const result = (await this.httpServer.sendCommand('get_html', {
|
|
319
|
-
tabId: this.
|
|
435
|
+
tabId: this.requireCurrentTabId(),
|
|
320
436
|
frameId: this.currentFrameId || undefined,
|
|
321
437
|
selector,
|
|
322
438
|
outer,
|
|
@@ -339,13 +455,13 @@ export class ExtensionBridge {
|
|
|
339
455
|
}
|
|
340
456
|
async screenshot(options) {
|
|
341
457
|
return (await this.httpServer.sendCommand('screenshot', {
|
|
342
|
-
tabId: this.
|
|
458
|
+
tabId: this.requireCurrentTabId(),
|
|
343
459
|
...options,
|
|
344
460
|
}));
|
|
345
461
|
}
|
|
346
462
|
async getHtmlWithImages(selector, outer = true) {
|
|
347
463
|
return (await this.httpServer.sendCommand('get_html_with_images', {
|
|
348
|
-
tabId: this.
|
|
464
|
+
tabId: this.requireCurrentTabId(),
|
|
349
465
|
frameId: this.currentFrameId || undefined,
|
|
350
466
|
selector,
|
|
351
467
|
outer,
|
|
@@ -353,7 +469,7 @@ export class ExtensionBridge {
|
|
|
353
469
|
}
|
|
354
470
|
async getAttribute(selector, refId, attribute) {
|
|
355
471
|
const result = (await this.httpServer.sendCommand('get_attribute', {
|
|
356
|
-
tabId: this.
|
|
472
|
+
tabId: this.requireCurrentTabId(),
|
|
357
473
|
frameId: this.currentFrameId || undefined,
|
|
358
474
|
selector,
|
|
359
475
|
refId,
|
|
@@ -363,10 +479,15 @@ export class ExtensionBridge {
|
|
|
363
479
|
}
|
|
364
480
|
async getMetadata() {
|
|
365
481
|
return (await this.httpServer.sendCommand('get_metadata', {
|
|
366
|
-
tabId: this.
|
|
482
|
+
tabId: this.requireCurrentTabId(),
|
|
367
483
|
frameId: this.currentFrameId || undefined,
|
|
368
484
|
}));
|
|
369
485
|
}
|
|
486
|
+
async getFrames() {
|
|
487
|
+
return (await this.httpServer.sendCommand('get_all_frames', {
|
|
488
|
+
tabId: this.requireCurrentTabId(),
|
|
489
|
+
}));
|
|
490
|
+
}
|
|
370
491
|
async getCookies(filter) {
|
|
371
492
|
return (await this.httpServer.sendCommand('cookies_get', filter ?? {}));
|
|
372
493
|
}
|
|
@@ -389,7 +510,7 @@ export class ExtensionBridge {
|
|
|
389
510
|
}
|
|
390
511
|
async debuggerSend(method, params, tabId, timeout) {
|
|
391
512
|
return await this.httpServer.sendCommand('debugger_send', {
|
|
392
|
-
tabId: tabId ?? this.
|
|
513
|
+
tabId: tabId ?? this.requireCurrentTabId(),
|
|
393
514
|
method,
|
|
394
515
|
params,
|
|
395
516
|
}, timeout);
|
|
@@ -397,7 +518,7 @@ export class ExtensionBridge {
|
|
|
397
518
|
// ==================== Debugger (CDP via Extension) ====================
|
|
398
519
|
async inputKey(type, options = {}) {
|
|
399
520
|
await this.httpServer.sendCommand('input_key', {
|
|
400
|
-
tabId: this.
|
|
521
|
+
tabId: this.requireCurrentTabId(),
|
|
401
522
|
type,
|
|
402
523
|
...options,
|
|
403
524
|
});
|
|
@@ -405,7 +526,7 @@ export class ExtensionBridge {
|
|
|
405
526
|
// ==================== 输入事件(通过 CDP)====================
|
|
406
527
|
async inputMouse(type, x, y, options = {}) {
|
|
407
528
|
await this.httpServer.sendCommand('input_mouse', {
|
|
408
|
-
tabId: this.
|
|
529
|
+
tabId: this.requireCurrentTabId(),
|
|
409
530
|
type,
|
|
410
531
|
x,
|
|
411
532
|
y,
|
|
@@ -414,113 +535,109 @@ export class ExtensionBridge {
|
|
|
414
535
|
}
|
|
415
536
|
async inputTouch(type, touchPoints) {
|
|
416
537
|
await this.httpServer.sendCommand('input_touch', {
|
|
417
|
-
tabId: this.
|
|
538
|
+
tabId: this.requireCurrentTabId(),
|
|
418
539
|
type,
|
|
419
540
|
touchPoints,
|
|
420
541
|
});
|
|
421
542
|
}
|
|
422
543
|
async inputType(text, delay = 0) {
|
|
423
544
|
await this.httpServer.sendCommand('input_type', {
|
|
424
|
-
tabId: this.
|
|
545
|
+
tabId: this.requireCurrentTabId(),
|
|
425
546
|
text,
|
|
426
547
|
delay,
|
|
427
548
|
});
|
|
428
549
|
}
|
|
429
550
|
async consoleEnable() {
|
|
430
551
|
await this.httpServer.sendCommand('console_enable', {
|
|
431
|
-
tabId: this.
|
|
552
|
+
tabId: this.requireCurrentTabId(),
|
|
432
553
|
});
|
|
433
554
|
}
|
|
434
555
|
// ==================== 控制台日志 ====================
|
|
435
556
|
async consoleGet(options = {}) {
|
|
436
557
|
const result = (await this.httpServer.sendCommand('console_get', {
|
|
437
|
-
tabId: this.
|
|
558
|
+
tabId: this.requireCurrentTabId(),
|
|
438
559
|
...options,
|
|
439
560
|
}));
|
|
440
561
|
return result.messages;
|
|
441
562
|
}
|
|
442
563
|
async networkEnable() {
|
|
443
564
|
await this.httpServer.sendCommand('network_enable', {
|
|
444
|
-
tabId: this.
|
|
565
|
+
tabId: this.requireCurrentTabId(),
|
|
445
566
|
});
|
|
446
567
|
}
|
|
447
568
|
// ==================== 网络日志 ====================
|
|
448
569
|
async networkGet(options = {}) {
|
|
449
570
|
const result = (await this.httpServer.sendCommand('network_get', {
|
|
450
|
-
tabId: this.
|
|
571
|
+
tabId: this.requireCurrentTabId(),
|
|
451
572
|
...options,
|
|
452
573
|
}));
|
|
453
574
|
return result.requests;
|
|
454
575
|
}
|
|
455
576
|
async stealthType(text, delay = 0) {
|
|
577
|
+
if (this.currentTabId === null) {
|
|
578
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
579
|
+
}
|
|
456
580
|
const params = {
|
|
581
|
+
tabId: this.requireCurrentTabId(),
|
|
582
|
+
frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
|
|
457
583
|
text,
|
|
458
584
|
delay,
|
|
459
585
|
};
|
|
460
|
-
if (this.currentTabId !== null) {
|
|
461
|
-
params.tabId = this.currentTabId;
|
|
462
|
-
}
|
|
463
|
-
if (this.currentFrameId !== null) {
|
|
464
|
-
params.frameId = this.currentFrameId;
|
|
465
|
-
}
|
|
466
586
|
await this.httpServer.sendCommand('stealth_type', params);
|
|
467
587
|
}
|
|
468
588
|
// ==================== Stealth 模式(JS 事件模拟,无 debugger)====================
|
|
469
589
|
async stealthKey(key, type = 'press', modifiers = []) {
|
|
590
|
+
if (this.currentTabId === null) {
|
|
591
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
592
|
+
}
|
|
470
593
|
const params = {
|
|
594
|
+
tabId: this.requireCurrentTabId(),
|
|
595
|
+
frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
|
|
471
596
|
key,
|
|
472
597
|
type,
|
|
473
598
|
modifiers,
|
|
474
599
|
};
|
|
475
|
-
if (this.currentTabId !== null) {
|
|
476
|
-
params.tabId = this.currentTabId;
|
|
477
|
-
}
|
|
478
|
-
if (this.currentFrameId !== null) {
|
|
479
|
-
params.frameId = this.currentFrameId;
|
|
480
|
-
}
|
|
481
600
|
await this.httpServer.sendCommand('stealth_key', params);
|
|
482
601
|
}
|
|
483
602
|
async stealthClick(x, y, button = 'left', clickCount = 1, refId) {
|
|
603
|
+
if (this.currentTabId === null) {
|
|
604
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
605
|
+
}
|
|
484
606
|
const params = {
|
|
607
|
+
tabId: this.requireCurrentTabId(),
|
|
608
|
+
frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
|
|
485
609
|
x,
|
|
486
610
|
y,
|
|
487
611
|
button,
|
|
488
612
|
clickCount,
|
|
489
613
|
};
|
|
490
|
-
if (this.currentTabId !== null) {
|
|
491
|
-
params.tabId = this.currentTabId;
|
|
492
|
-
}
|
|
493
|
-
if (this.currentFrameId !== null) {
|
|
494
|
-
params.frameId = this.currentFrameId;
|
|
495
|
-
}
|
|
496
614
|
if (typeof refId === 'string') {
|
|
497
615
|
params.refId = refId;
|
|
498
616
|
}
|
|
499
617
|
await this.httpServer.sendCommand('stealth_click', params);
|
|
500
618
|
}
|
|
501
619
|
async stealthMouse(type, x, y, button = 'left') {
|
|
620
|
+
if (this.currentTabId === null) {
|
|
621
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
622
|
+
}
|
|
502
623
|
const params = {
|
|
624
|
+
tabId: this.requireCurrentTabId(),
|
|
625
|
+
frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
|
|
503
626
|
type,
|
|
504
627
|
x,
|
|
505
628
|
y,
|
|
506
629
|
button,
|
|
507
630
|
};
|
|
508
|
-
if (this.currentTabId !== null) {
|
|
509
|
-
params.tabId = this.currentTabId;
|
|
510
|
-
}
|
|
511
|
-
if (this.currentFrameId !== null) {
|
|
512
|
-
params.frameId = this.currentFrameId;
|
|
513
|
-
}
|
|
514
631
|
await this.httpServer.sendCommand('stealth_mouse', params);
|
|
515
632
|
}
|
|
516
633
|
async stealthInject() {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
params.tabId = this.currentTabId;
|
|
520
|
-
}
|
|
521
|
-
if (this.currentFrameId !== null) {
|
|
522
|
-
params.frameId = this.currentFrameId;
|
|
634
|
+
if (this.currentTabId === null) {
|
|
635
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
523
636
|
}
|
|
637
|
+
const params = {
|
|
638
|
+
tabId: this.requireCurrentTabId(),
|
|
639
|
+
frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
|
|
640
|
+
};
|
|
524
641
|
await this.httpServer.sendCommand('stealth_inject', params);
|
|
525
642
|
}
|
|
526
643
|
getState() {
|
|
@@ -538,7 +655,7 @@ export class ExtensionBridge {
|
|
|
538
655
|
*/
|
|
539
656
|
async evaluateInFrame(frameId, expression, timeout) {
|
|
540
657
|
return (await this.httpServer.sendCommand('evaluate_in_frame', {
|
|
541
|
-
tabId: this.
|
|
658
|
+
tabId: this.requireCurrentTabId(),
|
|
542
659
|
frameId,
|
|
543
660
|
expression,
|
|
544
661
|
returnByValue: true,
|
|
@@ -551,10 +668,36 @@ export class ExtensionBridge {
|
|
|
551
668
|
*/
|
|
552
669
|
async resolveFrame(frame) {
|
|
553
670
|
return (await this.httpServer.sendCommand('resolve_frame', {
|
|
554
|
-
tabId: this.
|
|
671
|
+
tabId: this.requireCurrentTabId(),
|
|
555
672
|
frame,
|
|
556
673
|
}));
|
|
557
674
|
}
|
|
675
|
+
requireCurrentTabId() {
|
|
676
|
+
if (this.currentTabId === null) {
|
|
677
|
+
throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
|
|
678
|
+
}
|
|
679
|
+
return this.currentTabId;
|
|
680
|
+
}
|
|
681
|
+
normalizePageChange(result) {
|
|
682
|
+
return {
|
|
683
|
+
targetId: result.targetId,
|
|
684
|
+
windowId: result.windowId,
|
|
685
|
+
before: this.normalizeAffected(result.before),
|
|
686
|
+
after: this.normalizeAffected(result.after),
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
normalizeAffected(value) {
|
|
690
|
+
if (!value) {
|
|
691
|
+
return value;
|
|
692
|
+
}
|
|
693
|
+
if ('url' in value) {
|
|
694
|
+
return this.tabToTarget(value);
|
|
695
|
+
}
|
|
696
|
+
return {
|
|
697
|
+
...value,
|
|
698
|
+
tabs: value.tabs.map((tab) => this.tabToTarget(tab)),
|
|
699
|
+
};
|
|
700
|
+
}
|
|
558
701
|
parseTargetId(targetId) {
|
|
559
702
|
const parsed = parseInt(targetId, 10);
|
|
560
703
|
if (isNaN(parsed)) {
|
|
@@ -562,8 +705,25 @@ export class ExtensionBridge {
|
|
|
562
705
|
}
|
|
563
706
|
return parsed;
|
|
564
707
|
}
|
|
565
|
-
|
|
566
|
-
|
|
708
|
+
tabToTarget(tab) {
|
|
709
|
+
return {
|
|
710
|
+
id: tab.id,
|
|
711
|
+
targetId: String(tab.id),
|
|
712
|
+
url: tab.url,
|
|
713
|
+
title: tab.title,
|
|
714
|
+
type: 'page',
|
|
715
|
+
active: tab.active,
|
|
716
|
+
windowId: tab.windowId,
|
|
717
|
+
index: tab.index,
|
|
718
|
+
groupId: tab.groupId,
|
|
719
|
+
pinned: tab.pinned,
|
|
720
|
+
incognito: tab.incognito,
|
|
721
|
+
managed: tab.managed,
|
|
722
|
+
status: tab.status,
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
updateState(page) {
|
|
726
|
+
this.state = { url: page.url, title: page.title, managed: page.managed };
|
|
567
727
|
}
|
|
568
728
|
}
|
|
569
729
|
//# sourceMappingURL=bridge.js.map
|