@pyrokine/mcp-chrome 2.0.2 → 2.2.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.
Files changed (80) hide show
  1. package/README.md +86 -35
  2. package/README_zh.md +570 -0
  3. package/dist/cdp/launcher.d.ts.map +1 -1
  4. package/dist/cdp/launcher.js +41 -19
  5. package/dist/cdp/launcher.js.map +1 -1
  6. package/dist/core/browser-driver.d.ts +118 -1
  7. package/dist/core/browser-driver.d.ts.map +1 -1
  8. package/dist/core/browser-driver.js +11 -0
  9. package/dist/core/browser-driver.js.map +1 -1
  10. package/dist/core/error-sanitizer.js +2 -2
  11. package/dist/core/error-sanitizer.js.map +1 -1
  12. package/dist/core/errors.d.ts.map +1 -1
  13. package/dist/core/errors.js +17 -4
  14. package/dist/core/errors.js.map +1 -1
  15. package/dist/core/index.d.ts +1 -1
  16. package/dist/core/index.d.ts.map +1 -1
  17. package/dist/core/index.js +1 -1
  18. package/dist/core/index.js.map +1 -1
  19. package/dist/core/locator.d.ts.map +1 -1
  20. package/dist/core/locator.js +4 -3
  21. package/dist/core/locator.js.map +1 -1
  22. package/dist/core/session.d.ts +5 -2
  23. package/dist/core/session.d.ts.map +1 -1
  24. package/dist/core/session.js +107 -4
  25. package/dist/core/session.js.map +1 -1
  26. package/dist/core/types.d.ts +24 -1
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/core/types.js +77 -4
  29. package/dist/core/types.js.map +1 -1
  30. package/dist/core/unified-session.d.ts +38 -9
  31. package/dist/core/unified-session.d.ts.map +1 -1
  32. package/dist/core/unified-session.js +291 -18
  33. package/dist/core/unified-session.js.map +1 -1
  34. package/dist/core/utils.d.ts +1 -0
  35. package/dist/core/utils.d.ts.map +1 -1
  36. package/dist/core/utils.js +35 -7
  37. package/dist/core/utils.js.map +1 -1
  38. package/dist/extension/bridge.d.ts +37 -22
  39. package/dist/extension/bridge.d.ts.map +1 -1
  40. package/dist/extension/bridge.js +223 -63
  41. package/dist/extension/bridge.js.map +1 -1
  42. package/dist/extension/http-server.d.ts +6 -0
  43. package/dist/extension/http-server.d.ts.map +1 -1
  44. package/dist/extension/http-server.js +125 -14
  45. package/dist/extension/http-server.js.map +1 -1
  46. package/dist/tools/browse.d.ts.map +1 -1
  47. package/dist/tools/browse.js +153 -54
  48. package/dist/tools/browse.js.map +1 -1
  49. package/dist/tools/cookies.d.ts.map +1 -1
  50. package/dist/tools/cookies.js +2 -4
  51. package/dist/tools/cookies.js.map +1 -1
  52. package/dist/tools/evaluate.d.ts.map +1 -1
  53. package/dist/tools/evaluate.js +37 -10
  54. package/dist/tools/evaluate.js.map +1 -1
  55. package/dist/tools/extract.d.ts +1 -0
  56. package/dist/tools/extract.d.ts.map +1 -1
  57. package/dist/tools/extract.js +466 -227
  58. package/dist/tools/extract.js.map +1 -1
  59. package/dist/tools/input.d.ts.map +1 -1
  60. package/dist/tools/input.js +781 -444
  61. package/dist/tools/input.js.map +1 -1
  62. package/dist/tools/logs.d.ts.map +1 -1
  63. package/dist/tools/logs.js +75 -23
  64. package/dist/tools/logs.js.map +1 -1
  65. package/dist/tools/manage.d.ts +0 -3
  66. package/dist/tools/manage.d.ts.map +1 -1
  67. package/dist/tools/manage.js +339 -285
  68. package/dist/tools/manage.js.map +1 -1
  69. package/dist/tools/png.d.ts +16 -0
  70. package/dist/tools/png.d.ts.map +1 -0
  71. package/dist/tools/png.js +197 -0
  72. package/dist/tools/png.js.map +1 -0
  73. package/dist/tools/schema.d.ts +14 -112
  74. package/dist/tools/schema.d.ts.map +1 -1
  75. package/dist/tools/schema.js +21 -12
  76. package/dist/tools/schema.js.map +1 -1
  77. package/dist/tools/wait.d.ts.map +1 -1
  78. package/dist/tools/wait.js +73 -13
  79. package/dist/tools/wait.js.map +1 -1
  80. package/package.json +16 -13
