cdp-tunnel 3.3.7 → 3.3.9

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.7",
4
+ "version": "3.3.9",
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.7",
3
+ "version": "3.3.9",
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
  };
@@ -192,7 +193,6 @@ class PortPoolManager {
192
193
  }
193
194
 
194
195
  // SW 冷启动 warmup:第一个 client 连接时创建一个临时 tab 再关闭
195
- // 确保 chrome.debugger API 完全初始化,避免第一批并发请求失败
196
196
  if (!session.warmedUp) {
197
197
  session.warmedUp = true;
198
198
  const warmupId = `pool${session.portIndex}_internal_warmup`;
@@ -203,8 +203,8 @@ class PortPoolManager {
203
203
  __portIndex: session.portIndex,
204
204
  __clientId: `pool_${session.port}`
205
205
  }));
206
- // 响应回来后在 handlePluginMessage 里丢弃(_internal 前缀)
207
- // tab 会在 Browser.close 或断开时清理
206
+ // warmup 响应回来后在 handlePluginMessage 里关闭这个 tab
207
+ session.pendingWarmupClose = true;
208
208
  }
209
209
 
210
210
  // 通知扩展有 client 连接(带端口号作为分组标识)
@@ -280,8 +280,23 @@ class PortPoolManager {
280
280
 
281
281
  // 1. 响应消息:id 以 pool 开头(排除事件——事件有 method 字段)
282
282
  if (msg.id && typeof msg.id === 'string' && msg.id.startsWith('pool') && !msg.method) {
283
- // 内部命令(ensureVisible 用的)响应直接丢弃
283
+ // 内部命令响应
284
284
  if (msg.id.includes('_internal')) {
285
+ // warmup createTarget 响应——关掉 warmup tab
286
+ const m = msg.id.match(/^pool(\d+)_/);
287
+ if (m && msg.id.includes('_warmup') && msg.result && msg.result.targetId) {
288
+ const pidx = parseInt(m[1]);
289
+ const sess = this.portSessions[pidx];
290
+ const warmupTid = msg.result.targetId;
291
+ const closeId = `pool${pidx}_internal_warmup_close_${Date.now()}`;
292
+ pluginWs.send(JSON.stringify({
293
+ id: closeId,
294
+ method: 'Target.closeTarget',
295
+ params: { targetId: warmupTid },
296
+ __portIndex: pidx,
297
+ __clientId: `pool_${sess.port}`
298
+ }));
299
+ }
285
300
  return true;
286
301
  }
287
302
  const match = msg.id.match(/^pool(\d+)_(.+)$/);
@@ -325,9 +340,11 @@ class PortPoolManager {
325
340
  }
326
341
  }
327
342
 
328
- // 如果是 attachToTarget 响应,记录 sessionId → portIndex
343
+ // 如果是 attachToTarget 响应,记录 sessionId → portIndex + 发起请求的 client
329
344
  if (msg.result && msg.result.sessionId) {
330
345
  this.sessionToPort.set(msg.result.sessionId, portIndex);
346
+ // 记录 sessionId → 哪个 client 发起的(用于精确路由事件)
347
+ session.sessionToClient.set(msg.result.sessionId, pending ? pending.clientWs : null);
331
348
  }
332
349
 
333
350
  // 如果是 getTargets 响应,按 portIndex 过滤 targetInfos
@@ -389,8 +406,15 @@ class PortPoolManager {
389
406
  if (msg.sessionId) {
390
407
  const portIndex = this.sessionToPort.get(msg.sessionId);
391
408
  if (portIndex !== undefined) {
392
- this._broadcastToPort(portIndex, msg);
393
- return true;
409
+ const sess = this.portSessions[portIndex];
410
+ if (sess) {
411
+ // 精确路由:只发给持有这个 sessionId 的 client(不广播)
412
+ const ownerWs = sess.sessionToClient.get(msg.sessionId);
413
+ if (ownerWs && ownerWs.readyState === WebSocket.OPEN) {
414
+ ownerWs.send(JSON.stringify(msg));
415
+ }
416
+ return true;
417
+ }
394
418
  }
395
419
  // sessionId 未注册——交给主 proxy 处理(不吞掉)
396
420
  }