cdp-tunnel 2.5.22 → 2.6.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.
@@ -422,51 +422,51 @@ function checkTabVisibility(tabId) {
422
422
 
423
423
  var isCDPCreated = State.isCDPCreatedTab(tabId);
424
424
  var isOwnedByClient = isCDPCreated && State.getClientIdByTabId(tabId) === clientId;
425
+ var otherClientOwns = isCDPCreated && !isOwnedByClient;
425
426
 
426
- if (!isOwnedByClient) {
427
- Logger.info('[CDP] Skipping user/other-client tab:', targetId, 'tabId:', tabId, 'cdpCreated:', isCDPCreated);
427
+ if (otherClientOwns) {
428
+ Logger.info('[CDP] Skipping other-client tab:', targetId, 'tabId:', tabId);
428
429
  State.addEmittedTarget(targetId);
429
430
  return;
430
431
  }
431
432
 
432
433
  State.addEmittedTarget(targetId);
433
434
  var targetInfo = LocalHandler.mapToTargetInfo(target);
435
+ var isPreExisting = !isCDPCreated;
434
436
 
435
- Logger.info('[CDP] Emitting CDP-owned target:', targetId, 'tabId:', tabId);
437
+ Logger.info('[CDP] Emitting target:', targetId, 'tabId:', tabId, 'preExisting:', isPreExisting);
436
438
 
437
439
  EventBuilder.send('Target.targetCreated', { targetInfo: targetInfo });
438
440
 
439
- if (target.attached) {
440
- promises.push(Promise.resolve().then(function() {
441
- var sessionId = CDPUtils.generateSessionId();
442
- State.mapSession(sessionId, tabId, targetId);
441
+ var attachLogic = function(attached) {
442
+ var sessionId = CDPUtils.generateSessionId();
443
+ State.mapSession(sessionId, tabId, targetId);
443
444
 
444
- if (config.waitForDebuggerOnStart) {
445
- State.addPendingDebuggerTab(tabId);
446
- }
445
+ if (isPreExisting && clientId) {
446
+ State.setTabIdToClientId(tabId, clientId);
447
+ }
448
+ if (isPreExisting) {
449
+ State.addPreExistingTab(tabId);
450
+ }
447
451
 
448
- EventBuilder.send('Target.attachedToTarget', {
449
- sessionId: sessionId,
450
- targetInfo: Object.assign({}, targetInfo, { attached: true }),
451
- waitingForDebugger: config.waitForDebuggerOnStart || false
452
- });
453
- }));
452
+ if (config.waitForDebuggerOnStart) {
453
+ State.addPendingDebuggerTab(tabId);
454
+ }
455
+
456
+ EventBuilder.send('Target.attachedToTarget', {
457
+ sessionId: sessionId,
458
+ targetInfo: Object.assign({}, targetInfo, { attached: true }),
459
+ waitingForDebugger: config.waitForDebuggerOnStart || false
460
+ });
461
+ };
462
+
463
+ if (target.attached) {
464
+ promises.push(Promise.resolve().then(function() { attachLogic(true); }));
454
465
  } else {
455
466
  promises.push(
456
467
  DebuggerManager.attach(tabId).then(function(attached) {
457
468
  if (!attached) return;
458
- var sessionId = CDPUtils.generateSessionId();
459
- State.mapSession(sessionId, tabId, targetId);
460
-
461
- if (config.waitForDebuggerOnStart) {
462
- State.addPendingDebuggerTab(tabId);
463
- }
464
-
465
- EventBuilder.send('Target.attachedToTarget', {
466
- sessionId: sessionId,
467
- targetInfo: Object.assign({}, targetInfo, { attached: true }),
468
- waitingForDebugger: config.waitForDebuggerOnStart || false
469
- });
469
+ attachLogic(attached);
470
470
  })
471
471
  );
472
472
  }
@@ -33,25 +33,12 @@ var DebuggerManager = (function() {
33
33
  if (tagName.toLowerCase() === 'iframe') {
34
34
  var originalSetAttribute = element.setAttribute;
35
35
  element.setAttribute = function(name, value) {
36
- if (name.toLowerCase() === 'src' && isInternalUrl(value)) {
36
+ if (name.toLowerCase() === 'src' && isInternalUrl(String(value || ''))) {
37
37
  console.warn('[CDP-BLOCK] Blocked iframe src:', value);
38
- return;
38
+ return element;
39
39
  }
40
40
  return originalSetAttribute.call(this, name, value);
41
41
  };
42
-
43
- Object.defineProperty(element, 'src', {
44
- set: function(value) {
45
- if (isInternalUrl(value)) {
46
- console.warn('[CDP-BLOCK] Blocked iframe src via property:', value);
47
- return;
48
- }
49
- originalSetAttribute.call(this, 'src', value);
50
- },
51
- get: function() {
52
- return element.getAttribute('src');
53
- }
54
- });
55
42
  }
56
43
  return element;
57
44
  };
@@ -68,18 +55,25 @@ var DebuggerManager = (function() {
68
55
 
69
56
  // 拦截 location 修改
70
57
  var locationDescriptor = Object.getOwnPropertyDescriptor(window, 'location');
71
- Object.defineProperty(window, 'location', {
72
- set: function(value) {
73
- if (isInternalUrl(String(value))) {
74
- console.warn('[CDP-BLOCK] Blocked location change:', value);
75
- return;
76
- }
77
- locationDescriptor.set.call(window, value);
78
- },
79
- get: function() {
80
- return locationDescriptor.get.call(window);
58
+ if (locationDescriptor && typeof locationDescriptor.set === 'function') {
59
+ try {
60
+ Object.defineProperty(window, 'location', {
61
+ set: function(value) {
62
+ if (isInternalUrl(String(value))) {
63
+ console.warn('[CDP-BLOCK] Blocked location change:', value);
64
+ return;
65
+ }
66
+ locationDescriptor.set.call(window, value);
67
+ },
68
+ get: function() {
69
+ return locationDescriptor.get.call(window);
70
+ },
71
+ configurable: true
72
+ });
73
+ } catch(e) {
74
+ // location property cannot be redefined on some contexts, skip silently
81
75
  }
82
- });
76
+ }
83
77
 
84
78
  console.log('[CDP-BLOCK] Internal URL block script injected');
85
79
  })();
@@ -222,17 +216,22 @@ var DebuggerManager = (function() {
222
216
  return;
223
217
  }
224
218
 
225
- // 在新的执行上下文中也注入拦截脚本
219
+ // 在新的执行上下文中也注入拦截脚本(data: URL 上下文跳过,避免干扰导航)
226
220
  if (isDefaultContext) {
227
- chrome.debugger.sendCommand(
228
- { tabId: source.tabId },
229
- 'Runtime.evaluate',
230
- {
231
- expression: INTERNAL_URL_BLOCK_SCRIPT,
232
- contextId: context.id,
233
- runImmediately: true
234
- }
235
- ).catch(function() {});
221
+ chrome.tabs.get(source.tabId, function(tab) {
222
+ if (chrome.runtime.lastError) return;
223
+ var tabUrl = tab ? (tab.url || tab.pendingUrl || '') : '';
224
+ if (tabUrl.startsWith('data:')) return;
225
+ chrome.debugger.sendCommand(
226
+ { tabId: source.tabId },
227
+ 'Runtime.evaluate',
228
+ {
229
+ expression: INTERNAL_URL_BLOCK_SCRIPT,
230
+ contextId: context.id,
231
+ runImmediately: true
232
+ }
233
+ ).catch(function() {});
234
+ });
236
235
  }
237
236
  }
238
237
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdp-tunnel",
3
- "version": "2.5.22",
3
+ "version": "2.6.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",
@@ -167,6 +167,7 @@ class PluginNamespace {
167
167
  this.cachedTargets = [];
168
168
  this.lastTargetsUpdate = 0;
169
169
  this.cachedBrowserVersion = null;
170
+ this.discoveringClientIds = new Map();
170
171
  }
171
172
  }
172
173
 
@@ -505,6 +506,7 @@ function cleanupClient(ws, id, reason) {
505
506
  if (ns.clientIdToBrowserContext.has(id)) {
506
507
  ns.clientIdToBrowserContext.delete(id);
507
508
  }
509
+ ns.discoveringClientIds.delete(id);
508
510
  }
509
511
  for (const [gId, mapping] of globalRequestIdMap.entries()) {
510
512
  if (mapping.clientId === id) globalRequestIdMap.delete(gId);
@@ -787,8 +789,27 @@ function handlePluginConnection(ws, clientInfo, request) {
787
789
  }
788
790
  } else if (targetId && (parsed.method === 'Target.targetCreated' || parsed.method === 'Target.attachedToTarget')) {
789
791
  const pendingMap = parsed.method === 'Target.targetCreated' ? ns.pendingTargetCreatedEvents : ns.pendingAttachedEvents;
790
- pendingMap.set(targetId, { parsed: JSON.parse(JSON.stringify(parsed)), cdpData });
791
- console.log(`[TARGET EVENT PENDING] ${parsed.method} targetId=${targetId?.substring(0,8)} (cached, waiting for createTarget response)`);
792
+
793
+ let routedToDiscoverer = false;
794
+ if (ns.discoveringClientIds.size > 0) {
795
+ for (const [discClientId, timestamp] of ns.discoveringClientIds) {
796
+ if (Date.now() - timestamp < 30000) {
797
+ const discWs = clientById.get(discClientId);
798
+ if (discWs && discWs.readyState === WebSocket.OPEN) {
799
+ discWs.send(cdpData);
800
+ console.log(`[TARGET EVENT DISCOVERED] ${parsed.method} targetId=${targetId?.substring(0,8)} -> discovering client=${discClientId}`);
801
+ routedToDiscoverer = true;
802
+ }
803
+ } else {
804
+ ns.discoveringClientIds.delete(discClientId);
805
+ }
806
+ }
807
+ }
808
+
809
+ if (!routedToDiscoverer) {
810
+ pendingMap.set(targetId, { parsed: JSON.parse(JSON.stringify(parsed)), cdpData });
811
+ console.log(`[TARGET EVENT PENDING] ${parsed.method} targetId=${targetId?.substring(0,8)} (cached, waiting for createTarget response)`);
812
+ }
792
813
  } else {
793
814
  console.log(`[TARGET EVENT DROPPED] ${parsed.method} targetId=${targetId?.substring(0,8) || 'none'} (no owner, dropped for isolation)`);
794
815
  }
@@ -905,9 +926,11 @@ function handlePluginConnection(ws, clientInfo, request) {
905
926
  }
906
927
  if (mapping.isGetTargets && parsed.result && parsed.result.targetInfos) {
907
928
  const clientId = mapping.clientId;
929
+ const pluginWsForGetTargets = ws;
908
930
  parsed.result.targetInfos = parsed.result.targetInfos.filter(t => {
909
931
  if (t.type !== 'page') return true;
910
932
  const ownerClient = ns.targetIdToClientId.get(t.targetId);
933
+ if (!ownerClient) return true;
911
934
  return ownerClient === clientId;
912
935
  });
913
936
  console.log(`[GET TARGETS FILTERED] client=${clientId} returned ${parsed.result.targetInfos.filter(t => t.type === 'page').length} page targets`);
@@ -1218,6 +1241,14 @@ function handleClientConnection(ws, clientInfo, customClientId = null, targetPlu
1218
1241
  }
1219
1242
  }
1220
1243
 
1244
+ if (parsed && (parsed.method === 'Target.setDiscoverTargets' || parsed.method === 'Target.setAutoAttach')) {
1245
+ const ns = ws.pairedPlugin ? getNamespace(ws.pairedPlugin) : null;
1246
+ if (ns) {
1247
+ ns.discoveringClientIds.set(id, Date.now());
1248
+ console.log(`[DISCOVERING] client=${id} method=${parsed.method}`);
1249
+ }
1250
+ }
1251
+
1221
1252
  if (parsed && parsed.method === 'Browser.close') {
1222
1253
  if (shouldLog('info')) {
1223
1254
  console.log(`\n[BROWSER CLOSE] Client ${id} requested Browser.close, forwarding to plugin`);