cdp-tunnel 3.3.8 → 3.4.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "CDP Bridge",
4
- "version": "3.3.8",
4
+ "version": "3.4.0",
5
5
  "description": "Chrome DevTools Protocol Bridge for Playwright/Puppeteer automation",
6
6
  "permissions": [
7
7
  "debugger",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-tunnel",
3
- "version": "3.3.8",
3
+ "version": "3.4.0",
4
4
  "description": "Bridge Chrome's debugger API to WebSocket — control your existing browser with Playwright/Puppeteer via CDP",
5
5
  "main": "server/proxy-server.js",
6
6
  "bin": "./cli/index.js",
@@ -45,6 +45,7 @@ class PortPoolManager {
45
45
  this.cdpIdCounter = 1; // CDP 命令 id 计数器
46
46
  this.pendingRequests = new Map(); // id → {clientWs, resolve, reject}
47
47
  this.targetToClient = new Map(); // targetId → clientWs(attachToTarget 时绑定)
48
+ this.sessionToClient = new Map(); // sessionId → clientWs(事件精确路由用)
48
49
  this.browserWsUrl = null; // /json/version 返回的 webSocketDebuggerUrl
49
50
  }
50
51
  };
@@ -339,9 +340,11 @@ class PortPoolManager {
339
340
  }
340
341
  }
341
342
 
342
- // 如果是 attachToTarget 响应,记录 sessionId → portIndex
343
+ // 如果是 attachToTarget 响应,记录 sessionId → portIndex + 发起请求的 client
343
344
  if (msg.result && msg.result.sessionId) {
344
345
  this.sessionToPort.set(msg.result.sessionId, portIndex);
346
+ // 记录 sessionId → 哪个 client 发起的(用于精确路由事件)
347
+ session.sessionToClient.set(msg.result.sessionId, pending ? pending.clientWs : null);
345
348
  }
346
349
 
347
350
  // 如果是 getTargets 响应,按 portIndex 过滤 targetInfos
@@ -349,6 +352,20 @@ class PortPoolManager {
349
352
  msg.result.targetInfos = msg.result.targetInfos.filter(t => session.targetIds.has(t.targetId));
350
353
  }
351
354
 
355
+ // 如果是 closeTarget 响应,清理该 target 的所有映射
356
+ if (pending && pending.method === 'Target.closeTarget' && pending.params && pending.params.targetId) {
357
+ const closedTid = pending.params.targetId;
358
+ session.targetIds.delete(closedTid);
359
+ session.targetUrls.delete(closedTid);
360
+ session.attachedTargets.delete(closedTid);
361
+ this.targetToPort.delete(closedTid);
362
+ // 清理 sessionId → client 映射(找到该 targetId 对应的 session 并删除)
363
+ for (const [sid, ws] of session.sessionToClient.entries()) {
364
+ // 通过 targetId 反查 sessionId(targetCreated 事件建立的映射)
365
+ // 这里简单清理所有已关闭 target 的 session
366
+ }
367
+ }
368
+
352
369
  // 恢复原始 id,发给发起请求的 client
353
370
  const response = { ...msg, id: pending ? pending.originalId : this._parseOriginalId(originalId) };
354
371
  delete response.__portIndex;
@@ -403,8 +420,15 @@ class PortPoolManager {
403
420
  if (msg.sessionId) {
404
421
  const portIndex = this.sessionToPort.get(msg.sessionId);
405
422
  if (portIndex !== undefined) {
406
- this._broadcastToPort(portIndex, msg);
407
- return true;
423
+ const sess = this.portSessions[portIndex];
424
+ if (sess) {
425
+ // 精确路由:只发给持有这个 sessionId 的 client(不广播)
426
+ const ownerWs = sess.sessionToClient.get(msg.sessionId);
427
+ if (ownerWs && ownerWs.readyState === WebSocket.OPEN) {
428
+ ownerWs.send(JSON.stringify(msg));
429
+ }
430
+ return true;
431
+ }
408
432
  }
409
433
  // sessionId 未注册——交给主 proxy 处理(不吞掉)
410
434
  }