cdp-tunnel 3.2.7 → 3.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "CDP Bridge",
4
- "version": "3.2.7",
4
+ "version": "3.3.0",
5
5
  "description": "Chrome DevTools Protocol Bridge for Playwright/Puppeteer automation",
6
6
  "permissions": [
7
7
  "debugger",
@@ -1,5 +1,5 @@
1
1
  var Config = {
2
- WS_URL: 'ws://localhost:29931/plugin',
2
+ WS_URL: 'ws://localhost:9221/plugin',
3
3
  RECONNECT_DELAY: 3000,
4
4
  DEBUGGER_VERSION: '1.3',
5
5
  HEARTBEAT_INTERVAL: 25000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-tunnel",
3
- "version": "3.2.7",
3
+ "version": "3.3.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",
@@ -204,57 +204,38 @@ class PortPoolManager {
204
204
  const SYNTHETIC_INPUT = ['Input.dispatchKeyEvent', 'Input.dispatchMouseEvent'];
205
205
 
206
206
  // 消息处理:client → plugin(带 portIndex 标记)
207
- // session 级别的命令队列:保证跨 client 的命令串行处理
208
- const handleMessage = async (data) => {
207
+ ws.on('message', async (data) => {
209
208
  let msg;
210
209
  try { msg = JSON.parse(data.toString()); } catch { return; }
211
210
 
212
211
  if (msg.id !== undefined) {
213
- // createTarget:等前一个 createTarget 的响应回来
214
- if (msg.method === 'Target.createTarget' && session.createTargetChain) {
215
- await session.createTargetChain;
216
- }
217
-
218
- // attachToTarget:已 attach 的 target 返回虚拟 session
219
- if (msg.method === 'Target.attachToTarget' && msg.params && msg.params.targetId) {
220
- const targetId = msg.params.targetId;
221
- if (session.attachedTargets && session.attachedTargets.has(targetId)) {
222
- const vsid = `vs_${session.portIndex}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
223
- session.virtualSessions.set(vsid, targetId);
224
- this.sessionToPort.set(vsid, session.portIndex);
225
- ws.send(JSON.stringify({ id: msg.id, result: { sessionId: vsid } }));
226
- return;
227
- }
228
- if (!session.attachedTargets) session.attachedTargets = new Set();
229
- session.attachedTargets.add(targetId);
212
+ // createTarget 串行化(避免并发 chrome.tabs.create 回调串)
213
+ if (msg.method === 'Target.createTarget') {
214
+ while (session.createTargetLock) { await session.createTargetLock; }
215
+ session.createTargetLock = new Promise(r => { session._releaseCreateTarget = r; });
230
216
  }
231
217
 
218
+ // 合成输入命令:先 bringToFront + 等待,再发原命令
232
219
  if (SYNTHETIC_INPUT.indexOf(msg.method) >= 0 && msg.sessionId) {
233
220
  await this._ensureVisible(session, pluginWs, msg.sessionId);
234
221
  }
235
222
 
236
- // createTarget:设置串行链
237
- if (msg.method === 'Target.createTarget') {
238
- let release;
239
- session.createTargetChain = new Promise(r => { release = r; });
240
- session._releaseCT = release;
241
- }
242
-
223
+ // 命令:分配新 id,记录映射(含 method 名供响应后处理),转发给 plugin
243
224
  const newId = `pool${session.portIndex}_${msg.id}`;
244
225
  session.pendingRequests.set(newId, {
245
- originalId: msg.id, method: msg.method, clientWs: ws,
246
- params: msg.params, sessionId: msg.sessionId
226
+ originalId: msg.id,
227
+ method: msg.method,
228
+ clientWs: ws,
229
+ params: msg.params,
230
+ sessionId: msg.sessionId
247
231
  });
232
+
248
233
  const forwarded = { ...msg, id: newId, __portIndex: session.portIndex, __clientId: `pool_${session.port}` };
249
234
  pluginWs.send(JSON.stringify(forwarded));
250
235
  } else {
236
+ // 无 id 的消息(事件),直接转发
251
237
  pluginWs.send(JSON.stringify({ ...msg, __portIndex: session.portIndex }));
252
238
  }
253
- };
254
-
255
- ws.on('message', (data) => {
256
- if (!session.cmdQueue) session.cmdQueue = Promise.resolve();
257
- session.cmdQueue = session.cmdQueue.then(() => handleMessage(data)).catch(() => {});
258
239
  });
259
240
 
260
241
  ws.on('close', () => {
@@ -292,18 +273,18 @@ class PortPoolManager {
292
273
  const pending = session.pendingRequests.get(msg.id);
293
274
  session.pendingRequests.delete(msg.id);
294
275
 
295
- // 如果是 createTarget 响应,记录 targetId + 释放串行链
276
+ // 如果是 createTarget 响应,记录 targetId → portIndex 归属 + 初始 url + 释放锁
296
277
  if (msg.result && msg.result.targetId) {
297
278
  const tid = msg.result.targetId;
298
279
  session.targetIds.add(tid);
299
280
  session.targetUrls.set(tid, pending?.params?.url || 'about:blank');
300
281
  this.targetToPort.set(tid, portIndex);
301
- }
302
- // 释放 createTarget 串行链
303
- if (pending && pending.method === 'Target.createTarget' && session._releaseCT) {
304
- session._releaseCT();
305
- session._releaseCT = null;
306
- session.createTargetChain = null;
282
+ // 释放 createTarget 锁
283
+ if (session._releaseCreateTarget) {
284
+ session._releaseCreateTarget();
285
+ session._releaseCreateTarget = null;
286
+ session.createTargetLock = null;
287
+ }
307
288
  }
308
289
 
309
290
  // 如果是 Page.navigate 响应,更新 targetId 的 url