cdp-tunnel 2.7.3 → 2.7.5

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.
@@ -141,8 +141,11 @@ var SpecialHandler = (function() {
141
141
 
142
142
  function groupTabSilently(tabId, clientId) {
143
143
  return new Promise(function(resolve) {
144
- addTabToAutomationGroup(tabId, clientId);
145
- // 分组操作是异步的,给一点时间让 tab 被收进折叠的 group
144
+ try {
145
+ addTabToAutomationGroup(tabId, clientId);
146
+ } catch (e) {
147
+ Logger.error('[TabGroup] addTabToAutomationGroup threw:', e.message || e);
148
+ }
146
149
  setTimeout(resolve, 100);
147
150
  });
148
151
  }
@@ -165,7 +168,11 @@ var SpecialHandler = (function() {
165
168
  WebSocketManager.send({ type: 'tabgroup-debug', tabId: tabId, clientId: clientId, phase: 'start' });
166
169
 
167
170
  setTimeout(function() {
168
- muteTabIfNeeded(tabId);
171
+ try {
172
+ muteTabIfNeeded(tabId);
173
+ } catch (e) {
174
+ Logger.error('[TabGroup] muteTabIfNeeded threw:', e.message || e);
175
+ }
169
176
  }, 200);
170
177
 
171
178
  var groupClientId = clientId;
@@ -188,6 +195,11 @@ var SpecialHandler = (function() {
188
195
  function doGroup(tabId, clientId, baseName, retries) {
189
196
  retries = retries || 0;
190
197
  Logger.info('[TabGroup] doGroup: tabId=' + tabId + ' clientId=' + (clientId || 'none') + ' baseName=' + baseName + ' retry=' + retries);
198
+ if (!chrome.tabGroups) {
199
+ Logger.warn('[TabGroup] chrome.tabGroups API not available (headless mode?), skipping grouping for tab:', tabId);
200
+ EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'skip', reason: 'tabGroups-unavailable', tabId: tabId });
201
+ return;
202
+ }
191
203
  chrome.tabGroups.query({}, function(allGroups) {
192
204
  if (chrome.runtime.lastError) {
193
205
  Logger.error('[TabGroup] tabGroups.query failed:', chrome.runtime.lastError.message);
@@ -223,21 +235,26 @@ var SpecialHandler = (function() {
223
235
  }
224
236
  Logger.info('[TabGroup] chrome.tabs.group returned groupId:', groupId);
225
237
  EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'groupCreated', tabId: tabId, groupId: groupId });
226
- if (groupId) {
227
- chrome.tabGroups.update(groupId, {
228
- title: baseName,
229
- color: CDPUtils.getGroupColorForClient(clientId),
230
- collapsed: true
231
- }, function() {
232
- if (chrome.runtime.lastError) {
233
- Logger.error('[TabGroup] Failed to update group:', chrome.runtime.lastError.message);
234
- EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'updateGroup', error: chrome.runtime.lastError.message, groupId: groupId });
235
- } else {
236
- State.setGroupIdForClient(clientId, groupId);
237
- updateTabGroupName(clientId);
238
- Logger.info('[TabGroup] Created new group:', groupId, 'with tab:', tabId);
239
- }
240
- });
238
+ if (groupId) {
239
+ if (chrome.tabGroups) {
240
+ chrome.tabGroups.update(groupId, {
241
+ title: baseName,
242
+ color: CDPUtils.getGroupColorForClient(clientId),
243
+ collapsed: true
244
+ }, function() {
245
+ if (chrome.runtime.lastError) {
246
+ Logger.error('[TabGroup] Failed to update group:', chrome.runtime.lastError.message);
247
+ EventBuilder.send('CDPTunnel.debug', { source: 'doGroup', phase: 'updateGroup', error: chrome.runtime.lastError.message, groupId: groupId });
248
+ } else {
249
+ State.setGroupIdForClient(clientId, groupId);
250
+ updateTabGroupName(clientId);
251
+ Logger.info('[TabGroup] Group updated:', groupId, baseName);
252
+ }
253
+ });
254
+ } else {
255
+ State.setGroupIdForClient(clientId, groupId);
256
+ Logger.info('[TabGroup] Group created but tabGroups.update unavailable (headless):', groupId);
257
+ }
241
258
  } else {
242
259
  Logger.error('[TabGroup] chrome.tabs.group returned null groupId');
243
260
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "CDP Bridge",
4
- "version": "2.7.3",
4
+ "version": "2.7.5",
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:23297/plugin',
2
+ WS_URL: 'ws://localhost:58288/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": "2.7.3",
3
+ "version": "2.7.5",
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",
@@ -788,24 +788,16 @@ function handlePluginConnection(ws, clientInfo, request) {
788
788
  } else if (targetId && (parsed.method === 'Target.targetCreated' || parsed.method === 'Target.attachedToTarget')) {
789
789
  const pendingMap = parsed.method === 'Target.targetCreated' ? ns.pendingTargetCreatedEvents : ns.pendingAttachedEvents;
790
790
 
791
- let routedToDiscoverer = false;
792
- if (ns.discoveringClientIds.size > 0) {
793
- for (const [discClientId, timestamp] of ns.discoveringClientIds) {
794
- if (Date.now() - timestamp < 30000) {
795
- const discWs = clientById.get(discClientId);
796
- if (discWs && discWs.readyState === WebSocket.OPEN) {
797
- discWs.send(cdpData);
798
- routedToDiscoverer = true;
799
- }
800
- } else {
801
- ns.discoveringClientIds.delete(discClientId);
802
- }
803
- }
804
- }
791
+ // Check if there's a pending Target.createTarget from any client.
792
+ // If so, cache this event — createTarget response will deliver it to the right client.
793
+ // If not, broadcast to discovering clients (for emitAutoAttachForExistingTargets etc.)
794
+ const hasPendingCreateTarget = Array.from(globalRequestIdMap.values()).some(m => m.isCreateTarget);
805
795
 
806
- if (!routedToDiscoverer) {
796
+ if (hasPendingCreateTarget) {
807
797
  pendingMap.set(targetId, { parsed: JSON.parse(JSON.stringify(parsed)), cdpData });
808
- console.log(`[TARGET EVENT PENDING] ${parsed.method} targetId=${targetId?.substring(0,8)} (cached, waiting for createTarget response)`);
798
+ console.log(`[TARGET EVENT PENDING] ${parsed.method} targetId=${targetId?.substring(0,8) || 'none'} (cached, waiting for createTarget response)`);
799
+ } else {
800
+ console.log(`[TARGET EVENT DROPPED] ${parsed.method} targetId=${targetId?.substring(0,8) || 'none'} (no owner, dropped for isolation)`);
809
801
  }
810
802
  } else {
811
803
  console.log(`[TARGET EVENT DROPPED] ${parsed.method} targetId=${targetId?.substring(0,8) || 'none'} (no owner, dropped for isolation)`);
@@ -818,7 +810,7 @@ function handlePluginConnection(ws, clientInfo, request) {
818
810
  const sessionId = parsed.params?.sessionId;
819
811
 
820
812
  if (targetId && sessionId) {
821
- const clientId = ws.pairedClientId;
813
+ const clientId = ns.targetIdToClientId.get(targetId) || ws.pairedClientId;
822
814
  if (clientId) {
823
815
  ns.sessionToClientId.set(sessionId, clientId);
824
816
  console.log(`[SESSION MAPPED] sessionId=${sessionId?.substring(0,8) || 'none'} -> clientId=${clientId?.substring(0,8) || 'none'}`);
@@ -938,15 +930,33 @@ function handlePluginConnection(ws, clientInfo, request) {
938
930
  invalidateTargetsCache(ws);
939
931
  }
940
932
 
941
- const originalId = mapping.originalId;
942
- parsed.id = originalId;
943
- if (mapping.sessionId && !parsed.sessionId) {
944
- parsed.sessionId = mapping.sessionId;
933
+ if (mapping.isAutoDefaultPage) {
934
+ console.log(`[AUTO DEFAULT PAGE] createTarget response received for client=${mapping.clientId}, targetId=${parsed.result?.targetId?.substring(0,8) || 'none'} — skipping response send to client`);
935
+
936
+ if (mapping.pendingSetAutoAttach) {
937
+ const pending = mapping.pendingSetAutoAttach;
938
+ const pendingParsed = pending.parsed;
939
+ const pendingClientId = pending.clientId;
940
+
941
+ console.log(`[AUTO DEFAULT PAGE] Now forwarding pending setAutoAttach for client=${pendingClientId}`);
942
+
943
+ if (ws.readyState === WebSocket.OPEN) {
944
+ const forwardMsg = { ...pendingParsed, __clientId: pendingClientId };
945
+ ws.send(JSON.stringify(forwardMsg));
946
+ console.log(`[SEND TO PLUGIN] Forwarding setAutoAttach for client=${pendingClientId}`);
947
+ }
948
+ }
949
+ } else {
950
+ const originalId = mapping.originalId;
951
+ parsed.id = originalId;
952
+ if (mapping.sessionId && !parsed.sessionId) {
953
+ parsed.sessionId = mapping.sessionId;
954
+ }
955
+ const responseStr = JSON.stringify(parsed);
956
+ console.log(`[SEND TO CLIENT] ${responseStr.substring(0, 300)}`);
957
+ clientWs.send(responseStr);
958
+ console.log(`[ROUTE] Response global=${globalId} -> original=${originalId} -> client=${mapping.clientId} sessionId=${parsed.sessionId?.substring(0,8) || 'none'}`);
945
959
  }
946
- const responseStr = JSON.stringify(parsed);
947
- console.log(`[SEND TO CLIENT] ${responseStr.substring(0, 300)}`);
948
- clientWs.send(responseStr);
949
- console.log(`[ROUTE] Response global=${globalId} -> original=${originalId} -> client=${mapping.clientId} sessionId=${parsed.sessionId?.substring(0,8) || 'none'}`);
950
960
  }
951
961
  globalRequestIdMap.delete(globalId);
952
962
  } else {
@@ -1042,6 +1052,52 @@ function handlePluginConnection(ws, clientInfo, request) {
1042
1052
  }));
1043
1053
  }
1044
1054
 
1055
+ function autoCreateDefaultPageAndForward(clientWs, setAutoAttachParsed, originalData, clientId, originalRequestId) {
1056
+ const pluginWs = clientWs.pairedPlugin;
1057
+ if (!pluginWs || pluginWs.readyState !== WebSocket.OPEN) {
1058
+ forwardToPlugin(clientWs, originalData, clientId);
1059
+ return;
1060
+ }
1061
+
1062
+ globalRequestIdCounter++;
1063
+ const createGlobalId = globalRequestIdCounter;
1064
+
1065
+ globalRequestIdMap.set(createGlobalId, {
1066
+ clientId: clientId,
1067
+ originalId: -1,
1068
+ sessionId: null,
1069
+ method: 'Target.createTarget',
1070
+ isCreateTarget: true,
1071
+ isAutoDefaultPage: true,
1072
+ pendingSetAutoAttach: {
1073
+ parsed: setAutoAttachParsed,
1074
+ data: originalData,
1075
+ clientId: clientId,
1076
+ originalRequestId: originalRequestId
1077
+ }
1078
+ });
1079
+
1080
+ const request = {
1081
+ id: createGlobalId,
1082
+ method: 'Target.createTarget',
1083
+ params: { url: 'about:blank' },
1084
+ __clientId: clientId
1085
+ };
1086
+
1087
+ console.log(`[AUTO DEFAULT PAGE] Sending Target.createTarget for client=${clientId} globalId=${createGlobalId}, will forward setAutoAttach after`);
1088
+ pluginWs.send(JSON.stringify(request));
1089
+ }
1090
+
1091
+ function forwardToPlugin(clientWs, data, clientId) {
1092
+ const pluginWs = clientWs.pairedPlugin;
1093
+ if (pluginWs && pluginWs.readyState === WebSocket.OPEN) {
1094
+ console.log(`[SEND TO PLUGIN] method=Target.setAutoAttach clientId=${clientId}`);
1095
+ pluginWs.send(data);
1096
+ } else {
1097
+ broadcastToPlugins(data, clientWs);
1098
+ }
1099
+ }
1100
+
1045
1101
  /**
1046
1102
  * 处理 CDP 客户端连接 (Playwright/Puppeteer)
1047
1103
  */
@@ -1244,6 +1300,12 @@ function handleClientConnection(ws, clientInfo, customClientId = null, targetPlu
1244
1300
  }
1245
1301
  }
1246
1302
 
1303
+ if (parsed && parsed.method === 'Target.setAutoAttach' && parsed.params?.autoAttach && !ws._autoDefaultPageSent) {
1304
+ ws._autoDefaultPageSent = true;
1305
+ autoCreateDefaultPageAndForward(ws, parsed, modifiedData, id, originalId);
1306
+ return;
1307
+ }
1308
+
1247
1309
  if (parsed && parsed.method === 'Browser.close') {
1248
1310
  if (shouldLog('info')) {
1249
1311
  console.log(`\n[BROWSER CLOSE] Client ${id} requested Browser.close, forwarding to plugin`);