@@ -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.url, tab.title);
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
- await this.closeTab(tabId);
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.url, tab.title);
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
- this.currentTabId = this.parseTargetId(targetId);
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,6 +235,9 @@ 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) {
139
243
  if (this.currentTabId === null) {
@@ -141,7 +245,7 @@ export class ExtensionBridge {
141
245
  }
142
246
  const rpcTimeout = options?.timeout !== undefined ? options.timeout + RPC_MARGIN : undefined;
143
247
  const params = {
144
- tabId: this.currentTabId,
248
+ tabId: this.requireCurrentTabId(),
145
249
  url,
146
250
  waitUntil: options?.wait ?? 'load',
147
251
  timeout: options?.timeout,
@@ -149,7 +253,7 @@ export class ExtensionBridge {
149
253
  const result = await this.httpServer.sendCommand('navigate', params, rpcTimeout);
150
254
  const tab = result;
151
255
  this.currentTabId = tab.id;
152
- this.updateState(tab.url, tab.title);
256
+ this.updateState(tab);
153
257
  }
154
258
  // ==================== 导航操作 ====================
155
259
  async goBack(timeout) {
@@ -160,12 +264,12 @@ export class ExtensionBridge {
160
264
  // 调用方传 timeout 时:timeout 即导航超时 + 信号窗口 + 传输余量
161
265
  const rpcTimeout = timeout !== undefined ? timeout + NAV_SIGNAL_WINDOW + RPC_MARGIN : 30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
162
266
  const params = {
163
- tabId: this.currentTabId,
267
+ tabId: this.requireCurrentTabId(),
164
268
  waitUntil: 'load',
165
269
  timeout,
166
270
  };
167
271
  const result = (await this.httpServer.sendCommand('go_back', params, rpcTimeout));
168
- this.updateState(result.url, result.title);
272
+ this.updateState(result);
169
273
  return result;
170
274
  }
171
275
  async goForward(timeout) {
@@ -176,12 +280,12 @@ export class ExtensionBridge {
176
280
  // 调用方传 timeout 时:timeout 即导航超时 + 信号窗口 + 传输余量
177
281
  const rpcTimeout = timeout !== undefined ? timeout + NAV_SIGNAL_WINDOW + RPC_MARGIN : 30000 + NAV_SIGNAL_WINDOW + RPC_MARGIN;
178
282
  const params = {
179
- tabId: this.currentTabId,
283
+ tabId: this.requireCurrentTabId(),
180
284
  waitUntil: 'load',
181
285
  timeout,
182
286
  };
183
287
  const result = (await this.httpServer.sendCommand('go_forward', params, rpcTimeout));
184
- this.updateState(result.url, result.title);
288
+ this.updateState(result);
185
289
  return result;
186
290
  }
187
291
  async reload(ignoreCache = false, waitUntil, timeout) {
@@ -190,18 +294,18 @@ export class ExtensionBridge {
190
294
  }
191
295
  const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
192
296
  const params = {
193
- tabId: this.currentTabId,
297
+ tabId: this.requireCurrentTabId(),
194
298
  ignoreCache,
195
299
  waitUntil: waitUntil ?? 'load',
196
300
  timeout,
197
301
  };
198
302
  const result = await this.httpServer.sendCommand('reload', params, rpcTimeout);
199
303
  const tab = result;
200
- this.updateState(tab.url, tab.title);
304
+ this.updateState(tab);
201
305
  }
202
306
  async readPage(options) {
203
307
  return (await this.httpServer.sendCommand('read_page', {
204
- tabId: this.currentTabId,
308
+ tabId: this.requireCurrentTabId(),
205
309
  frameId: this.currentFrameId || undefined,
206
310
  ...options,
207
311
  }));
@@ -209,7 +313,7 @@ export class ExtensionBridge {
209
313
  // ==================== 页面内容 ====================
210
314
  async click(refId) {
211
315
  const result = (await this.httpServer.sendCommand('click', {
212
- tabId: this.currentTabId,
316
+ tabId: this.requireCurrentTabId(),
213
317
  frameId: this.currentFrameId || undefined,
214
318
  refId,
215
319
  }));
@@ -220,15 +324,23 @@ export class ExtensionBridge {
220
324
  // ==================== DOM 操作 ====================
221
325
  async actionableClick(refId, force) {
222
326
  return (await this.httpServer.sendCommand('actionable_click', {
223
- tabId: this.currentTabId,
327
+ tabId: this.requireCurrentTabId(),
224
328
  frameId: this.currentFrameId || undefined,
225
329
  refId,
226
330
  force: force ?? false,
227
331
  }));
228
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
+ }
229
341
  async dispatchInput(refId, text) {
230
342
  return (await this.httpServer.sendCommand('dispatch_input', {
231
- tabId: this.currentTabId,
343
+ tabId: this.requireCurrentTabId(),
232
344
  frameId: this.currentFrameId || undefined,
233
345
  refId,
234
346
  text,
@@ -236,7 +348,7 @@ export class ExtensionBridge {
236
348
  }
237
349
  async dragAndDrop(srcRefId, dstRefId) {
238
350
  return (await this.httpServer.sendCommand('drag_and_drop', {
239
- tabId: this.currentTabId,
351
+ tabId: this.requireCurrentTabId(),
240
352
  frameId: this.currentFrameId || undefined,
241
353
  srcRefId,
242
354
  dstRefId,
@@ -244,7 +356,7 @@ export class ExtensionBridge {
244
356
  }
245
357
  async getComputedStyle(refId, prop) {
246
358
  return (await this.httpServer.sendCommand('get_computed_style', {
247
- tabId: this.currentTabId,
359
+ tabId: this.requireCurrentTabId(),
248
360
  frameId: this.currentFrameId || undefined,
249
361
  refId,
250
362
  prop,
@@ -252,7 +364,7 @@ export class ExtensionBridge {
252
364
  }
253
365
  async type(refId, text, clear = false) {
254
366
  const result = (await this.httpServer.sendCommand('type', {
255
- tabId: this.currentTabId,
367
+ tabId: this.requireCurrentTabId(),
256
368
  frameId: this.currentFrameId || undefined,
257
369
  refId,
258
370
  text,
@@ -268,7 +380,7 @@ export class ExtensionBridge {
268
380
  }
269
381
  async scroll(x, y, refId) {
270
382
  await this.httpServer.sendCommand('scroll', {
271
- tabId: this.currentTabId,
383
+ tabId: this.requireCurrentTabId(),
272
384
  frameId: this.currentFrameId || undefined,
273
385
  x,
274
386
  y,
@@ -283,7 +395,7 @@ export class ExtensionBridge {
283
395
  // _args 参数仅满足 IBrowserDriver 接口签名;ExtensionBridge 不消费 args(stealth 路径上层已字符串拼接)
284
396
  const rpcTimeout = timeout !== undefined ? timeout + RPC_MARGIN : undefined;
285
397
  const result = (await this.httpServer.sendCommand('evaluate', {
286
- tabId: this.currentTabId,
398
+ tabId: this.requireCurrentTabId(),
287
399
  frameId: this.currentFrameId || undefined,
288
400
  code,
289
401
  timeout,
@@ -298,12 +410,12 @@ export class ExtensionBridge {
298
410
  return JSON.parse(result.result);
299
411
  }
300
412
  catch (err) {
301
- throw new Error(`evaluate 结果 JSON 解析失败: ${err}`);
413
+ throw new Error(`evaluate 结果 JSON 解析失败: ${err}`, { cause: err });
302
414
  }
303
415
  }
304
416
  async find(selector, text, xpath, timeout) {
305
417
  return (await this.httpServer.sendCommand('find', {
306
- tabId: this.currentTabId,
418
+ tabId: this.requireCurrentTabId(),
307
419
  frameId: this.currentFrameId || undefined,
308
420
  selector,
309
421
  text,
@@ -312,7 +424,7 @@ export class ExtensionBridge {
312
424
  }
313
425
  async getText(selector) {
314
426
  const result = (await this.httpServer.sendCommand('get_text', {
315
- tabId: this.currentTabId,
427
+ tabId: this.requireCurrentTabId(),
316
428
  frameId: this.currentFrameId || undefined,
317
429
  selector,
318
430
  }));
@@ -320,7 +432,7 @@ export class ExtensionBridge {
320
432
  }
321
433
  async getHtml(selector, outer = true) {
322
434
  const result = (await this.httpServer.sendCommand('get_html', {
323
- tabId: this.currentTabId,
435
+ tabId: this.requireCurrentTabId(),
324
436
  frameId: this.currentFrameId || undefined,
325
437
  selector,
326
438
  outer,
@@ -343,13 +455,13 @@ export class ExtensionBridge {
343
455
  }
344
456
  async screenshot(options) {
345
457
  return (await this.httpServer.sendCommand('screenshot', {
346
- tabId: this.currentTabId,
458
+ tabId: this.requireCurrentTabId(),
347
459
  ...options,
348
460
  }));
349
461
  }
350
462
  async getHtmlWithImages(selector, outer = true) {
351
463
  return (await this.httpServer.sendCommand('get_html_with_images', {
352
- tabId: this.currentTabId,
464
+ tabId: this.requireCurrentTabId(),
353
465
  frameId: this.currentFrameId || undefined,
354
466
  selector,
355
467
  outer,
@@ -357,7 +469,7 @@ export class ExtensionBridge {
357
469
  }
358
470
  async getAttribute(selector, refId, attribute) {
359
471
  const result = (await this.httpServer.sendCommand('get_attribute', {
360
- tabId: this.currentTabId,
472
+ tabId: this.requireCurrentTabId(),
361
473
  frameId: this.currentFrameId || undefined,
362
474
  selector,
363
475
  refId,
@@ -367,10 +479,15 @@ export class ExtensionBridge {
367
479
  }
368
480
  async getMetadata() {
369
481
  return (await this.httpServer.sendCommand('get_metadata', {
370
- tabId: this.currentTabId,
482
+ tabId: this.requireCurrentTabId(),
371
483
  frameId: this.currentFrameId || undefined,
372
484
  }));
373
485
  }
486
+ async getFrames() {
487
+ return (await this.httpServer.sendCommand('get_all_frames', {
488
+ tabId: this.requireCurrentTabId(),
489
+ }));
490
+ }
374
491
  async getCookies(filter) {
375
492
  return (await this.httpServer.sendCommand('cookies_get', filter ?? {}));
376
493
  }
@@ -393,7 +510,7 @@ export class ExtensionBridge {
393
510
  }
394
511
  async debuggerSend(method, params, tabId, timeout) {
395
512
  return await this.httpServer.sendCommand('debugger_send', {
396
- tabId: tabId ?? this.currentTabId,
513
+ tabId: tabId ?? this.requireCurrentTabId(),
397
514
  method,
398
515
  params,
399
516
  }, timeout);
@@ -401,7 +518,7 @@ export class ExtensionBridge {
401
518
  // ==================== Debugger (CDP via Extension) ====================
402
519
  async inputKey(type, options = {}) {
403
520
  await this.httpServer.sendCommand('input_key', {
404
- tabId: this.currentTabId,
521
+ tabId: this.requireCurrentTabId(),
405
522
  type,
406
523
  ...options,
407
524
  });
@@ -409,7 +526,7 @@ export class ExtensionBridge {
409
526
  // ==================== 输入事件(通过 CDP)====================
410
527
  async inputMouse(type, x, y, options = {}) {
411
528
  await this.httpServer.sendCommand('input_mouse', {
412
- tabId: this.currentTabId,
529
+ tabId: this.requireCurrentTabId(),
413
530
  type,
414
531
  x,
415
532
  y,
@@ -418,40 +535,40 @@ export class ExtensionBridge {
418
535
  }
419
536
  async inputTouch(type, touchPoints) {
420
537
  await this.httpServer.sendCommand('input_touch', {
421
- tabId: this.currentTabId,
538
+ tabId: this.requireCurrentTabId(),
422
539
  type,
423
540
  touchPoints,
424
541
  });
425
542
  }
426
543
  async inputType(text, delay = 0) {
427
544
  await this.httpServer.sendCommand('input_type', {
428
- tabId: this.currentTabId,
545
+ tabId: this.requireCurrentTabId(),
429
546
  text,
430
547
  delay,
431
548
  });
432
549
  }
433
550
  async consoleEnable() {
434
551
  await this.httpServer.sendCommand('console_enable', {
435
- tabId: this.currentTabId,
552
+ tabId: this.requireCurrentTabId(),
436
553
  });
437
554
  }
438
555
  // ==================== 控制台日志 ====================
439
556
  async consoleGet(options = {}) {
440
557
  const result = (await this.httpServer.sendCommand('console_get', {
441
- tabId: this.currentTabId,
558
+ tabId: this.requireCurrentTabId(),
442
559
  ...options,
443
560
  }));
444
561
  return result.messages;
445
562
  }
446
563
  async networkEnable() {
447
564
  await this.httpServer.sendCommand('network_enable', {
448
- tabId: this.currentTabId,
565
+ tabId: this.requireCurrentTabId(),
449
566
  });
450
567
  }
451
568
  // ==================== 网络日志 ====================
452
569
  async networkGet(options = {}) {
453
570
  const result = (await this.httpServer.sendCommand('network_get', {
454
- tabId: this.currentTabId,
571
+ tabId: this.requireCurrentTabId(),
455
572
  ...options,
456
573
  }));
457
574
  return result.requests;
@@ -461,7 +578,7 @@ export class ExtensionBridge {
461
578
  throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
462
579
  }
463
580
  const params = {
464
- tabId: this.currentTabId,
581
+ tabId: this.requireCurrentTabId(),
465
582
  frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
466
583
  text,
467
584
  delay,
@@ -474,7 +591,7 @@ export class ExtensionBridge {
474
591
  throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
475
592
  }
476
593
  const params = {
477
- tabId: this.currentTabId,
594
+ tabId: this.requireCurrentTabId(),
478
595
  frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
479
596
  key,
480
597
  type,
@@ -487,7 +604,7 @@ export class ExtensionBridge {
487
604
  throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
488
605
  }
489
606
  const params = {
490
- tabId: this.currentTabId,
607
+ tabId: this.requireCurrentTabId(),
491
608
  frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
492
609
  x,
493
610
  y,
@@ -504,7 +621,7 @@ export class ExtensionBridge {
504
621
  throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
505
622
  }
506
623
  const params = {
507
- tabId: this.currentTabId,
624
+ tabId: this.requireCurrentTabId(),
508
625
  frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
509
626
  type,
510
627
  x,
@@ -518,7 +635,7 @@ export class ExtensionBridge {
518
635
  throw new DriverCapabilityError('没有当前页面,请先 browse attach 或先 browse open 创建受控页面');
519
636
  }
520
637
  const params = {
521
- tabId: this.currentTabId,
638
+ tabId: this.requireCurrentTabId(),
522
639
  frameId: this.currentFrameId !== null ? this.currentFrameId : undefined,
523
640
  };
524
641
  await this.httpServer.sendCommand('stealth_inject', params);
@@ -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.currentTabId,
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.currentTabId,
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
- updateState(url, title) {
566
- this.state = { url, title };
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