@pyrokine/mcp-chrome 1.7.0 → 2.0.1
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 +71 -31
- package/dist/anti-detection/behavior.d.ts.map +1 -1
- package/dist/anti-detection/behavior.js.map +1 -1
- package/dist/anti-detection/index.d.ts +1 -1
- package/dist/anti-detection/index.d.ts.map +1 -1
- package/dist/anti-detection/index.js +1 -1
- package/dist/anti-detection/index.js.map +1 -1
- package/dist/anti-detection/injection.d.ts +6 -2
- package/dist/anti-detection/injection.d.ts.map +1 -1
- package/dist/anti-detection/injection.js +34 -80
- package/dist/anti-detection/injection.js.map +1 -1
- package/dist/cdp/client.d.ts +2 -2
- package/dist/cdp/client.d.ts.map +1 -1
- package/dist/cdp/client.js +8 -10
- package/dist/cdp/client.js.map +1 -1
- package/dist/cdp/index.d.ts.map +1 -1
- package/dist/cdp/index.js.map +1 -1
- package/dist/cdp/launcher.d.ts.map +1 -1
- package/dist/cdp/launcher.js +40 -13
- package/dist/cdp/launcher.js.map +1 -1
- package/dist/core/auto-wait.d.ts +2 -2
- package/dist/core/auto-wait.d.ts.map +1 -1
- package/dist/core/auto-wait.js +2 -2
- package/dist/core/auto-wait.js.map +1 -1
- package/dist/core/browser-driver.d.ts +307 -0
- package/dist/core/browser-driver.d.ts.map +1 -0
- package/dist/core/browser-driver.js +21 -0
- package/dist/core/browser-driver.js.map +1 -0
- package/dist/core/error-sanitizer.d.ts +25 -0
- package/dist/core/error-sanitizer.d.ts.map +1 -0
- package/dist/core/error-sanitizer.js +66 -0
- package/dist/core/error-sanitizer.js.map +1 -0
- package/dist/core/errors.d.ts +10 -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/extension-errors.d.ts +20 -0
- package/dist/core/extension-errors.d.ts.map +1 -0
- package/dist/core/extension-errors.js +40 -0
- package/dist/core/extension-errors.js.map +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/locator.d.ts +2 -2
- package/dist/core/locator.d.ts.map +1 -1
- package/dist/core/locator.js +25 -65
- package/dist/core/locator.js.map +1 -1
- package/dist/core/retry.d.ts +2 -2
- package/dist/core/retry.d.ts.map +1 -1
- package/dist/core/retry.js +2 -2
- package/dist/core/retry.js.map +1 -1
- package/dist/core/session.d.ts +149 -46
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +673 -181
- package/dist/core/session.js.map +1 -1
- package/dist/core/types.d.ts +9 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +13 -6
- package/dist/core/types.js.map +1 -1
- package/dist/core/unified-session.d.ts +46 -85
- package/dist/core/unified-session.d.ts.map +1 -1
- package/dist/core/unified-session.js +341 -650
- package/dist/core/unified-session.js.map +1 -1
- package/dist/core/utils.d.ts +7 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +33 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/extension/bridge.d.ts +69 -52
- package/dist/extension/bridge.d.ts.map +1 -1
- package/dist/extension/bridge.js +242 -111
- package/dist/extension/bridge.js.map +1 -1
- package/dist/extension/http-server.d.ts +6 -4
- package/dist/extension/http-server.d.ts.map +1 -1
- package/dist/extension/http-server.js +45 -31
- package/dist/extension/http-server.js.map +1 -1
- package/dist/extension/index.d.ts.map +1 -1
- package/dist/extension/index.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/browse.d.ts.map +1 -1
- package/dist/tools/browse.js +32 -34
- package/dist/tools/browse.js.map +1 -1
- package/dist/tools/cookies.d.ts.map +1 -1
- package/dist/tools/cookies.js +38 -16
- package/dist/tools/cookies.js.map +1 -1
- package/dist/tools/evaluate.d.ts.map +1 -1
- package/dist/tools/evaluate.js +54 -23
- package/dist/tools/evaluate.js.map +1 -1
- package/dist/tools/extract.d.ts.map +1 -1
- package/dist/tools/extract.js +221 -153
- package/dist/tools/extract.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/input.d.ts.map +1 -1
- package/dist/tools/input.js +281 -89
- package/dist/tools/input.js.map +1 -1
- package/dist/tools/logs.d.ts.map +1 -1
- package/dist/tools/logs.js +31 -17
- package/dist/tools/logs.js.map +1 -1
- package/dist/tools/manage.d.ts.map +1 -1
- package/dist/tools/manage.js +25 -28
- package/dist/tools/manage.js.map +1 -1
- package/dist/tools/schema.d.ts +1 -1
- package/dist/tools/schema.d.ts.map +1 -1
- package/dist/tools/schema.js +31 -55
- package/dist/tools/schema.js.map +1 -1
- package/dist/tools/wait.d.ts.map +1 -1
- package/dist/tools/wait.js +19 -16
- package/dist/tools/wait.js.map +1 -1
- package/package.json +48 -40
package/dist/extension/bridge.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 封装与 Chrome Extension 的通信,提供与 CDP 类似的接口
|
|
5
5
|
* 使用 HTTP + WebSocket 实现
|
|
6
6
|
*/
|
|
7
|
+
import { DriverCapabilityError, } from '../core/browser-driver.js';
|
|
7
8
|
import { ExtensionHttpServer } from './http-server.js';
|
|
8
9
|
/** RPC 传输余量(毫秒):给网络往返和 Extension 处理留出的额外时间 */
|
|
9
10
|
const RPC_MARGIN = 5000;
|
|
@@ -26,8 +27,8 @@ export class ExtensionBridge {
|
|
|
26
27
|
this.httpServer.on('connected', () => {
|
|
27
28
|
if (this.currentTabId !== null) {
|
|
28
29
|
const tabId = this.currentTabId;
|
|
29
|
-
this.httpServer.sendCommand('debugger_attach', { tabId }).catch(() => {
|
|
30
|
-
|
|
30
|
+
this.httpServer.sendCommand('debugger_attach', { tabId }).catch((err) => {
|
|
31
|
+
console.error('[Bridge] 重连后 debugger re-attach 失败:', err.message);
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
34
|
});
|
|
@@ -53,6 +54,25 @@ export class ExtensionBridge {
|
|
|
53
54
|
const result = await this.httpServer.sendCommand('tabs_list', {});
|
|
54
55
|
return result;
|
|
55
56
|
}
|
|
57
|
+
/** IBrowserDriver 接口:列出所有 tab,统一为 ListedTarget 形式(id 字符串化以保持跨 driver 兼容) */
|
|
58
|
+
async listTargets() {
|
|
59
|
+
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
|
+
}
|
|
56
76
|
async createTab(url, timeout) {
|
|
57
77
|
const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
|
|
58
78
|
const result = await this.httpServer.sendCommand('tabs_create', {
|
|
@@ -67,6 +87,16 @@ export class ExtensionBridge {
|
|
|
67
87
|
this.updateState(tab.url, tab.title);
|
|
68
88
|
return tab;
|
|
69
89
|
}
|
|
90
|
+
/** IBrowserDriver 接口:新建页面(targetId 为字符串化的 chrome tab id) */
|
|
91
|
+
async newPage(url, timeout) {
|
|
92
|
+
const tab = await this.createTab(url, timeout);
|
|
93
|
+
return {
|
|
94
|
+
targetId: String(tab.id),
|
|
95
|
+
url: tab.url,
|
|
96
|
+
title: tab.title,
|
|
97
|
+
type: 'page',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
70
100
|
async closeTab(tabId) {
|
|
71
101
|
await this.httpServer.sendCommand('tabs_close', { tabId });
|
|
72
102
|
if (this.currentTabId === tabId) {
|
|
@@ -74,131 +104,164 @@ export class ExtensionBridge {
|
|
|
74
104
|
this.state = null;
|
|
75
105
|
}
|
|
76
106
|
}
|
|
107
|
+
/** IBrowserDriver 接口:关闭页面(targetId 是 chrome tab id 的字符串形式,省略时关闭当前 tab) */
|
|
108
|
+
async closePage(targetId) {
|
|
109
|
+
const tabId = targetId !== undefined ? this.parseTargetId(targetId) : this.currentTabId;
|
|
110
|
+
if (tabId === null) {
|
|
111
|
+
throw new DriverCapabilityError('没有可关闭的页面,请指定 targetId');
|
|
112
|
+
}
|
|
113
|
+
await this.closeTab(tabId);
|
|
114
|
+
}
|
|
77
115
|
async activateTab(tabId) {
|
|
78
116
|
const result = await this.httpServer.sendCommand('tabs_activate', { tabId });
|
|
79
117
|
const tab = result;
|
|
80
118
|
this.currentTabId = tab.id;
|
|
81
119
|
this.updateState(tab.url, tab.title);
|
|
82
120
|
}
|
|
83
|
-
|
|
121
|
+
/** IBrowserDriver 接口:激活页面(切到前台) */
|
|
122
|
+
async activatePage(targetId) {
|
|
123
|
+
const tabId = this.parseTargetId(targetId);
|
|
124
|
+
await this.activateTab(tabId);
|
|
125
|
+
}
|
|
126
|
+
/** IBrowserDriver 接口:选择操作目标 tab(不切换前台,只设置当前 currentTabId) */
|
|
127
|
+
async selectPage(targetId) {
|
|
128
|
+
this.currentTabId = this.parseTargetId(targetId);
|
|
129
|
+
}
|
|
130
|
+
/** IBrowserDriver 接口:获取当前操作目标 ID(chrome tab id 的字符串形式) */
|
|
131
|
+
getCurrentTargetId() {
|
|
132
|
+
return this.currentTabId !== null ? String(this.currentTabId) : null;
|
|
133
|
+
}
|
|
134
|
+
/** IBrowserDriver 接口:设置当前操作目标 ID */
|
|
135
|
+
setCurrentTargetId(targetId) {
|
|
136
|
+
this.currentTabId = targetId !== null ? this.parseTargetId(targetId) : null;
|
|
137
|
+
}
|
|
84
138
|
async navigate(url, options) {
|
|
85
139
|
const rpcTimeout = options?.timeout !== undefined ? options.timeout + RPC_MARGIN : undefined;
|
|
86
|
-
const
|
|
87
|
-
tabId: this.currentTabId,
|
|
140
|
+
const params = {
|
|
88
141
|
url,
|
|
89
|
-
waitUntil: options?.
|
|
142
|
+
waitUntil: options?.wait ?? 'load',
|
|
90
143
|
timeout: options?.timeout,
|
|
91
|
-
}
|
|
144
|
+
};
|
|
145
|
+
if (this.currentTabId !== null) {
|
|
146
|
+
params.tabId = this.currentTabId;
|
|
147
|
+
}
|
|
148
|
+
const result = await this.httpServer.sendCommand('navigate', params, rpcTimeout);
|
|
92
149
|
const tab = result;
|
|
150
|
+
this.currentTabId = tab.id;
|
|
93
151
|
this.updateState(tab.url, tab.title);
|
|
94
152
|
}
|
|
153
|
+
// ==================== 导航操作 ====================
|
|
95
154
|
async goBack(timeout) {
|
|
96
155
|
// 默认:NAV_SIGNAL_WINDOW + 导航等待(默认 30s)+ RPC_MARGIN = 40s
|
|
97
156
|
// 调用方传 timeout 时:timeout 即导航超时 + 信号窗口 + 传输余量
|
|
98
|
-
const rpcTimeout = timeout !== undefined ?
|
|
99
|
-
|
|
100
|
-
30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
|
|
101
|
-
const result = await this.httpServer.sendCommand('go_back', {
|
|
102
|
-
tabId: this.currentTabId,
|
|
157
|
+
const rpcTimeout = timeout !== undefined ? timeout + NAV_SIGNAL_WINDOW + RPC_MARGIN : 30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
|
|
158
|
+
const params = {
|
|
103
159
|
waitUntil: 'load',
|
|
104
160
|
timeout,
|
|
105
|
-
}
|
|
161
|
+
};
|
|
162
|
+
if (this.currentTabId !== null) {
|
|
163
|
+
params.tabId = this.currentTabId;
|
|
164
|
+
}
|
|
165
|
+
const result = (await this.httpServer.sendCommand('go_back', params, rpcTimeout));
|
|
106
166
|
this.updateState(result.url, result.title);
|
|
107
167
|
return result;
|
|
108
168
|
}
|
|
109
169
|
async goForward(timeout) {
|
|
110
170
|
// 默认:NAV_SIGNAL_WINDOW + 导航等待(默认 30s)+ RPC_MARGIN = 40s
|
|
111
171
|
// 调用方传 timeout 时:timeout 即导航超时 + 信号窗口 + 传输余量
|
|
112
|
-
const rpcTimeout = timeout !== undefined ?
|
|
113
|
-
|
|
114
|
-
30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
|
|
115
|
-
const result = await this.httpServer.sendCommand('go_forward', {
|
|
116
|
-
tabId: this.currentTabId,
|
|
172
|
+
const rpcTimeout = timeout !== undefined ? timeout + NAV_SIGNAL_WINDOW + RPC_MARGIN : 30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
|
|
173
|
+
const params = {
|
|
117
174
|
waitUntil: 'load',
|
|
118
175
|
timeout,
|
|
119
|
-
}
|
|
176
|
+
};
|
|
177
|
+
if (this.currentTabId !== null) {
|
|
178
|
+
params.tabId = this.currentTabId;
|
|
179
|
+
}
|
|
180
|
+
const result = (await this.httpServer.sendCommand('go_forward', params, rpcTimeout));
|
|
120
181
|
this.updateState(result.url, result.title);
|
|
121
182
|
return result;
|
|
122
183
|
}
|
|
123
184
|
async reload(ignoreCache = false, waitUntil, timeout) {
|
|
124
185
|
const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
|
|
125
|
-
const
|
|
126
|
-
tabId: this.currentTabId,
|
|
186
|
+
const params = {
|
|
127
187
|
ignoreCache,
|
|
128
188
|
waitUntil: waitUntil ?? 'load',
|
|
129
189
|
timeout,
|
|
130
|
-
}
|
|
190
|
+
};
|
|
191
|
+
if (this.currentTabId !== null) {
|
|
192
|
+
params.tabId = this.currentTabId;
|
|
193
|
+
}
|
|
194
|
+
const result = await this.httpServer.sendCommand('reload', params, rpcTimeout);
|
|
131
195
|
const tab = result;
|
|
132
196
|
this.updateState(tab.url, tab.title);
|
|
133
197
|
}
|
|
134
|
-
// ==================== 页面内容 ====================
|
|
135
198
|
async readPage(options) {
|
|
136
|
-
return await this.httpServer.sendCommand('read_page', {
|
|
199
|
+
return (await this.httpServer.sendCommand('read_page', {
|
|
137
200
|
tabId: this.currentTabId,
|
|
138
201
|
frameId: this.currentFrameId || undefined,
|
|
139
202
|
...options,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
async screenshot(options) {
|
|
143
|
-
return await this.httpServer.sendCommand('screenshot', {
|
|
144
|
-
tabId: this.currentTabId,
|
|
145
|
-
...options,
|
|
146
|
-
});
|
|
203
|
+
}));
|
|
147
204
|
}
|
|
148
|
-
// ====================
|
|
205
|
+
// ==================== 页面内容 ====================
|
|
149
206
|
async click(refId) {
|
|
150
|
-
const result = await this.httpServer.sendCommand('click', {
|
|
207
|
+
const result = (await this.httpServer.sendCommand('click', {
|
|
151
208
|
tabId: this.currentTabId,
|
|
152
209
|
frameId: this.currentFrameId || undefined,
|
|
153
210
|
refId,
|
|
154
|
-
});
|
|
211
|
+
}));
|
|
155
212
|
if (!result.success) {
|
|
156
213
|
throw new Error(result.error || 'Click failed');
|
|
157
214
|
}
|
|
158
215
|
}
|
|
216
|
+
// ==================== DOM 操作 ====================
|
|
159
217
|
async actionableClick(refId, force) {
|
|
160
|
-
return await this.httpServer.sendCommand('actionable_click', {
|
|
218
|
+
return (await this.httpServer.sendCommand('actionable_click', {
|
|
161
219
|
tabId: this.currentTabId,
|
|
162
220
|
frameId: this.currentFrameId || undefined,
|
|
163
221
|
refId,
|
|
164
222
|
force: force ?? false,
|
|
165
|
-
});
|
|
223
|
+
}));
|
|
166
224
|
}
|
|
167
|
-
async
|
|
168
|
-
return await this.httpServer.sendCommand('
|
|
225
|
+
async dispatchInput(refId, text) {
|
|
226
|
+
return (await this.httpServer.sendCommand('dispatch_input', {
|
|
169
227
|
tabId: this.currentTabId,
|
|
170
228
|
frameId: this.currentFrameId || undefined,
|
|
171
229
|
refId,
|
|
172
|
-
|
|
230
|
+
text,
|
|
231
|
+
}));
|
|
173
232
|
}
|
|
174
|
-
async
|
|
175
|
-
return await this.httpServer.sendCommand('
|
|
233
|
+
async dragAndDrop(srcRefId, dstRefId) {
|
|
234
|
+
return (await this.httpServer.sendCommand('drag_and_drop', {
|
|
176
235
|
tabId: this.currentTabId,
|
|
177
236
|
frameId: this.currentFrameId || undefined,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
});
|
|
237
|
+
srcRefId,
|
|
238
|
+
dstRefId,
|
|
239
|
+
}));
|
|
181
240
|
}
|
|
182
241
|
async getComputedStyle(refId, prop) {
|
|
183
|
-
return await this.httpServer.sendCommand('get_computed_style', {
|
|
242
|
+
return (await this.httpServer.sendCommand('get_computed_style', {
|
|
184
243
|
tabId: this.currentTabId,
|
|
185
244
|
frameId: this.currentFrameId || undefined,
|
|
186
245
|
refId,
|
|
187
246
|
prop,
|
|
188
|
-
});
|
|
247
|
+
}));
|
|
189
248
|
}
|
|
190
249
|
async type(refId, text, clear = false) {
|
|
191
|
-
const result = await this.httpServer.sendCommand('type', {
|
|
250
|
+
const result = (await this.httpServer.sendCommand('type', {
|
|
192
251
|
tabId: this.currentTabId,
|
|
193
252
|
frameId: this.currentFrameId || undefined,
|
|
194
253
|
refId,
|
|
195
254
|
text,
|
|
196
255
|
clear,
|
|
197
|
-
});
|
|
256
|
+
}));
|
|
198
257
|
if (!result.success) {
|
|
199
258
|
throw new Error(result.error || 'Type failed');
|
|
200
259
|
}
|
|
201
260
|
}
|
|
261
|
+
/** IBrowserDriver 接口别名(避开与字段名冲突的命名歧义) */
|
|
262
|
+
typeRef(refId, text, clear = false) {
|
|
263
|
+
return this.type(refId, text, clear);
|
|
264
|
+
}
|
|
202
265
|
async scroll(x, y, refId) {
|
|
203
266
|
await this.httpServer.sendCommand('scroll', {
|
|
204
267
|
tabId: this.currentTabId,
|
|
@@ -208,84 +271,122 @@ export class ExtensionBridge {
|
|
|
208
271
|
refId,
|
|
209
272
|
});
|
|
210
273
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
274
|
+
/** IBrowserDriver 接口别名 */
|
|
275
|
+
scrollAt(x, y, refId) {
|
|
276
|
+
return this.scroll(x, y, refId);
|
|
277
|
+
}
|
|
278
|
+
async evaluate(code, _args, timeout) {
|
|
279
|
+
// _args 参数仅满足 IBrowserDriver 接口签名;ExtensionBridge 不消费 args(stealth 路径上层已字符串拼接)
|
|
280
|
+
const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
|
|
281
|
+
const result = (await this.httpServer.sendCommand('evaluate', {
|
|
215
282
|
tabId: this.currentTabId,
|
|
216
283
|
frameId: this.currentFrameId || undefined,
|
|
217
284
|
code,
|
|
218
285
|
timeout,
|
|
219
|
-
}, rpcTimeout);
|
|
286
|
+
}, rpcTimeout));
|
|
220
287
|
if (!result.success) {
|
|
221
288
|
throw new Error(result.error || 'Evaluate failed');
|
|
222
289
|
}
|
|
223
|
-
|
|
290
|
+
if (!result.result) {
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
return JSON.parse(result.result);
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
throw new Error(`evaluate 结果 JSON 解析失败: ${err}`);
|
|
298
|
+
}
|
|
224
299
|
}
|
|
225
300
|
async find(selector, text, xpath, timeout) {
|
|
226
|
-
return await this.httpServer.sendCommand('find', {
|
|
301
|
+
return (await this.httpServer.sendCommand('find', {
|
|
227
302
|
tabId: this.currentTabId,
|
|
228
303
|
frameId: this.currentFrameId || undefined,
|
|
229
304
|
selector,
|
|
230
305
|
text,
|
|
231
306
|
xpath,
|
|
232
|
-
}, timeout);
|
|
307
|
+
}, timeout));
|
|
233
308
|
}
|
|
234
309
|
async getText(selector) {
|
|
235
|
-
const result = await this.httpServer.sendCommand('get_text', {
|
|
310
|
+
const result = (await this.httpServer.sendCommand('get_text', {
|
|
236
311
|
tabId: this.currentTabId,
|
|
237
312
|
frameId: this.currentFrameId || undefined,
|
|
238
313
|
selector,
|
|
239
|
-
});
|
|
314
|
+
}));
|
|
240
315
|
return result.text;
|
|
241
316
|
}
|
|
242
317
|
async getHtml(selector, outer = true) {
|
|
243
|
-
const result = await this.httpServer.sendCommand('get_html', {
|
|
318
|
+
const result = (await this.httpServer.sendCommand('get_html', {
|
|
244
319
|
tabId: this.currentTabId,
|
|
245
320
|
frameId: this.currentFrameId || undefined,
|
|
246
321
|
selector,
|
|
247
322
|
outer,
|
|
248
|
-
});
|
|
323
|
+
}));
|
|
249
324
|
return result.html;
|
|
250
325
|
}
|
|
326
|
+
getPageHtml(selector, outer = true) {
|
|
327
|
+
return this.getHtml(selector, outer);
|
|
328
|
+
}
|
|
329
|
+
getPageText(selector) {
|
|
330
|
+
return this.getText(selector);
|
|
331
|
+
}
|
|
332
|
+
async getConsoleLogs(options = {}) {
|
|
333
|
+
const messages = await this.consoleGet(options);
|
|
334
|
+
return messages;
|
|
335
|
+
}
|
|
336
|
+
async getNetworkRequests(options = {}) {
|
|
337
|
+
const requests = await this.networkGet(options);
|
|
338
|
+
return requests;
|
|
339
|
+
}
|
|
340
|
+
async screenshot(options) {
|
|
341
|
+
return (await this.httpServer.sendCommand('screenshot', {
|
|
342
|
+
tabId: this.currentTabId,
|
|
343
|
+
...options,
|
|
344
|
+
}));
|
|
345
|
+
}
|
|
251
346
|
async getHtmlWithImages(selector, outer = true) {
|
|
252
|
-
return await this.httpServer.sendCommand('get_html_with_images', {
|
|
347
|
+
return (await this.httpServer.sendCommand('get_html_with_images', {
|
|
253
348
|
tabId: this.currentTabId,
|
|
254
349
|
frameId: this.currentFrameId || undefined,
|
|
255
350
|
selector,
|
|
256
351
|
outer,
|
|
257
|
-
});
|
|
352
|
+
}));
|
|
258
353
|
}
|
|
259
354
|
async getAttribute(selector, refId, attribute) {
|
|
260
|
-
const result = await this.httpServer.sendCommand('get_attribute', {
|
|
355
|
+
const result = (await this.httpServer.sendCommand('get_attribute', {
|
|
261
356
|
tabId: this.currentTabId,
|
|
262
357
|
frameId: this.currentFrameId || undefined,
|
|
263
358
|
selector,
|
|
264
359
|
refId,
|
|
265
360
|
attribute,
|
|
266
|
-
});
|
|
361
|
+
}));
|
|
267
362
|
return result.value;
|
|
268
363
|
}
|
|
269
364
|
async getMetadata() {
|
|
270
|
-
return await this.httpServer.sendCommand('get_metadata', {
|
|
365
|
+
return (await this.httpServer.sendCommand('get_metadata', {
|
|
271
366
|
tabId: this.currentTabId,
|
|
272
367
|
frameId: this.currentFrameId || undefined,
|
|
273
|
-
});
|
|
368
|
+
}));
|
|
274
369
|
}
|
|
275
|
-
// ==================== Cookies ====================
|
|
276
370
|
async getCookies(filter) {
|
|
277
|
-
return await this.httpServer.sendCommand('cookies_get', filter ?? {});
|
|
371
|
+
return (await this.httpServer.sendCommand('cookies_get', filter ?? {}));
|
|
278
372
|
}
|
|
373
|
+
// ==================== Cookies ====================
|
|
279
374
|
async setCookie(params) {
|
|
280
|
-
|
|
375
|
+
const sameSiteMap = { None: 'no_restriction', Lax: 'lax', Strict: 'strict' };
|
|
376
|
+
const chromeSameSite = params.sameSite ? (sameSiteMap[params.sameSite] ?? params.sameSite) : undefined;
|
|
377
|
+
const url = params.url ?? this.state?.url ?? 'http://localhost';
|
|
378
|
+
await this.httpServer.sendCommand('cookies_set', {
|
|
379
|
+
...params,
|
|
380
|
+
url,
|
|
381
|
+
...(chromeSameSite !== undefined && { sameSite: chromeSameSite }),
|
|
382
|
+
});
|
|
281
383
|
}
|
|
282
384
|
async deleteCookie(url, name) {
|
|
283
385
|
await this.httpServer.sendCommand('cookies_delete', { url, name });
|
|
284
386
|
}
|
|
285
387
|
async clearCookies(filter) {
|
|
286
|
-
return await this.httpServer.sendCommand('cookies_clear', filter ?? {});
|
|
388
|
+
return (await this.httpServer.sendCommand('cookies_clear', filter ?? {}));
|
|
287
389
|
}
|
|
288
|
-
// ==================== Debugger (CDP via Extension) ====================
|
|
289
390
|
async debuggerSend(method, params, tabId, timeout) {
|
|
290
391
|
return await this.httpServer.sendCommand('debugger_send', {
|
|
291
392
|
tabId: tabId ?? this.currentTabId,
|
|
@@ -293,7 +394,7 @@ export class ExtensionBridge {
|
|
|
293
394
|
params,
|
|
294
395
|
}, timeout);
|
|
295
396
|
}
|
|
296
|
-
// ====================
|
|
397
|
+
// ==================== Debugger (CDP via Extension) ====================
|
|
297
398
|
async inputKey(type, options = {}) {
|
|
298
399
|
await this.httpServer.sendCommand('input_key', {
|
|
299
400
|
tabId: this.currentTabId,
|
|
@@ -301,6 +402,7 @@ export class ExtensionBridge {
|
|
|
301
402
|
...options,
|
|
302
403
|
});
|
|
303
404
|
}
|
|
405
|
+
// ==================== 输入事件(通过 CDP)====================
|
|
304
406
|
async inputMouse(type, x, y, options = {}) {
|
|
305
407
|
await this.httpServer.sendCommand('input_mouse', {
|
|
306
408
|
tabId: this.currentTabId,
|
|
@@ -324,85 +426,107 @@ export class ExtensionBridge {
|
|
|
324
426
|
delay,
|
|
325
427
|
});
|
|
326
428
|
}
|
|
327
|
-
// ==================== 控制台日志 ====================
|
|
328
429
|
async consoleEnable() {
|
|
329
430
|
await this.httpServer.sendCommand('console_enable', {
|
|
330
431
|
tabId: this.currentTabId,
|
|
331
432
|
});
|
|
332
433
|
}
|
|
434
|
+
// ==================== 控制台日志 ====================
|
|
333
435
|
async consoleGet(options = {}) {
|
|
334
|
-
const result = await this.httpServer.sendCommand('console_get', {
|
|
436
|
+
const result = (await this.httpServer.sendCommand('console_get', {
|
|
335
437
|
tabId: this.currentTabId,
|
|
336
438
|
...options,
|
|
337
|
-
});
|
|
439
|
+
}));
|
|
338
440
|
return result.messages;
|
|
339
441
|
}
|
|
340
|
-
// ==================== 网络日志 ====================
|
|
341
442
|
async networkEnable() {
|
|
342
443
|
await this.httpServer.sendCommand('network_enable', {
|
|
343
444
|
tabId: this.currentTabId,
|
|
344
445
|
});
|
|
345
446
|
}
|
|
447
|
+
// ==================== 网络日志 ====================
|
|
346
448
|
async networkGet(options = {}) {
|
|
347
|
-
const result = await this.httpServer.sendCommand('network_get', {
|
|
449
|
+
const result = (await this.httpServer.sendCommand('network_get', {
|
|
348
450
|
tabId: this.currentTabId,
|
|
349
451
|
...options,
|
|
350
|
-
});
|
|
452
|
+
}));
|
|
351
453
|
return result.requests;
|
|
352
454
|
}
|
|
353
|
-
// ==================== Stealth 模式(JS 事件模拟,无 debugger)====================
|
|
354
455
|
async stealthType(text, delay = 0) {
|
|
355
|
-
|
|
356
|
-
tabId: this.currentTabId,
|
|
357
|
-
frameId: this.currentFrameId || undefined,
|
|
456
|
+
const params = {
|
|
358
457
|
text,
|
|
359
458
|
delay,
|
|
360
|
-
}
|
|
459
|
+
};
|
|
460
|
+
if (this.currentTabId !== null) {
|
|
461
|
+
params.tabId = this.currentTabId;
|
|
462
|
+
}
|
|
463
|
+
if (this.currentFrameId !== null) {
|
|
464
|
+
params.frameId = this.currentFrameId;
|
|
465
|
+
}
|
|
466
|
+
await this.httpServer.sendCommand('stealth_type', params);
|
|
361
467
|
}
|
|
468
|
+
// ==================== Stealth 模式(JS 事件模拟,无 debugger)====================
|
|
362
469
|
async stealthKey(key, type = 'press', modifiers = []) {
|
|
363
|
-
|
|
364
|
-
tabId: this.currentTabId,
|
|
365
|
-
frameId: this.currentFrameId || undefined,
|
|
470
|
+
const params = {
|
|
366
471
|
key,
|
|
367
472
|
type,
|
|
368
473
|
modifiers,
|
|
369
|
-
}
|
|
474
|
+
};
|
|
475
|
+
if (this.currentTabId !== null) {
|
|
476
|
+
params.tabId = this.currentTabId;
|
|
477
|
+
}
|
|
478
|
+
if (this.currentFrameId !== null) {
|
|
479
|
+
params.frameId = this.currentFrameId;
|
|
480
|
+
}
|
|
481
|
+
await this.httpServer.sendCommand('stealth_key', params);
|
|
370
482
|
}
|
|
371
|
-
async stealthClick(x, y, button = 'left') {
|
|
372
|
-
|
|
373
|
-
tabId: this.currentTabId,
|
|
374
|
-
frameId: this.currentFrameId || undefined,
|
|
483
|
+
async stealthClick(x, y, button = 'left', clickCount = 1, refId) {
|
|
484
|
+
const params = {
|
|
375
485
|
x,
|
|
376
486
|
y,
|
|
377
487
|
button,
|
|
378
|
-
|
|
488
|
+
clickCount,
|
|
489
|
+
};
|
|
490
|
+
if (this.currentTabId !== null) {
|
|
491
|
+
params.tabId = this.currentTabId;
|
|
492
|
+
}
|
|
493
|
+
if (this.currentFrameId !== null) {
|
|
494
|
+
params.frameId = this.currentFrameId;
|
|
495
|
+
}
|
|
496
|
+
if (typeof refId === 'string') {
|
|
497
|
+
params.refId = refId;
|
|
498
|
+
}
|
|
499
|
+
await this.httpServer.sendCommand('stealth_click', params);
|
|
379
500
|
}
|
|
380
501
|
async stealthMouse(type, x, y, button = 'left') {
|
|
381
|
-
|
|
382
|
-
tabId: this.currentTabId,
|
|
383
|
-
frameId: this.currentFrameId || undefined,
|
|
502
|
+
const params = {
|
|
384
503
|
type,
|
|
385
504
|
x,
|
|
386
505
|
y,
|
|
387
506
|
button,
|
|
388
|
-
}
|
|
507
|
+
};
|
|
508
|
+
if (this.currentTabId !== null) {
|
|
509
|
+
params.tabId = this.currentTabId;
|
|
510
|
+
}
|
|
511
|
+
if (this.currentFrameId !== null) {
|
|
512
|
+
params.frameId = this.currentFrameId;
|
|
513
|
+
}
|
|
514
|
+
await this.httpServer.sendCommand('stealth_mouse', params);
|
|
389
515
|
}
|
|
390
516
|
async stealthInject() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
517
|
+
const params = {};
|
|
518
|
+
if (this.currentTabId !== null) {
|
|
519
|
+
params.tabId = this.currentTabId;
|
|
520
|
+
}
|
|
521
|
+
if (this.currentFrameId !== null) {
|
|
522
|
+
params.frameId = this.currentFrameId;
|
|
523
|
+
}
|
|
524
|
+
await this.httpServer.sendCommand('stealth_inject', params);
|
|
395
525
|
}
|
|
396
|
-
// ==================== 状态管理 ====================
|
|
397
526
|
getState() {
|
|
398
527
|
return this.state;
|
|
399
528
|
}
|
|
400
|
-
|
|
401
|
-
return this.currentTabId;
|
|
402
|
-
}
|
|
403
|
-
setCurrentTabId(tabId) {
|
|
404
|
-
this.currentTabId = tabId;
|
|
405
|
-
}
|
|
529
|
+
// ==================== 状态管理 ====================
|
|
406
530
|
getCurrentFrameId() {
|
|
407
531
|
return this.currentFrameId;
|
|
408
532
|
}
|
|
@@ -413,23 +537,30 @@ export class ExtensionBridge {
|
|
|
413
537
|
* 在指定 iframe 中以 precise 模式执行 JS(通过 contextId 绕过 CSP)
|
|
414
538
|
*/
|
|
415
539
|
async evaluateInFrame(frameId, expression, timeout) {
|
|
416
|
-
return await this.httpServer.sendCommand('evaluate_in_frame', {
|
|
540
|
+
return (await this.httpServer.sendCommand('evaluate_in_frame', {
|
|
417
541
|
tabId: this.currentTabId,
|
|
418
542
|
frameId,
|
|
419
543
|
expression,
|
|
420
544
|
returnByValue: true,
|
|
421
545
|
awaitPromise: true,
|
|
422
546
|
timeout,
|
|
423
|
-
}, timeout);
|
|
547
|
+
}, timeout));
|
|
424
548
|
}
|
|
425
549
|
/**
|
|
426
550
|
* 解析 iframe 选择器/索引 → frameId
|
|
427
551
|
*/
|
|
428
552
|
async resolveFrame(frame) {
|
|
429
|
-
return await this.httpServer.sendCommand('resolve_frame', {
|
|
553
|
+
return (await this.httpServer.sendCommand('resolve_frame', {
|
|
430
554
|
tabId: this.currentTabId,
|
|
431
555
|
frame,
|
|
432
|
-
});
|
|
556
|
+
}));
|
|
557
|
+
}
|
|
558
|
+
parseTargetId(targetId) {
|
|
559
|
+
const parsed = parseInt(targetId, 10);
|
|
560
|
+
if (isNaN(parsed)) {
|
|
561
|
+
throw new DriverCapabilityError(`无效的 Tab ID: ${targetId}`);
|
|
562
|
+
}
|
|
563
|
+
return parsed;
|
|
433
564
|
}
|
|
434
565
|
updateState(url, title) {
|
|
435
566
|
this.state = { url, title };
|