cdp-tunnel 2.1.2 → 2.2.1
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.
- package/cli/index.js +15 -0
- package/extension-new/background.js +3 -3
- package/extension-new/config-page-preview.html +1 -1
- package/extension-new/config-page.js +6 -0
- package/extension-new/manifest.json +8 -3
- package/package.json +1 -1
- package/server/modules/logger.js +26 -1
- package/server/proxy-server.js +42 -2
package/cli/index.js
CHANGED
|
@@ -20,6 +20,21 @@ program
|
|
|
20
20
|
.description('Chrome DevTools Protocol Tunnel')
|
|
21
21
|
.version(require(path.join(__dirname, '..', 'package.json')).version);
|
|
22
22
|
|
|
23
|
+
function syncExtensionVersion() {
|
|
24
|
+
try {
|
|
25
|
+
const pkgVersion = require(path.join(__dirname, '..', 'package.json')).version;
|
|
26
|
+
const manifestPath = path.join(__dirname, '..', 'extension-new', 'manifest.json');
|
|
27
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
28
|
+
if (manifest.version !== pkgVersion) {
|
|
29
|
+
manifest.version = pkgVersion;
|
|
30
|
+
manifest.description = `CDP Tunnel v${pkgVersion} — ${manifest.description.split('—')[1] || manifest.description}`.trim();
|
|
31
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
32
|
+
}
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
syncExtensionVersion();
|
|
37
|
+
|
|
23
38
|
function log(color, ...args) {
|
|
24
39
|
const colors = {
|
|
25
40
|
green: '\x1b[32m',
|
|
@@ -158,10 +158,10 @@ importScripts('features/automation-badge.js');
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
var openerTabId = tab.openerTabId;
|
|
161
|
-
var isOpenerControlled = openerTabId && State.isTabAttached(openerTabId);
|
|
161
|
+
var isOpenerControlled = openerTabId && State.isTabAttached(openerTabId) && !State.isPreExistingTab(openerTabId);
|
|
162
162
|
|
|
163
|
-
// 只有当 opener
|
|
164
|
-
//
|
|
163
|
+
// 只有当 opener 是 CDP 主动管理的 tab 时才跟踪新页面
|
|
164
|
+
// pre-existing tab 虽然也 attach 了 debugger,但属于用户 tab,不应继承 CDP 控制
|
|
165
165
|
if (!openerTabId) {
|
|
166
166
|
Logger.info('[Tabs] Tab has no opener, skipping. tabId:', tabId);
|
|
167
167
|
return;
|
|
@@ -657,7 +657,7 @@
|
|
|
657
657
|
<nav class="navbar">
|
|
658
658
|
<div class="navbar-brand">
|
|
659
659
|
<div class="logo">🔌</div>
|
|
660
|
-
<h1>CDP Bridge
|
|
660
|
+
<h1>CDP Bridge <small id="versionBadge" style="font-size:12px;color:#888;font-weight:normal"></small></h1>
|
|
661
661
|
</div>
|
|
662
662
|
<div class="status-badge disconnected" id="statusBadge">
|
|
663
663
|
<div class="dot"></div>
|
|
@@ -267,6 +267,12 @@
|
|
|
267
267
|
chrome.storage.local.set({ autoMute: e.target.checked });
|
|
268
268
|
addLog(e.target.checked ? '🔇 自动静音已开启' : '🔊 自动静音已关闭', 'action');
|
|
269
269
|
});
|
|
270
|
+
|
|
271
|
+
var versionBadge = document.getElementById('versionBadge');
|
|
272
|
+
if (versionBadge) {
|
|
273
|
+
var manifest = chrome.runtime.getManifest();
|
|
274
|
+
versionBadge.textContent = 'v' + manifest.version;
|
|
275
|
+
}
|
|
270
276
|
|
|
271
277
|
fetchState();
|
|
272
278
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "CDP Bridge",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.1",
|
|
5
5
|
"description": "Chrome DevTools Protocol Bridge for Playwright/Puppeteer automation",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"debugger",
|
|
@@ -33,8 +33,13 @@
|
|
|
33
33
|
},
|
|
34
34
|
"web_accessible_resources": [
|
|
35
35
|
{
|
|
36
|
-
"resources": [
|
|
37
|
-
|
|
36
|
+
"resources": [
|
|
37
|
+
"config-page-preview.html",
|
|
38
|
+
"config-page.js"
|
|
39
|
+
],
|
|
40
|
+
"matches": [
|
|
41
|
+
"<all_urls>"
|
|
42
|
+
]
|
|
38
43
|
}
|
|
39
44
|
]
|
|
40
45
|
}
|
package/package.json
CHANGED
package/server/modules/logger.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
3
4
|
|
|
4
5
|
const logDir = path.join(__dirname, '../../logs');
|
|
5
6
|
if (!fs.existsSync(logDir)) {
|
|
6
7
|
fs.mkdirSync(logDir, { recursive: true });
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
const cdpDir = path.join(os.homedir(), '.cdp-tunnel');
|
|
11
|
+
|
|
9
12
|
const logFile = path.join(logDir, 'cdp-debug.log');
|
|
10
13
|
const statusLogFile = path.join(logDir, 'server-status.log');
|
|
14
|
+
const disconnectLogFile = path.join(cdpDir, 'disconnect.log');
|
|
11
15
|
|
|
12
16
|
const MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
13
17
|
const MAX_LOG_FILES = 5;
|
|
@@ -117,6 +121,26 @@ function clearLog() {
|
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
function logDisconnect(event, details) {
|
|
125
|
+
const timestamp = new Date().toISOString();
|
|
126
|
+
const separator = '='.repeat(70);
|
|
127
|
+
const lines = [
|
|
128
|
+
separator,
|
|
129
|
+
`[${timestamp}] ${event}`,
|
|
130
|
+
JSON.stringify(details, null, 2),
|
|
131
|
+
''
|
|
132
|
+
].join('\n');
|
|
133
|
+
try {
|
|
134
|
+
const dir = path.dirname(disconnectLogFile);
|
|
135
|
+
if (!fs.existsSync(dir)) {
|
|
136
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
fs.appendFileSync(disconnectLogFile, lines);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
console.error('[LOGGER] Error writing disconnect log:', e.message);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
120
144
|
const NOISY_METHODS = [
|
|
121
145
|
'Runtime.consoleAPICalled',
|
|
122
146
|
'Network.requestWillBeSent',
|
|
@@ -249,5 +273,6 @@ module.exports = {
|
|
|
249
273
|
logFile,
|
|
250
274
|
logStatus,
|
|
251
275
|
logConnectionEvent,
|
|
252
|
-
flushAllLogs
|
|
276
|
+
flushAllLogs,
|
|
277
|
+
logDisconnect
|
|
253
278
|
};
|
package/server/proxy-server.js
CHANGED
|
@@ -16,7 +16,7 @@ const path = require('path');
|
|
|
16
16
|
const os = require('os');
|
|
17
17
|
const { execSync, spawn: spawnProcess } = require('child_process');
|
|
18
18
|
const { CONFIG, BROWSER_ID, shouldLog } = require('./modules/config');
|
|
19
|
-
const { logCDP, logEvent, clearLog, logStatus, logConnectionEvent, flushAllLogs } = require('./modules/logger');
|
|
19
|
+
const { logCDP, logEvent, clearLog, logStatus, logConnectionEvent, flushAllLogs, logDisconnect } = require('./modules/logger');
|
|
20
20
|
|
|
21
21
|
const PORT = CONFIG.PORT;
|
|
22
22
|
const CONFIG_DIR = path.join(os.homedir(), '.cdp-tunnel');
|
|
@@ -154,11 +154,13 @@ const browserContextToClientId = new Map();
|
|
|
154
154
|
const clientIdToBrowserContext = new Map();
|
|
155
155
|
let globalRequestIdCounter = 0;
|
|
156
156
|
|
|
157
|
+
const { version: PKG_VERSION } = require('../package.json');
|
|
158
|
+
|
|
157
159
|
let cachedTargets = [];
|
|
158
160
|
let lastTargetsUpdate = 0;
|
|
159
161
|
|
|
160
162
|
console.log('='.repeat(60));
|
|
161
|
-
console.log(
|
|
163
|
+
console.log(` WebSocket CDP Proxy Server v${PKG_VERSION}`);
|
|
162
164
|
console.log('='.repeat(60));
|
|
163
165
|
console.log(` Server started on port ${PORT}`);
|
|
164
166
|
console.log(` - Plugin path: ws://localhost:${PORT}/plugin`);
|
|
@@ -697,6 +699,16 @@ function handlePluginConnection(ws, clientInfo) {
|
|
|
697
699
|
}
|
|
698
700
|
});
|
|
699
701
|
|
|
702
|
+
logDisconnect('PLUGIN_DISCONNECTED', {
|
|
703
|
+
pluginId: id,
|
|
704
|
+
code, reason: reason?.toString() || 'none',
|
|
705
|
+
remainingPlugins: pluginConnections.size,
|
|
706
|
+
affectedClients,
|
|
707
|
+
uptime: ws.connectedAt ? `${((Date.now() - ws.connectedAt) / 1000).toFixed(0)}s` : 'unknown',
|
|
708
|
+
activeSessions: sessionToClientId.size,
|
|
709
|
+
pendingRequests: pendingAttachRequests.size
|
|
710
|
+
});
|
|
711
|
+
|
|
700
712
|
if (affectedClients.length > 0) {
|
|
701
713
|
logConnectionEvent('PLUGIN_DISCONNECT_AFFECTED_CLIENTS', { pluginId: id, affectedClients });
|
|
702
714
|
}
|
|
@@ -963,6 +975,20 @@ function handleClientConnection(ws, clientInfo, customClientId = null) {
|
|
|
963
975
|
totalPlugins: pluginConnections.size,
|
|
964
976
|
totalClients: clientConnections.size
|
|
965
977
|
});
|
|
978
|
+
|
|
979
|
+
const isUnexpected = code !== 1000 && code !== 1001;
|
|
980
|
+
if (isUnexpected) {
|
|
981
|
+
logDisconnect('CLIENT_DISCONNECTED_UNEXPECTED', {
|
|
982
|
+
clientId: id,
|
|
983
|
+
code, reason: reason?.toString() || 'none',
|
|
984
|
+
sessionsLost: sessionsToClean.length,
|
|
985
|
+
cdpMethodsUsed: ws.cdpTrace ? [...new Set(ws.cdpTrace)] : [],
|
|
986
|
+
uptime: ws.connectedAt ? `${((Date.now() - ws.connectedAt) / 1000).toFixed(0)}s` : 'unknown',
|
|
987
|
+
remainingClients: clientConnections.size,
|
|
988
|
+
pluginAlive: pluginConnections.size > 0,
|
|
989
|
+
pairedPluginId: ws.pairedPlugin?.id || null
|
|
990
|
+
});
|
|
991
|
+
}
|
|
966
992
|
|
|
967
993
|
if (ws.cdpTrace && ws.cdpTrace.length && shouldLog('debug')) {
|
|
968
994
|
const unique = [...new Set(ws.cdpTrace)];
|
|
@@ -1343,6 +1369,14 @@ const heartbeatInterval = setInterval(() => {
|
|
|
1343
1369
|
console.log(`[${now}] Plugin ${ws.id} not responding, terminating...`);
|
|
1344
1370
|
}
|
|
1345
1371
|
logConnectionEvent('HEARTBEAT_TIMEOUT', { type: 'plugin', id: ws.id });
|
|
1372
|
+
logDisconnect('HEARTBEAT_TIMEOUT_PLUGIN', {
|
|
1373
|
+
pluginId: ws.id,
|
|
1374
|
+
pairedClientId: ws.pairedClientId || null,
|
|
1375
|
+
uptime: ws.connectedAt ? `${((Date.now() - ws.connectedAt) / 1000).toFixed(0)}s` : 'unknown',
|
|
1376
|
+
remainingPlugins: pluginConnections.size,
|
|
1377
|
+
activeClients: clientConnections.size,
|
|
1378
|
+
activeSessions: sessionToClientId.size
|
|
1379
|
+
});
|
|
1346
1380
|
pluginConnections.delete(ws);
|
|
1347
1381
|
if (ws.pairedClientId) {
|
|
1348
1382
|
connectionPairs.delete(ws.pairedClientId);
|
|
@@ -1365,6 +1399,12 @@ const heartbeatInterval = setInterval(() => {
|
|
|
1365
1399
|
console.log(`[${now}] Client ${ws.id} not responding, terminating...`);
|
|
1366
1400
|
}
|
|
1367
1401
|
logConnectionEvent('HEARTBEAT_TIMEOUT', { type: 'client', id: ws.id });
|
|
1402
|
+
logDisconnect('HEARTBEAT_TIMEOUT_CLIENT', {
|
|
1403
|
+
clientId: ws.id,
|
|
1404
|
+
uptime: ws.connectedAt ? `${((Date.now() - ws.connectedAt) / 1000).toFixed(0)}s` : 'unknown',
|
|
1405
|
+
remainingClients: clientConnections.size,
|
|
1406
|
+
pluginAlive: pluginConnections.size > 0
|
|
1407
|
+
});
|
|
1368
1408
|
clientConnections.delete(ws);
|
|
1369
1409
|
clientById.delete(ws.id);
|
|
1370
1410
|
if (ws.pairedPlugin) {
|