cdp-tunnel 1.0.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.
Files changed (46) hide show
  1. package/.github/workflows/publish.yml +92 -0
  2. package/.github/workflows/release-assets.yml +50 -0
  3. package/LICENSE +81 -0
  4. package/PUBLISH.md +65 -0
  5. package/README.md +228 -0
  6. package/cli/guide.html +753 -0
  7. package/cli/icon.svg +13 -0
  8. package/cli/icon128.png +0 -0
  9. package/cli/index.js +357 -0
  10. package/docs/README_CN.md +204 -0
  11. package/docs/config-page-screenshot.png +0 -0
  12. package/extension-new/background.js +294 -0
  13. package/extension-new/cdp/handler/forward.js +44 -0
  14. package/extension-new/cdp/handler/local.js +233 -0
  15. package/extension-new/cdp/handler/special.js +442 -0
  16. package/extension-new/cdp/index.js +104 -0
  17. package/extension-new/cdp/response.js +49 -0
  18. package/extension-new/config-page-preview.html +769 -0
  19. package/extension-new/config-page.js +318 -0
  20. package/extension-new/core/debugger.js +310 -0
  21. package/extension-new/core/state.js +384 -0
  22. package/extension-new/core/websocket.js +326 -0
  23. package/extension-new/features/automation-badge.js +113 -0
  24. package/extension-new/features/screencast.js +221 -0
  25. package/extension-new/icons/icon128.png +0 -0
  26. package/extension-new/icons/icon16.png +0 -0
  27. package/extension-new/icons/icon48.png +0 -0
  28. package/extension-new/manifest.json +39 -0
  29. package/extension-new/popup.html +72 -0
  30. package/extension-new/popup.js +34 -0
  31. package/extension-new/utils/config.js +20 -0
  32. package/extension-new/utils/diagnostics.js +560 -0
  33. package/extension-new/utils/helpers.js +25 -0
  34. package/extension-new/utils/logger.js +64 -0
  35. package/package.json +42 -0
  36. package/server/modules/config.js +28 -0
  37. package/server/modules/logger.js +197 -0
  38. package/server/proxy-server.js +1431 -0
  39. package/tests/playwright-demo.js +45 -0
  40. package/tests/playwright-interactive.js +261 -0
  41. package/tests/playwright-multi-demo.js +60 -0
  42. package/tests/playwright-multi.js +85 -0
  43. package/tests/playwright-single.js +41 -0
  44. package/tests/screenshot-config.js +35 -0
  45. package/tests/test-client.js +89 -0
  46. package/tests/test-multi-client.js +129 -0
