@pyrokine/mcp-chrome 1.1.0 → 1.3.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 (91) hide show
  1. package/README.md +103 -53
  2. package/dist/anti-detection/behavior.d.ts +0 -8
  3. package/dist/anti-detection/behavior.d.ts.map +1 -1
  4. package/dist/anti-detection/behavior.js +0 -16
  5. package/dist/anti-detection/behavior.js.map +1 -1
  6. package/dist/cdp/client.d.ts +0 -2
  7. package/dist/cdp/client.d.ts.map +1 -1
  8. package/dist/cdp/client.js +30 -45
  9. package/dist/cdp/client.js.map +1 -1
  10. package/dist/cdp/launcher.d.ts +1 -8
  11. package/dist/cdp/launcher.d.ts.map +1 -1
  12. package/dist/cdp/launcher.js +4 -20
  13. package/dist/cdp/launcher.js.map +1 -1
  14. package/dist/core/auto-wait.d.ts +2 -2
  15. package/dist/core/auto-wait.d.ts.map +1 -1
  16. package/dist/core/auto-wait.js +1 -1
  17. package/dist/core/auto-wait.js.map +1 -1
  18. package/dist/core/errors.d.ts +10 -13
  19. package/dist/core/errors.d.ts.map +1 -1
  20. package/dist/core/errors.js +19 -25
  21. package/dist/core/errors.js.map +1 -1
  22. package/dist/core/locator.d.ts +6 -7
  23. package/dist/core/locator.d.ts.map +1 -1
  24. package/dist/core/locator.js +77 -31
  25. package/dist/core/locator.js.map +1 -1
  26. package/dist/core/retry.d.ts.map +1 -1
  27. package/dist/core/retry.js +1 -1
  28. package/dist/core/retry.js.map +1 -1
  29. package/dist/core/session.d.ts +32 -33
  30. package/dist/core/session.d.ts.map +1 -1
  31. package/dist/core/session.js +154 -114
  32. package/dist/core/session.js.map +1 -1
  33. package/dist/core/types.d.ts +4 -0
  34. package/dist/core/types.d.ts.map +1 -1
  35. package/dist/core/types.js +6 -0
  36. package/dist/core/types.js.map +1 -1
  37. package/dist/core/unified-session.d.ts +54 -67
  38. package/dist/core/unified-session.d.ts.map +1 -1
  39. package/dist/core/unified-session.js +215 -181
  40. package/dist/core/unified-session.js.map +1 -1
  41. package/dist/extension/bridge.d.ts +0 -19
  42. package/dist/extension/bridge.d.ts.map +1 -1
  43. package/dist/extension/bridge.js +6 -52
  44. package/dist/extension/bridge.js.map +1 -1
  45. package/dist/extension/http-server.d.ts +13 -11
  46. package/dist/extension/http-server.d.ts.map +1 -1
  47. package/dist/extension/http-server.js +101 -95
  48. package/dist/extension/http-server.js.map +1 -1
  49. package/dist/index.js +11 -64
  50. package/dist/index.js.map +1 -1
  51. package/dist/tools/browse.d.ts +3 -80
  52. package/dist/tools/browse.d.ts.map +1 -1
  53. package/dist/tools/browse.js +135 -291
  54. package/dist/tools/browse.js.map +1 -1
  55. package/dist/tools/cookies.d.ts +3 -71
  56. package/dist/tools/cookies.d.ts.map +1 -1
  57. package/dist/tools/cookies.js +75 -157
  58. package/dist/tools/cookies.js.map +1 -1
  59. package/dist/tools/evaluate.d.ts +3 -52
  60. package/dist/tools/evaluate.d.ts.map +1 -1
  61. package/dist/tools/evaluate.js +35 -86
  62. package/dist/tools/evaluate.js.map +1 -1
  63. package/dist/tools/extract.d.ts +3 -226
  64. package/dist/tools/extract.d.ts.map +1 -1
  65. package/dist/tools/extract.js +98 -170
  66. package/dist/tools/extract.js.map +1 -1
  67. package/dist/tools/index.d.ts +9 -9
  68. package/dist/tools/index.d.ts.map +1 -1
  69. package/dist/tools/index.js +9 -9
  70. package/dist/tools/index.js.map +1 -1
  71. package/dist/tools/input.d.ts +3 -258
  72. package/dist/tools/input.d.ts.map +1 -1
  73. package/dist/tools/input.js +56 -143
  74. package/dist/tools/input.js.map +1 -1
  75. package/dist/tools/logs.d.ts +3 -51
  76. package/dist/tools/logs.d.ts.map +1 -1
  77. package/dist/tools/logs.js +47 -108
  78. package/dist/tools/logs.js.map +1 -1
  79. package/dist/tools/manage.d.ts +3 -64
  80. package/dist/tools/manage.d.ts.map +1 -1
  81. package/dist/tools/manage.js +243 -373
  82. package/dist/tools/manage.js.map +1 -1
  83. package/dist/tools/schema.d.ts +16 -182
  84. package/dist/tools/schema.d.ts.map +1 -1
  85. package/dist/tools/schema.js +70 -159
  86. package/dist/tools/schema.js.map +1 -1
  87. package/dist/tools/wait.d.ts +3 -221
  88. package/dist/tools/wait.d.ts.map +1 -1
  89. package/dist/tools/wait.js +74 -145
  90. package/dist/tools/wait.js.map +1 -1
  91. package/package.json +1 -1
