cdp-tunnel 2.9.4 → 2.10.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/README.md +1 -1
- package/extension-new/config-page-preview.html +24 -0
- package/extension-new/config-page.js +25 -0
- package/extension-new/manifest.json +1 -1
- package/extension-new/popup.html +21 -0
- package/extension-new/popup.js +10 -1
- package/extension-new/utils/config.js +1 -1
- package/package.json +1 -2
- package/server/proxy-server.js +10 -0
package/README.md
CHANGED
|
@@ -102,7 +102,7 @@ The server will start on `localhost:9221`.
|
|
|
102
102
|
|
|
103
103
|
#### 3. Connect the Extension
|
|
104
104
|
|
|
105
|
-
Click the extension icon,
|
|
105
|
+
Click the extension icon, then click **打开完整配置** to open the configuration page. Add a connection: fill in Name (e.g., "local"), WebSocket URL (default `ws://localhost:9221/plugin`), and Mode (create/takeover). The CDP address will be displayed (e.g., `http://localhost:9221` for create mode, `http://localhost:9222` for takeover mode). Copy it and use it in Playwright: `chromium.connectOverCDP('http://localhost:9221')`.
|
|
106
106
|
|
|
107
107
|
### 3. Client Connection
|
|
108
108
|
|
|
@@ -254,6 +254,27 @@
|
|
|
254
254
|
.status-dot.error { background: #f44336; box-shadow: 0 0 0 2px rgba(244, 67, 54, 0.2); }
|
|
255
255
|
.status-dot.disabled { background: #9e9e9e; }
|
|
256
256
|
|
|
257
|
+
.status-connected { color: #4caf50; font-size: 11px; font-weight: 600; }
|
|
258
|
+
.status-error { color: #f44336; font-size: 11px; font-weight: 600; }
|
|
259
|
+
.status-error-hint {
|
|
260
|
+
display: block;
|
|
261
|
+
font-size: 11px;
|
|
262
|
+
margin-top: 4px;
|
|
263
|
+
color: #999;
|
|
264
|
+
}
|
|
265
|
+
.status-error-hint code {
|
|
266
|
+
background: rgba(244, 67, 54, 0.1);
|
|
267
|
+
color: #f44336;
|
|
268
|
+
padding: 2px 4px;
|
|
269
|
+
border-radius: 3px;
|
|
270
|
+
font-family: monospace;
|
|
271
|
+
}
|
|
272
|
+
.status-disabled { color: #9e9e9e; font-size: 11px; }
|
|
273
|
+
.conn-config-status {
|
|
274
|
+
margin-top: 4px;
|
|
275
|
+
font-size: 11px;
|
|
276
|
+
}
|
|
277
|
+
|
|
257
278
|
.conn-config-item input[type="checkbox"] {
|
|
258
279
|
width: 16px;
|
|
259
280
|
height: 16px;
|
|
@@ -849,6 +870,9 @@
|
|
|
849
870
|
<option value="create">创建模式</option>
|
|
850
871
|
<option value="takeover">接管模式</option>
|
|
851
872
|
</select>
|
|
873
|
+
<div id="modeHint" style="display:none; font-size:11px; color:#999; margin-top:4px; grid-column:1/-1;">
|
|
874
|
+
🔗 接管模式将使用端口 <span id="takeoverPortHint"></span> 作为 CDP 端点
|
|
875
|
+
</div>
|
|
852
876
|
<button class="btn btn-primary btn-sm" id="addConnBtn">添加连接</button>
|
|
853
877
|
</div>
|
|
854
878
|
</div>
|
|
@@ -80,6 +80,12 @@
|
|
|
80
80
|
return 'disabled';
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function getStatusHtml(status) {
|
|
84
|
+
if (status === 'connected') return '<span class="status-connected">已连接</span>';
|
|
85
|
+
if (status === 'error') return '<span class="status-error">连接失败</span><br><span class="status-error-hint">💡 运行 <code>cdp-tunnel diagnose</code> 排查</span>';
|
|
86
|
+
return '<span class="status-disabled">未连接</span>';
|
|
87
|
+
}
|
|
88
|
+
|
|
83
89
|
function renderConnections(connections) {
|
|
84
90
|
if (!connections || connections.length === 0) {
|
|
85
91
|
elements.connConfigList.innerHTML =
|
|
@@ -96,6 +102,7 @@
|
|
|
96
102
|
var statusClass = getStatusClass(conn.id, conn.enabled);
|
|
97
103
|
var isActive = conn.enabled && statusClass === 'connected';
|
|
98
104
|
var cdpAddr = getCdpAddress(conn.url, conn.mode);
|
|
105
|
+
var statusHtml = getStatusHtml(statusClass);
|
|
99
106
|
html +=
|
|
100
107
|
'<div class="conn-config-item' + (isActive ? ' active' : '') + '" data-id="' + conn.id + '">' +
|
|
101
108
|
'<input type="checkbox" class="conn-toggle" data-id="' + conn.id + '"' + (conn.enabled ? ' checked' : '') + ' title="启用/禁用">' +
|
|
@@ -104,6 +111,7 @@
|
|
|
104
111
|
'<div class="conn-config-tag">' + (conn.mode === 'takeover' ? '🔗 ' : '🆕 ') + escapeHtml(conn.tag) + '</div>' +
|
|
105
112
|
'<div class="conn-config-url" title="' + escapeAttr(conn.url) + '">WS: ' + escapeHtml(conn.url) + '</div>' +
|
|
106
113
|
(cdpAddr ? '<div class="conn-config-cdp">CDP: <span class="cdp-addr" data-cdp="' + escapeAttr(cdpAddr) + '">' + escapeHtml(cdpAddr) + '</span> <button class="btn-copy-cdp" data-cdp="' + escapeAttr(cdpAddr) + '" title="复制 CDP 地址">📋</button></div>' : '') +
|
|
114
|
+
'<div class="conn-config-status">' + statusHtml + '</div>' +
|
|
107
115
|
'</div>' +
|
|
108
116
|
'<button class="btn-delete" data-id="' + conn.id + '" title="删除">删除</button>' +
|
|
109
117
|
'</div>';
|
|
@@ -326,6 +334,23 @@
|
|
|
326
334
|
addLog('action', e.target.checked ? '自动静音已开启' : '自动静音已关闭');
|
|
327
335
|
});
|
|
328
336
|
|
|
337
|
+
elements.inputMode.addEventListener('change', function(e) {
|
|
338
|
+
var modeHint = document.getElementById('modeHint');
|
|
339
|
+
var takeoverPortHint = document.getElementById('takeoverPortHint');
|
|
340
|
+
var url = elements.newConnUrl.value;
|
|
341
|
+
|
|
342
|
+
if (e.target.value === 'takeover') {
|
|
343
|
+
var match = url.match(/:(\d+)/);
|
|
344
|
+
if (match) {
|
|
345
|
+
var port = parseInt(match[1]) + 1;
|
|
346
|
+
takeoverPortHint.textContent = port;
|
|
347
|
+
modeHint.style.display = 'block';
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
modeHint.style.display = 'none';
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
329
354
|
var versionBadge = document.getElementById('versionBadge');
|
|
330
355
|
if (versionBadge && typeof chrome !== 'undefined' && chrome.runtime) {
|
|
331
356
|
var manifest = chrome.runtime.getManifest();
|
package/extension-new/popup.html
CHANGED
|
@@ -31,6 +31,27 @@ body { width: 320px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
|
|
31
31
|
|
|
32
32
|
.empty-hint { text-align: center; padding: 16px 10px; color: #777; font-size: 12px; }
|
|
33
33
|
|
|
34
|
+
.first-time-guide {
|
|
35
|
+
background: rgba(33, 150, 243, 0.1);
|
|
36
|
+
border: 1px solid rgba(33, 150, 243, 0.3);
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
padding: 12px;
|
|
39
|
+
margin-bottom: 16px;
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: 12px;
|
|
42
|
+
}
|
|
43
|
+
.guide-icon {
|
|
44
|
+
font-size: 24px;
|
|
45
|
+
}
|
|
46
|
+
.guide-text {
|
|
47
|
+
font-size: 13px;
|
|
48
|
+
line-height: 1.4;
|
|
49
|
+
}
|
|
50
|
+
.guide-text strong {
|
|
51
|
+
display: block;
|
|
52
|
+
margin-bottom: 4px;
|
|
53
|
+
}
|
|
54
|
+
|
|
34
55
|
.stats-row { display: flex; gap: 16px; padding: 8px 0; font-size: 12px; color: #aaa; }
|
|
35
56
|
.stats-row span b { color: #4a9eff; font-weight: 600; }
|
|
36
57
|
|
package/extension-new/popup.js
CHANGED
|
@@ -27,7 +27,16 @@
|
|
|
27
27
|
connectionList.innerHTML = '';
|
|
28
28
|
|
|
29
29
|
if (!connections || connections.length === 0) {
|
|
30
|
-
|
|
30
|
+
var guideHtml = `
|
|
31
|
+
<div class="first-time-guide">
|
|
32
|
+
<div class="guide-icon">👋</div>
|
|
33
|
+
<div class="guide-text">
|
|
34
|
+
<strong>首次使用?</strong><br>
|
|
35
|
+
请先启动 cdp-tunnel server,然后点击下方按钮配置连接
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
`;
|
|
39
|
+
connectionList.innerHTML = guideHtml;
|
|
31
40
|
return;
|
|
32
41
|
}
|
|
33
42
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdp-tunnel",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1",
|
|
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",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"bcryptjs": "^3.0.3",
|
|
61
61
|
"better-sqlite3": "^12.10.0",
|
|
62
|
-
"cdp-tunnel": "^2.5.17",
|
|
63
62
|
"commander": "^12.0.0",
|
|
64
63
|
"http-proxy": "^1.18.1",
|
|
65
64
|
"jsonwebtoken": "^9.0.3",
|
package/server/proxy-server.js
CHANGED
|
@@ -1165,6 +1165,16 @@ function forwardToPlugin(clientWs, data, clientId) {
|
|
|
1165
1165
|
* 处理 CDP 客户端连接 (Playwright/Puppeteer)
|
|
1166
1166
|
*/
|
|
1167
1167
|
function handleClientConnection(ws, clientInfo, customClientId = null, targetPluginId = null, mode = 'create') {
|
|
1168
|
+
if (mode === 'takeover') {
|
|
1169
|
+
for (const client of clientConnections) {
|
|
1170
|
+
if (client.mode === 'takeover' && client.readyState === WebSocket.OPEN) {
|
|
1171
|
+
console.log('[TAKEOVER] Rejected: takeover mode already has a connected client');
|
|
1172
|
+
ws.close(1008, 'Takeover mode already in use. Only one client allowed.');
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1168
1178
|
clientConnections.add(ws);
|
|
1169
1179
|
const id = customClientId || generateId('client');
|
|
1170
1180
|
ws.mode = mode;
|