@@ -0,0 +1,28 @@
1
+ const CONFIG = {
2
+ PORT: 9221,
3
+ HEARTBEAT_INTERVAL: 30000,
4
+ STATUS_PRINT_INTERVAL: 60000,
5
+ TARGETS_CACHE_TTL: 2000,
6
+ TARGETS_REQUEST_TIMEOUT: 1000,
7
+ CDP_TRACE_MAX_LENGTH: 300,
8
+ LOG_MESSAGE_PREVIEW_LENGTH: 1000,
9
+ CLIENT_IDLE_TIMEOUT: 300000,
10
+ LOG_LEVEL: process.env.LOG_LEVEL || 'info'
11
+ };
12
+
13
+ const LOG_LEVELS = {
14
+ debug: 0,
15
+ info: 1,
16
+ warn: 2,
17
+ error: 3
18
+ };
19
+
20
+ function shouldLog(level) {
21
+ const currentLevel = LOG_LEVELS[CONFIG.LOG_LEVEL] ?? LOG_LEVELS.info;
22
+ const targetLevel = LOG_LEVELS[level] ?? LOG_LEVELS.info;
23
+ return targetLevel >= currentLevel;
24
+ }
25
+
26
+ const BROWSER_ID = `browser_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
27
+
28
+ module.exports = { CONFIG, BROWSER_ID, shouldLog };
@@ -0,0 +1,197 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const logDir = path.join(__dirname, '../../logs');
5
+ if (!fs.existsSync(logDir)) {
6
+ fs.mkdirSync(logDir, { recursive: true });
7
+ }
8
+
9
+ const logFile = path.join(logDir, 'cdp-debug.log');
10
+ const statusLogFile = path.join(logDir, 'server-status.log');
11
+
12
+ const MAX_LOG_SIZE = 10 * 1024 * 1024;
13
+ const MAX_LOG_FILES = 5;
14
+
15
+ let logWriteQueue = [];
16
+ let isWritingLog = false;
17
+ let statusWriteQueue = [];
18
+ let isWritingStatus = false;
19
+
20
+ function checkAndRotateLog(filePath) {
21
+ try {
22
+ const stats = fs.statSync(filePath);
23
+ if (stats.size >= MAX_LOG_SIZE) {
24
+ const ext = path.extname(filePath);
25
+ const base = path.basename(filePath, ext);
26
+ const dir = path.dirname(filePath);
27
+
28
+ for (let i = MAX_LOG_FILES - 1; i >= 1; i--) {
29
+ const oldFile = path.join(dir, `${base}.${i}${ext}`);
30
+ const newFile = path.join(dir, `${base}.${i + 1}${ext}`);
31
+ if (fs.existsSync(oldFile)) {
32
+ if (i === MAX_LOG_FILES - 1) {
33
+ fs.unlinkSync(oldFile);
34
+ } else {
35
+ fs.renameSync(oldFile, newFile);
36
+ }
37
+ }
38
+ }
39
+
40
+ const firstBackup = path.join(dir, `${base}.1${ext}`);
41
+ fs.renameSync(filePath, firstBackup);
42
+ return true;
43
+ }
44
+ } catch (e) {
45
+ // 文件不存在,忽略
46
+ }
47
+ return false;
48
+ }
49
+
50
+ function flushLogQueue() {
51
+ if (logWriteQueue.length === 0 || isWritingLog) return;
52
+
53
+ isWritingLog = true;
54
+ const dataToWrite = logWriteQueue.join('');
55
+ logWriteQueue = [];
56
+
57
+ fs.writeFile(logFile, dataToWrite, { flag: 'a' }, (err) => {
58
+ isWritingLog = false;
59
+ if (err) console.error('[LOGGER] Error writing log:', err.message);
60
+
61
+ if (logWriteQueue.length > 0) {
62
+ setImmediate(flushLogQueue);
63
+ }
64
+ });
65
+ }
66
+
67
+ function flushStatusQueue() {
68
+ if (statusWriteQueue.length === 0 || isWritingStatus) return;
69
+
70
+ isWritingStatus = true;
71
+ const dataToWrite = statusWriteQueue.join('');
72
+ statusWriteQueue = [];
73
+
74
+ fs.writeFile(statusLogFile, dataToWrite, { flag: 'a' }, (err) => {
75
+ isWritingStatus = false;
76
+ if (err) console.error('[LOGGER] Error writing status log:', err.message);
77
+
78
+ if (statusWriteQueue.length > 0) {
79
+ setImmediate(flushStatusQueue);
80
+ }
81
+ });
82
+ }
83
+
84
+ function checkLogRotation() {
85
+ checkAndRotateLog(logFile);
86
+ checkAndRotateLog(statusLogFile);
87
+ }
88
+
89
+ setInterval(checkLogRotation, 60000);
90
+
91
+ function clearLog() {
92
+ try {
93
+ fs.writeFileSync(logFile, '');
94
+ fs.writeFileSync(statusLogFile, '');
95
+ } catch (e) {
96
+ console.error('[LOGGER] Error clearing logs:', e.message);
97
+ }
98
+ }
99
+
100
+ const NOISY_METHODS = [
101
+ 'Runtime.consoleAPICalled',
102
+ 'Network.requestWillBeSent',
103
+ 'Network.requestWillBeSentExtraInfo',
104
+ 'Network.responseReceived',
105
+ 'Network.responseReceivedExtraInfo',
106
+ 'Network.dataReceived',
107
+ 'Network.loadingFinished',
108
+ 'Input.dispatchMouseEvent',
109
+ ];
110
+
111
+ function truncateMessage(message) {
112
+ try {
113
+ const parsed = JSON.parse(message);
114
+ if (parsed.method === 'Page.screencastFrame' && parsed.params?.data) {
115
+ const truncated = { ...parsed };
116
+ truncated.params = { ...parsed.params };
117
+ truncated.params.data = `[BASE64_IMAGE_${parsed.params.data.length}bytes]`;
118
+ return JSON.stringify(truncated);
119
+ }
120
+ if (parsed.method === 'Page.screencastFrameAck') {
121
+ const truncated = { ...parsed };
122
+ truncated.params = { sessionId: parsed.params?.sessionId };
123
+ return JSON.stringify(truncated);
124
+ }
125
+ if (NOISY_METHODS.includes(parsed.method)) {
126
+ return null;
127
+ }
128
+ return message;
129
+ } catch {
130
+ return message;
131
+ }
132
+ }
133
+
134
+ function logCDP(direction, message, sessionId = null, pluginType = null) {
135
+ const truncatedMessage = truncateMessage(message);
136
+ if (truncatedMessage === null) {
137
+ return;
138
+ }
139
+ const timestamp = new Date().toISOString();
140
+ const sessionPrefix = sessionId ? `[session:${sessionId.substring(0, 8)}]` : '';
141
+ const typePrefix = pluginType ? `[${pluginType}]` : '';
142
+ const logLine = `[${timestamp}] ${typePrefix}${sessionPrefix}[${direction}] ${truncatedMessage}\n`;
143
+
144
+ logWriteQueue.push(logLine);
145
+ if (logWriteQueue.length > 100) {
146
+ flushLogQueue();
147
+ }
148
+ }
149
+
150
+ function logEvent(event, details) {
151
+ const timestamp = new Date().toISOString();
152
+ const logLine = `[${timestamp}] [EVENT] ${event} ${details}\n`;
153
+
154
+ logWriteQueue.push(logLine);
155
+ if (logWriteQueue.length > 100) {
156
+ flushLogQueue();
157
+ }
158
+ }
159
+
160
+ function logStatus(status) {
161
+ const timestamp = new Date().toISOString();
162
+ const logLine = `[${timestamp}] ${JSON.stringify(status)}\n`;
163
+
164
+ statusWriteQueue.push(logLine);
165
+ if (statusWriteQueue.length > 100) {
166
+ flushStatusQueue();
167
+ }
168
+ }
169
+
170
+ function logConnectionEvent(event, data) {
171
+ const timestamp = new Date().toISOString();
172
+ const logLine = `[${timestamp}] [${event}] ${JSON.stringify(data)}\n`;
173
+
174
+ statusWriteQueue.push(logLine);
175
+ if (statusWriteQueue.length > 100) {
176
+ flushStatusQueue();
177
+ }
178
+ }
179
+
180
+ function flushAllLogs() {
181
+ flushLogQueue();
182
+ flushStatusQueue();
183
+ }
184
+
185
+ setInterval(flushAllLogs, 5000);
186
+
187
+ process.on('beforeExit', flushAllLogs);
188
+
189
+ module.exports = {
190
+ logCDP,
191
+ logEvent,
192
+ clearLog,
193
+ logFile,
194
+ logStatus,
195
+ logConnectionEvent,
196
+ flushAllLogs
197
+ };