@@ -10,7 +10,7 @@
10
10
  import { BehaviorSimulator } from '../anti-detection/index.js';
11
11
  import { AutoWait } from './auto-wait.js';
12
12
  import { Locator } from './locator.js';
13
- import type { ConnectOptions, ConsoleLogEntry, Cookie, CookieOptions, LaunchOptions, NetworkRequestEntry, PageState, Target, TargetInfo, WaitUntil } from './types.js';
13
+ import { type ConnectOptions, type ConsoleLogEntry, type Cookie, type CookieOptions, type LaunchOptions, type NetworkRequestEntry, type PageState, type Target, type TargetInfo, type WaitUntil } from './types.js';
14
14
  /**
15
15
  * 会话状态
16
16
  */
@@ -33,17 +33,19 @@ declare class SessionManager {
33
33
  private state;
34
34
  private behaviorSimulator;
35
35
  private stealthMode;
36
+ /** 当前按下的修饰键位掩码 */
37
+ private modifiers;
36
38
  private operationLock;
37
39
  private consoleLogs;
38
40
  private networkRequests;
39
41
  private requestMap;
40
42
  private listenersInstalled;
41
43
  private constructor();
42
- static getInstance(): SessionManager;
43
44
  /**
44
45
  * 获取当前调试端口
45
46
  */
46
47
  get port(): number | null;
48
+ static getInstance(): SessionManager;
47
49
  /**
48
50
  * 启动浏览器
49
51
  *
@@ -63,10 +65,6 @@ declare class SessionManager {
63
65
  * 附加到指定页面(外部入口,加锁)
64
66
  */
65
67
  attachToTarget(targetId: string): Promise<void>;
66
- /**
67
- * 附加到指定页面(内部版本,不加锁,供 launch/connect 等已持锁方法调用)
68
- */
69
- private attachToTargetInternal;
70
68
  /**
71
69
  * 导航到 URL
72
70
  */
@@ -108,6 +106,7 @@ declare class SessionManager {
108
106
  */
109
107
  createLocator(target: Target, options?: {
110
108
  timeout?: number;
109
+ nth?: number;
111
110
  }): Locator;
112
111
  /**
113
112
  * 创建自动等待器
@@ -162,7 +161,7 @@ declare class SessionManager {
162
161
  /**
163
162
  * 截图
164
163
  */
165
- screenshot(fullPage?: boolean): Promise<string>;
164
+ screenshot(fullPage?: boolean, scale?: number, format?: string, quality?: number): Promise<string>;
166
165
  /**
167
166
  * 获取页面状态
168
167
  */
@@ -216,10 +215,6 @@ declare class SessionManager {
216
215
  * 新建页面(外部入口,加锁)
217
216
  */
218
217
  newPage(): Promise<TargetInfo>;
219
- /**
220
- * 新建页面(内部版本,不加锁,供 launch 等已持锁方法调用)
221
- */
222
- private newPageInternal;
223
218
  /**
224
219
  * 激活页面(切到前台)
225
220
  */
@@ -237,13 +232,6 @@ declare class SessionManager {
237
232
  * 2. 通过 withLock 串行化状态清理:等 withLock 中的操作处理完错误后再置空引用
238
233
  */
239
234
  close(): Promise<void>;
240
- /**
241
- * 重置所有状态(同步,不加锁)
242
- *
243
- * 供已持有 withLock 的方法调用(launch/connect),避免 close() 的 withLock 重入死锁。
244
- * 外部调用请使用 close()。
245
- */
246
- private resetState;
247
235
  /**
248
236
  * 获取当前状态
249
237
  */
@@ -253,9 +241,33 @@ declare class SessionManager {
253
241
  */
254
242
  isConnected(): boolean;
255
243
  /**
256
- * 是否有活跃会话
244
+ * 发送 CDP 命令(page-level,携带 sessionId)
245
+ *
246
+ * 每次调用都检查连接状态,防止 close() 并发置空 this.cdp 后崩溃。
247
+ * 多步操作(type 循环、fullPage 截图等)的 await 间隙可能被 close() 打断,
248
+ * ensureSession() 确保在当前 tick 内 this.cdp 非空。
249
+ */
250
+ send<T>(method: string, params?: object, timeout?: number): Promise<T>;
251
+ /**
252
+ * 发送 browser-level CDP 命令(不携带 sessionId)
253
+ * 用于 Target.*、Browser.* 等浏览器级命令
254
+ */
255
+ sendBrowserCommand<T>(method: string, params?: object): Promise<T>;
256
+ /**
257
+ * 附加到指定页面(内部版本,不加锁,供 launch/connect 等已持锁方法调用)
258
+ */
259
+ private attachToTargetInternal;
260
+ /**
261
+ * 新建页面(内部版本,不加锁,供 launch 等已持锁方法调用)
262
+ */
263
+ private newPageInternal;
264
+ /**
265
+ * 重置所有状态(同步,不加锁)
266
+ *
267
+ * 供已持有 withLock 的方法调用(launch/connect),避免 close() 的 withLock 重入死锁。
268
+ * 外部调用请使用 close()。
257
269
  */
258
- hasSession(): boolean;
270
+ private resetState;
259
271
  /**
260
272
  * 串行执行操作(防止并发竞态)
261
273
  */
@@ -280,19 +292,6 @@ declare class SessionManager {
280
292
  * 更新页面状态
281
293
  */
282
294
  private updateState;
283
- /**
284
- * 发送 CDP 命令(page-level,携带 sessionId)
285
- *
286
- * 每次调用都检查连接状态,防止 close() 并发置空 this.cdp 后崩溃。
287
- * 多步操作(type 循环、fullPage 截图等)的 await 间隙可能被 close() 打断,
288
- * ensureSession() 确保在当前 tick 内 this.cdp 非空。
289
- */
290
- send<T>(method: string, params?: object, timeout?: number): Promise<T>;
291
- /**
292
- * 发送 browser-level CDP 命令(不携带 sessionId)
293
- * 用于 Target.*、Browser.* 等浏览器级命令
294
- */
295
- sendBrowserCommand<T>(method: string, params?: object): Promise<T>;
296
295
  /**
297
296
  * 确保已连接
298
297
  */
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,iBAAiB,EAAyB,MAAM,4BAA4B,CAAA;AAEpF,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAA;AAEvC,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,KAAK,EACR,cAAc,EACd,eAAe,EACf,MAAM,EACN,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,UAAU,EACV,SAAS,EACZ,MAAM,YAAY,CAAA;AAEnB;;GAEG;AACH,UAAU,YAAY;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,cAAM,cAAc;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IAEvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAc;IACrD,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,GAAG,CAA8C;IACzD,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,SAAS,CAAwC;IACzD,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,iBAAiB,CAAmD;IAC5E,OAAO,CAAC,WAAW,CAAwC;IAE3D,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,UAAU,CAKd;IAGJ,OAAO,CAAC,kBAAkB,CAAQ;IAElC,OAAO;IAGP,MAAM,CAAC,WAAW,IAAI,cAAc;IAOpC;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,GAAG,IAAI,CAExB;IAED;;;;;OAKG;IACG,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;IAqF9D;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAqC3D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAuB1C;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;YACW,sBAAsB;IAgCpC;;OAEG;IACG,QAAQ,CACV,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GACrD,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;OAIG;IACG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA4EhF;;OAEG;IACG,iBAAiB,CAAC,OAAO,GAAE,MAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/D;;OAEG;IACG,MAAM,CAAC,OAAO,SAAQ,GAAG,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAC,CAAC;IA2B5D;;OAEG;IACG,SAAS,CAAC,OAAO,SAAQ,GAAG,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAC,CAAC;IAyB/D;;OAEG;IACG,MAAM,CAAC,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBtF;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;IAQtE;;OAEG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,QAAQ;IAKxD;;OAEG;IACH,oBAAoB,IAAI,iBAAiB;IAIzC;;OAEG;IACG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUpD;;OAEG;IACG,SAAS,CACX,MAAM,GAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAkB,GAClE,OAAO,CAAC,IAAI,CAAC;IAWhB;;OAEG;IACG,OAAO,CACT,MAAM,GAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAkB,GAClE,OAAO,CAAC,IAAI,CAAC;IAWhB;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/D;;OAEG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASzC;;OAEG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASvC;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrD;;OAEG;IACG,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B;;OAEG;IACG,UAAU,CAAC,QAAQ,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAqCnD;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAgExC;;;OAGG;IACG,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IASpD;;OAEG;IACG,SAAS,CACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAchB;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7D;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAKnC;;OAEG;IACH,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,eAAe,EAAE;IAQ9D;;OAEG;IACH,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,mBAAmB,EAAE;IAS3E;;OAEG;IACH,SAAS,IAAI,IAAI;IAMjB;;OAEG;IACG,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAiCjF;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/D;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD;;OAEG;IACG,UAAU,CAAC,IAAI,GAAE,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBtF;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAIpC;;OAEG;YACW,eAAe;IAiB7B;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD;;OAEG;IACG,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBjD;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAY5B;;;;;OAKG;IACH,OAAO,CAAC,UAAU;IAmBlB;;OAEG;IACH,QAAQ,IAAI,YAAY,GAAG,IAAI;IAI/B;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;OAEG;YACW,QAAQ;IActB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAwCvB;;OAEG;YACW,WAAW;IA6BzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuE3B;;OAEG;YACW,WAAW;IAczB;;;;;;OAMG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAKtE;;;OAGG;IACH,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,OAAO,CAAC,aAAa;CAMxB;AAoED;;GAEG;AACH,wBAAgB,UAAU,IAAI,cAAc,CAE3C"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/core/session.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,7 @@ import { BrowserLauncher, CDPClient, getBrowserWSEndpoint, getTargets } from '..
12
12
  import { AutoWait } from './auto-wait.js';
13
13
  import { NavigationTimeoutError, SessionNotFoundError, TargetNotFoundError } from './errors.js';
14
14
  import { Locator } from './locator.js';
15
+ import { DEFAULT_TIMEOUT, MODIFIER_KEYS, } from './types.js';
15
16
  /**
16
17
  * 会话管理器(单例)
17
18
  */
@@ -27,6 +28,8 @@ class SessionManager {
27
28
  state = null;
28
29
  behaviorSimulator = new BehaviorSimulator();
29
30
  stealthMode = 'safe';
31
+ /** 当前按下的修饰键位掩码 */
32
+ modifiers = 0;
30
33
  // 操作锁(防止并发竞态)
31
34
  operationLock = Promise.resolve();
32
35
  consoleLogs = [];
@@ -36,18 +39,18 @@ class SessionManager {
36
39
  listenersInstalled = false;
37
40
  constructor() {
38
41
  }
39
- static getInstance() {
40
- if (!SessionManager.instance) {
41
- SessionManager.instance = new SessionManager();
42
- }
43
- return SessionManager.instance;
44
- }
45
42
  /**
46
43
  * 获取当前调试端口
47
44
  */
48
45
  get port() {
49
46
  return this.launcher?.port ?? (this.connectedPort || null);
50
47
  }
48
+ static getInstance() {
49
+ if (!SessionManager.instance) {
50
+ SessionManager.instance = new SessionManager();
51
+ }
52
+ return SessionManager.instance;
53
+ }
51
54
  /**
52
55
  * 启动浏览器
53
56
  *
@@ -132,7 +135,7 @@ class SessionManager {
132
135
  */
133
136
  async connect(options) {
134
137
  return this.withLock(async () => {
135
- const { host = '127.0.0.1', port, timeout = 30000, stealth = 'safe' } = options;
138
+ const { host = '127.0.0.1', port, timeout = DEFAULT_TIMEOUT, stealth = 'safe' } = options;
136
139
  // 关闭现有会话
137
140
  this.resetState();
138
141
  // 保存 stealth 模式
@@ -142,6 +145,7 @@ class SessionManager {
142
145
  // 连接 CDP
143
146
  this.cdp = new CDPClient();
144
147
  await this.cdp.connect(endpoint, timeout);
148
+ this.connectedPort = port;
145
149
  // 获取第一个页面
146
150
  const targets = await getTargets(host, port);
147
151
  const pageTarget = targets.find((t) => t.type === 'page');
@@ -180,43 +184,13 @@ class SessionManager {
180
184
  async attachToTarget(targetId) {
181
185
  return this.withLock(async () => this.attachToTargetInternal(targetId));
182
186
  }
183
- /**
184
- * 附加到指定页面(内部版本,不加锁,供 launch/connect 等已持锁方法调用)
185
- */
186
- async attachToTargetInternal(targetId) {
187
- this.ensureConnected();
188
- // 如果已经附加到同一个 target,跳过
189
- if (this.currentTargetId === targetId && this.sessionId) {
190
- return;
191
- }
192
- // 如果有之前的 session,先分离
193
- if (this.sessionId) {
194
- try {
195
- await this.cdp.send('Target.detachFromTarget', {
196
- sessionId: this.sessionId,
197
- });
198
- }
199
- catch {
200
- // 忽略分离错误
201
- }
202
- }
203
- // 附加到目标
204
- const { sessionId } = (await this.cdp.send('Target.attachToTarget', {
205
- targetId,
206
- flatten: true,
207
- }));
208
- this.sessionId = sessionId;
209
- this.currentTargetId = targetId;
210
- // 初始化会话
211
- await this.initSession();
212
- }
213
187
  /**
214
188
  * 导航到 URL
215
189
  */
216
190
  async navigate(url, options = {}) {
217
191
  return this.withLock(async () => {
218
192
  this.ensureSession();
219
- const { wait = 'load', timeout = 30000 } = options;
193
+ const { wait = 'load', timeout = DEFAULT_TIMEOUT } = options;
220
194
  // 导航(传 timeout 防止 CDP 默认 30s 截断用户预算)
221
195
  const { errorText } = (await this.send('Page.navigate', { url }, timeout));
222
196
  if (errorText) {
@@ -309,14 +283,14 @@ class SessionManager {
309
283
  /**
310
284
  * 等待导航完成(跨文档导航或同文档导航)
311
285
  */
312
- async waitForNavigation(timeout = 30000) {
286
+ async waitForNavigation(timeout = DEFAULT_TIMEOUT) {
313
287
  this.ensureSession();
314
288
  await this.waitForAnyEvent(['Page.loadEventFired', 'Page.navigatedWithinDocument'], timeout);
315
289
  }
316
290
  /**
317
291
  * 后退
318
292
  */
319
- async goBack(timeout = 30000) {
293
+ async goBack(timeout = DEFAULT_TIMEOUT) {
320
294
  return this.withLock(async () => {
321
295
  this.ensureSession();
322
296
  const { currentIndex, entries } = await this.send('Page.getNavigationHistory', undefined, timeout);
@@ -327,7 +301,8 @@ class SessionManager {
327
301
  const waitPromise = this.waitForAnyEvent(['Page.loadEventFired', 'Page.navigatedWithinDocument'], timeout);
328
302
  // 预注册 rejection handler:若 send() 抛错导致 waitPromise 永远不被 await,
329
303
  // 其 timer reject 不会成为 unhandled rejection(Node 20 默认会退出进程)
330
- waitPromise.catch(() => { });
304
+ waitPromise.catch(() => {
305
+ });
331
306
  await this.send('Page.navigateToHistoryEntry', { entryId: entries[currentIndex - 1].id }, timeout);
332
307
  await waitPromise;
333
308
  await this.updateState();
@@ -337,7 +312,7 @@ class SessionManager {
337
312
  /**
338
313
  * 前进
339
314
  */
340
- async goForward(timeout = 30000) {
315
+ async goForward(timeout = DEFAULT_TIMEOUT) {
341
316
  return this.withLock(async () => {
342
317
  this.ensureSession();
343
318
  const { currentIndex, entries } = await this.send('Page.getNavigationHistory', undefined, timeout);
@@ -346,7 +321,8 @@ class SessionManager {
346
321
  }
347
322
  // 跨文档导航触发 loadEventFired,同文档导航(hash/pushState)触发 navigatedWithinDocument
348
323
  const waitPromise = this.waitForAnyEvent(['Page.loadEventFired', 'Page.navigatedWithinDocument'], timeout);
349
- waitPromise.catch(() => { });
324
+ waitPromise.catch(() => {
325
+ });
350
326
  await this.send('Page.navigateToHistoryEntry', { entryId: entries[currentIndex + 1].id }, timeout);
351
327
  await waitPromise;
352
328
  await this.updateState();
@@ -359,9 +335,10 @@ class SessionManager {
359
335
  async reload(options = {}) {
360
336
  return this.withLock(async () => {
361
337
  this.ensureSession();
362
- const { ignoreCache = false, timeout = 30000 } = options;
338
+ const { ignoreCache = false, timeout = DEFAULT_TIMEOUT } = options;
363
339
  const waitPromise = this.cdp.waitForEvent('Page.loadEventFired', undefined, timeout);
364
- waitPromise.catch(() => { });
340
+ waitPromise.catch(() => {
341
+ });
365
342
  await this.send('Page.reload', { ignoreCache }, timeout);
366
343
  await waitPromise;
367
344
  await this.updateState();
@@ -374,6 +351,7 @@ class SessionManager {
374
351
  this.ensureSession();
375
352
  return new Locator(this.cdp, target, this.sessionId, {
376
353
  ...options,
354
+ nth: options?.nth ?? target.nth,
377
355
  getUrl: () => this.state?.url,
378
356
  });
379
357
  }
@@ -399,6 +377,7 @@ class SessionManager {
399
377
  type: 'mouseMoved',
400
378
  x,
401
379
  y,
380
+ modifiers: this.modifiers,
402
381
  });
403
382
  this.behaviorSimulator.setCurrentPosition({ x, y });
404
383
  }
@@ -413,6 +392,7 @@ class SessionManager {
413
392
  clickCount: 1,
414
393
  x: this.behaviorSimulator.getCurrentPosition().x,
415
394
  y: this.behaviorSimulator.getCurrentPosition().y,
395
+ modifiers: this.modifiers,
416
396
  });
417
397
  }
418
398
  /**
@@ -426,6 +406,7 @@ class SessionManager {
426
406
  clickCount: 1,
427
407
  x: this.behaviorSimulator.getCurrentPosition().x,
428
408
  y: this.behaviorSimulator.getCurrentPosition().y,
409
+ modifiers: this.modifiers,
429
410
  });
430
411
  }
431
412
  /**
@@ -440,6 +421,7 @@ class SessionManager {
440
421
  y: pos.y,
441
422
  deltaX,
442
423
  deltaY,
424
+ modifiers: this.modifiers,
443
425
  });
444
426
  }
445
427
  /**
@@ -447,9 +429,13 @@ class SessionManager {
447
429
  */
448
430
  async keyDown(key) {
449
431
  this.ensureSession();
432
+ if (MODIFIER_KEYS[key]) {
433
+ this.modifiers |= MODIFIER_KEYS[key];
434
+ }
450
435
  const keyDefinition = getKeyDefinition(key);
451
436
  await this.send('Input.dispatchKeyEvent', {
452
437
  type: 'keyDown',
438
+ modifiers: this.modifiers,
453
439
  ...keyDefinition,
454
440
  });
455
441
  }
@@ -461,8 +447,12 @@ class SessionManager {
461
447
  const keyDefinition = getKeyDefinition(key);
462
448
  await this.send('Input.dispatchKeyEvent', {
463
449
  type: 'keyUp',
450
+ modifiers: this.modifiers,
464
451
  ...keyDefinition,
465
452
  });
453
+ if (MODIFIER_KEYS[key]) {
454
+ this.modifiers &= ~MODIFIER_KEYS[key];
455
+ }
466
456
  }
467
457
  /**
468
458
  * 输入文本
@@ -472,10 +462,12 @@ class SessionManager {
472
462
  for (const char of text) {
473
463
  await this.send('Input.dispatchKeyEvent', {
474
464
  type: 'keyDown',
465
+ modifiers: this.modifiers,
475
466
  text: char,
476
467
  });
477
468
  await this.send('Input.dispatchKeyEvent', {
478
469
  type: 'keyUp',
470
+ modifiers: this.modifiers,
479
471
  text: char,
480
472
  });
481
473
  if (delay > 0) {
@@ -516,8 +508,12 @@ class SessionManager {
516
508
  /**
517
509
  * 截图
518
510
  */
519
- async screenshot(fullPage = false) {
511
+ async screenshot(fullPage = false, scale, format, quality) {
520
512
  this.ensureSession();
513
+ const captureParams = { format: format ?? 'png' };
514
+ if (quality !== undefined) {
515
+ captureParams.quality = quality;
516
+ }
521
517
  if (fullPage) {
522
518
  // 获取页面完整高度
523
519
  const { result } = (await this.send('Runtime.evaluate', {
@@ -529,22 +525,18 @@ class SessionManager {
529
525
  await this.send('Emulation.setDeviceMetricsOverride', {
530
526
  width,
531
527
  height,
532
- deviceScaleFactor: 1,
528
+ deviceScaleFactor: scale ?? 1,
533
529
  mobile: false,
534
530
  });
535
531
  try {
536
- const { data } = (await this.send('Page.captureScreenshot', {
537
- format: 'png',
538
- }));
532
+ const { data } = (await this.send('Page.captureScreenshot', captureParams));
539
533
  return data;
540
534
  }
541
535
  finally {
542
536
  await this.send('Emulation.clearDeviceMetricsOverride');
543
537
  }
544
538
  }
545
- const { data } = (await this.send('Page.captureScreenshot', {
546
- format: 'png',
547
- }));
539
+ const { data } = (await this.send('Page.captureScreenshot', captureParams));
548
540
  return data;
549
541
  }
550
542
  /**
@@ -671,23 +663,45 @@ class SessionManager {
671
663
  */
672
664
  async evaluate(script, args, timeout) {
673
665
  this.ensureSession();
674
- let expression = script;
666
+ // CDP 命令超时需大于脚本执行超时,给 WebSocket 通信留余量
667
+ const CDP_MARGIN = 5000;
668
+ const sendTimeout = timeout !== undefined ? timeout + CDP_MARGIN : undefined;
669
+ // 有参数时使用 callFunctionOn:避免大 payload 字符串拼接,参数通过协议结构化传递
675
670
  if (args && args.length > 0) {
676
- // 将参数序列化并注入
677
- const argsStr = args.map((a) => JSON.stringify(a)).join(', ');
678
- expression = `(${script})(${argsStr})`;
671
+ const { result: globalResult } = (await this.send('Runtime.evaluate', {
672
+ expression: 'globalThis',
673
+ returnByValue: false,
674
+ }));
675
+ try {
676
+ const callParams = {
677
+ functionDeclaration: script,
678
+ objectId: globalResult.objectId,
679
+ arguments: args.map(a => ({ value: a })),
680
+ returnByValue: true,
681
+ awaitPromise: true,
682
+ };
683
+ if (timeout !== undefined) {
684
+ callParams.timeout = timeout;
685
+ }
686
+ const { result, exceptionDetails } = (await this.send('Runtime.callFunctionOn', callParams, sendTimeout));
687
+ if (exceptionDetails) {
688
+ throw new Error(exceptionDetails.exception.description);
689
+ }
690
+ return result.value;
691
+ }
692
+ finally {
693
+ this.send('Runtime.releaseObject', { objectId: globalResult.objectId }).catch(() => {
694
+ });
695
+ }
679
696
  }
680
697
  const evalParams = {
681
- expression,
698
+ expression: script,
682
699
  returnByValue: true,
683
700
  awaitPromise: true,
684
701
  };
685
702
  if (timeout !== undefined) {
686
703
  evalParams.timeout = timeout;
687
704
  }
688
- // CDP 命令超时需大于脚本执行超时,给 WebSocket 通信留余量
689
- const CDP_MARGIN = 5000;
690
- const sendTimeout = timeout !== undefined ? timeout + CDP_MARGIN : undefined;
691
705
  const { result, exceptionDetails } = (await this.send('Runtime.evaluate', evalParams, sendTimeout));
692
706
  if (exceptionDetails) {
693
707
  throw new Error(exceptionDetails.exception.description);
@@ -739,22 +753,6 @@ class SessionManager {
739
753
  async newPage() {
740
754
  return this.withLock(async () => this.newPageInternal());
741
755
  }
742
- /**
743
- * 新建页面(内部版本,不加锁,供 launch 等已持锁方法调用)
744
- */
745
- async newPageInternal() {
746
- this.ensureConnected();
747
- const { targetId } = (await this.cdp.send('Target.createTarget', {
748
- url: 'about:blank',
749
- }));
750
- await this.attachToTargetInternal(targetId);
751
- return {
752
- targetId,
753
- type: 'page',
754
- url: 'about:blank',
755
- title: '',
756
- };
757
- }
758
756
  /**
759
757
  * 激活页面(切到前台)
760
758
  */
@@ -800,6 +798,83 @@ class SessionManager {
800
798
  this.resetState();
801
799
  });
802
800
  }
801
+ /**
802
+ * 获取当前状态
803
+ */
804
+ getState() {
805
+ return this.state;
806
+ }
807
+ /**
808
+ * 是否已连接
809
+ */
810
+ isConnected() {
811
+ return this.cdp !== null && this.cdp.isConnected;
812
+ }
813
+ /**
814
+ * 发送 CDP 命令(page-level,携带 sessionId)
815
+ *
816
+ * 每次调用都检查连接状态,防止 close() 并发置空 this.cdp 后崩溃。
817
+ * 多步操作(type 循环、fullPage 截图等)的 await 间隙可能被 close() 打断,
818
+ * ensureSession() 确保在当前 tick 内 this.cdp 非空。
819
+ */
820
+ send(method, params, timeout) {
821
+ this.ensureSession();
822
+ return this.cdp.send(method, params, this.sessionId ?? undefined, timeout);
823
+ }
824
+ /**
825
+ * 发送 browser-level CDP 命令(不携带 sessionId)
826
+ * 用于 Target.*、Browser.* 等浏览器级命令
827
+ */
828
+ sendBrowserCommand(method, params) {
829
+ this.ensureConnected();
830
+ return this.cdp.send(method, params);
831
+ }
832
+ /**
833
+ * 附加到指定页面(内部版本,不加锁,供 launch/connect 等已持锁方法调用)
834
+ */
835
+ async attachToTargetInternal(targetId) {
836
+ this.ensureConnected();
837
+ // 如果已经附加到同一个 target,跳过
838
+ if (this.currentTargetId === targetId && this.sessionId) {
839
+ return;
840
+ }
841
+ // 如果有之前的 session,先分离
842
+ if (this.sessionId) {
843
+ try {
844
+ await this.cdp.send('Target.detachFromTarget', {
845
+ sessionId: this.sessionId,
846
+ });
847
+ }
848
+ catch {
849
+ // 忽略分离错误
850
+ }
851
+ }
852
+ // 附加到目标
853
+ const { sessionId } = (await this.cdp.send('Target.attachToTarget', {
854
+ targetId,
855
+ flatten: true,
856
+ }));
857
+ this.sessionId = sessionId;
858
+ this.currentTargetId = targetId;
859
+ // 初始化会话
860
+ await this.initSession();
861
+ }
862
+ /**
863
+ * 新建页面(内部版本,不加锁,供 launch 等已持锁方法调用)
864
+ */
865
+ async newPageInternal() {
866
+ this.ensureConnected();
867
+ const { targetId } = (await this.cdp.send('Target.createTarget', {
868
+ url: 'about:blank',
869
+ }));
870
+ await this.attachToTargetInternal(targetId);
871
+ return {
872
+ targetId,
873
+ type: 'page',
874
+ url: 'about:blank',
875
+ title: '',
876
+ };
877
+ }
803
878
  /**
804
879
  * 重置所有状态(同步,不加锁)
805
880
  *
@@ -816,30 +891,14 @@ class SessionManager {
816
891
  this.launcher = null;
817
892
  }
818
893
  this.clearLogs();
894
+ this.modifiers = 0;
895
+ this.behaviorSimulator.setCurrentPosition({ x: 0, y: 0 });
819
896
  this.sessionId = null;
820
897
  this.currentTargetId = null;
821
898
  this.state = null;
822
899
  this.listenersInstalled = false;
823
900
  this.connectedPort = 0;
824
901
  }
825
- /**
826
- * 获取当前状态
827
- */
828
- getState() {
829
- return this.state;
830
- }
831
- /**
832
- * 是否已连接
833
- */
834
- isConnected() {
835
- return this.cdp !== null && this.cdp.isConnected;
836
- }
837
- /**
838
- * 是否有活跃会话
839
- */
840
- hasSession() {
841
- return this.sessionId !== null;
842
- }
843
902
  /**
844
903
  * 串行执行操作(防止并发竞态)
845
904
  */
@@ -996,25 +1055,6 @@ class SessionManager {
996
1055
  targetId: this.currentTargetId,
997
1056
  };
998
1057
  }
999
- /**
1000
- * 发送 CDP 命令(page-level,携带 sessionId)
1001
- *
1002
- * 每次调用都检查连接状态,防止 close() 并发置空 this.cdp 后崩溃。
1003
- * 多步操作(type 循环、fullPage 截图等)的 await 间隙可能被 close() 打断,
1004
- * ensureSession() 确保在当前 tick 内 this.cdp 非空。
1005
- */
1006
- send(method, params, timeout) {
1007
- this.ensureSession();
1008
- return this.cdp.send(method, params, this.sessionId ?? undefined, timeout);
1009
- }
1010
- /**
1011
- * 发送 browser-level CDP 命令(不携带 sessionId)
1012
- * 用于 Target.*、Browser.* 等浏览器级命令
1013
- */
1014
- sendBrowserCommand(method, params) {
1015
- this.ensureConnected();
1016
- return this.cdp.send(method, params);
1017
- }
1018
1058
  /**
1019
1059
  * 确保已连接
1020
1060
  */