@mt0926/node-network-devtools 0.1.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 (73) hide show
  1. package/BUILD.md +204 -0
  2. package/LICENSE +21 -0
  3. package/README.md +310 -0
  4. package/README.zh-CN.md +310 -0
  5. package/dist/esm/adapters/nextjs.js +123 -0
  6. package/dist/esm/adapters/nextjs.js.map +1 -0
  7. package/dist/esm/cdp/cdp-bridge.js +312 -0
  8. package/dist/esm/cdp/cdp-bridge.js.map +1 -0
  9. package/dist/esm/cli.js +203 -0
  10. package/dist/esm/cli.js.map +1 -0
  11. package/dist/esm/config.js +136 -0
  12. package/dist/esm/config.js.map +1 -0
  13. package/dist/esm/context/context-manager.js +126 -0
  14. package/dist/esm/context/context-manager.js.map +1 -0
  15. package/dist/esm/gui/browser-launcher.js +165 -0
  16. package/dist/esm/gui/browser-launcher.js.map +1 -0
  17. package/dist/esm/gui/event-bridge.js +192 -0
  18. package/dist/esm/gui/event-bridge.js.map +1 -0
  19. package/dist/esm/gui/port-utils.js +80 -0
  20. package/dist/esm/gui/port-utils.js.map +1 -0
  21. package/dist/esm/gui/server.js +227 -0
  22. package/dist/esm/gui/server.js.map +1 -0
  23. package/dist/esm/gui/websocket-hub.js +326 -0
  24. package/dist/esm/gui/websocket-hub.js.map +1 -0
  25. package/dist/esm/index.js +90 -0
  26. package/dist/esm/index.js.map +1 -0
  27. package/dist/esm/interceptors/http-patcher.js +203 -0
  28. package/dist/esm/interceptors/http-patcher.js.map +1 -0
  29. package/dist/esm/interceptors/undici-patcher.js +324 -0
  30. package/dist/esm/interceptors/undici-patcher.js.map +1 -0
  31. package/dist/esm/register.js +132 -0
  32. package/dist/esm/register.js.map +1 -0
  33. package/dist/esm/store/ring-buffer.js +236 -0
  34. package/dist/esm/store/ring-buffer.js.map +1 -0
  35. package/dist/esm/test-setup.js +7 -0
  36. package/dist/esm/test-setup.js.map +1 -0
  37. package/dist/gui/assets/index.css +1 -0
  38. package/dist/gui/assets/index.js +40 -0
  39. package/dist/gui/index.html +14 -0
  40. package/dist/types/adapters/nextjs.d.ts +80 -0
  41. package/dist/types/adapters/nextjs.d.ts.map +1 -0
  42. package/dist/types/cdp/cdp-bridge.d.ts +86 -0
  43. package/dist/types/cdp/cdp-bridge.d.ts.map +1 -0
  44. package/dist/types/cli.d.ts +8 -0
  45. package/dist/types/cli.d.ts.map +1 -0
  46. package/dist/types/config.d.ts +57 -0
  47. package/dist/types/config.d.ts.map +1 -0
  48. package/dist/types/context/context-manager.d.ts +96 -0
  49. package/dist/types/context/context-manager.d.ts.map +1 -0
  50. package/dist/types/gui/browser-launcher.d.ts +52 -0
  51. package/dist/types/gui/browser-launcher.d.ts.map +1 -0
  52. package/dist/types/gui/event-bridge.d.ts +36 -0
  53. package/dist/types/gui/event-bridge.d.ts.map +1 -0
  54. package/dist/types/gui/port-utils.d.ts +25 -0
  55. package/dist/types/gui/port-utils.d.ts.map +1 -0
  56. package/dist/types/gui/server.d.ts +50 -0
  57. package/dist/types/gui/server.d.ts.map +1 -0
  58. package/dist/types/gui/websocket-hub.d.ts +67 -0
  59. package/dist/types/gui/websocket-hub.d.ts.map +1 -0
  60. package/dist/types/index.d.ts +44 -0
  61. package/dist/types/index.d.ts.map +1 -0
  62. package/dist/types/interceptors/http-patcher.d.ts +32 -0
  63. package/dist/types/interceptors/http-patcher.d.ts.map +1 -0
  64. package/dist/types/interceptors/undici-patcher.d.ts +37 -0
  65. package/dist/types/interceptors/undici-patcher.d.ts.map +1 -0
  66. package/dist/types/register.d.ts +18 -0
  67. package/dist/types/register.d.ts.map +1 -0
  68. package/dist/types/store/ring-buffer.d.ts +148 -0
  69. package/dist/types/store/ring-buffer.d.ts.map +1 -0
  70. package/dist/types/test-setup.d.ts +7 -0
  71. package/dist/types/test-setup.d.ts.map +1 -0
  72. package/package.json +103 -0
  73. package/templates/instrumentation.ts +32 -0
@@ -0,0 +1,312 @@
1
+ /**
2
+ * CDP 桥接模块
3
+ *
4
+ * 将请求数据转换为 CDP Network 事件并发送到 Chrome DevTools
5
+ *
6
+ * 注意:Network 事件广播功能需要:
7
+ * 1. Node.js 20.18.0+ 版本
8
+ * 2. --experimental-network-inspection 标志
9
+ * 3. Chrome DevTools 目前还不支持显示这些事件(功能请求待实现)
10
+ *
11
+ * 当前实现会将事件发送到控制台作为备选方案
12
+ */
13
+ import * as inspector from 'node:inspector';
14
+ import { getConfig } from '../config.js';
15
+ // 检查 Network API 是否可用
16
+ const hasNetworkAPI = typeof inspector.Network?.requestWillBeSent === 'function';
17
+ /**
18
+ * CDP Bridge 实现
19
+ */
20
+ class CDPBridgeImpl {
21
+ session = null;
22
+ connected = false;
23
+ /**
24
+ * 连接到 Inspector
25
+ */
26
+ async connect() {
27
+ if (this.connected)
28
+ return;
29
+ try {
30
+ this.session = new inspector.Session();
31
+ this.session.connect();
32
+ // 启用 Network 域
33
+ await this.post('Network.enable', {});
34
+ this.connected = true;
35
+ }
36
+ catch (error) {
37
+ this.session = null;
38
+ this.connected = false;
39
+ throw error;
40
+ }
41
+ }
42
+ /**
43
+ * 断开连接
44
+ */
45
+ disconnect() {
46
+ if (this.session) {
47
+ try {
48
+ this.session.disconnect();
49
+ }
50
+ catch {
51
+ // 忽略断开连接时的错误
52
+ }
53
+ this.session = null;
54
+ }
55
+ this.connected = false;
56
+ }
57
+ /**
58
+ * 检查是否已连接
59
+ */
60
+ isConnected() {
61
+ return this.connected;
62
+ }
63
+ /**
64
+ * 发送 CDP 命令
65
+ */
66
+ post(method, params) {
67
+ return new Promise((resolve, reject) => {
68
+ if (!this.session) {
69
+ reject(new Error('Session not connected'));
70
+ return;
71
+ }
72
+ this.session.post(method, params, (err, result) => {
73
+ if (err)
74
+ reject(err);
75
+ else
76
+ resolve(result);
77
+ });
78
+ });
79
+ }
80
+ /**
81
+ * 脱敏请求头
82
+ */
83
+ sanitizeHeaders(headers) {
84
+ const config = getConfig();
85
+ const redactHeaders = config.redactHeaders.map(h => h.toLowerCase());
86
+ const sanitized = {};
87
+ for (const [key, value] of Object.entries(headers)) {
88
+ const lowerKey = key.toLowerCase();
89
+ const strValue = Array.isArray(value) ? value.join(', ') : value;
90
+ if (redactHeaders.includes(lowerKey)) {
91
+ if (lowerKey === 'authorization') {
92
+ // 保留 scheme,脱敏 credentials
93
+ const parts = strValue.split(' ');
94
+ sanitized[key] = parts.length > 1 ? `${parts[0]} [REDACTED]` : '[REDACTED]';
95
+ }
96
+ else {
97
+ sanitized[key] = '[REDACTED]';
98
+ }
99
+ }
100
+ else {
101
+ sanitized[key] = strValue;
102
+ }
103
+ }
104
+ return sanitized;
105
+ }
106
+ /**
107
+ * 解析堆栈追踪为 CDP CallFrame 格式
108
+ */
109
+ parseStackTrace(stackTrace) {
110
+ const callFrames = [];
111
+ const lines = stackTrace.split('\n');
112
+ for (const line of lines) {
113
+ // 匹配格式: " at functionName (file:line:column)"
114
+ // 或: " at file:line:column"
115
+ const match = line.match(/^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/);
116
+ if (match) {
117
+ const [, functionName, url, lineNumber, columnNumber] = match;
118
+ // 跳过 node_modules 和内部模块
119
+ if (url.includes('node_modules') || url.startsWith('node:')) {
120
+ continue;
121
+ }
122
+ callFrames.push({
123
+ functionName: functionName || '(anonymous)',
124
+ scriptId: '0', // V8 会分配实际的 scriptId
125
+ url: url.startsWith('file://') ? url : `file://${url}`,
126
+ lineNumber: parseInt(lineNumber, 10) - 1, // CDP 使用 0-based 行号
127
+ columnNumber: parseInt(columnNumber, 10) - 1,
128
+ });
129
+ }
130
+ }
131
+ return { callFrames };
132
+ }
133
+ /**
134
+ * 从 Content-Type 头提取 MIME 类型
135
+ */
136
+ getMimeType(headers) {
137
+ const contentType = headers['content-type'] || headers['Content-Type'];
138
+ if (!contentType)
139
+ return 'text/plain';
140
+ const value = Array.isArray(contentType) ? contentType[0] : contentType;
141
+ // 提取 MIME 类型,去掉 charset 等参数
142
+ return value.split(';')[0].trim();
143
+ }
144
+ /**
145
+ * 发送 Network.requestWillBeSent 事件
146
+ *
147
+ * 注意:需要 Node.js 20.18.0+ 和 --experimental-network-inspection 标志
148
+ */
149
+ emitRequestWillBeSent(request) {
150
+ if (!this.connected)
151
+ return;
152
+ try {
153
+ const cdpRequest = {
154
+ url: request.url,
155
+ method: request.method,
156
+ headers: this.sanitizeHeaders(request.headers),
157
+ };
158
+ // 处理请求体
159
+ if (request.body) {
160
+ cdpRequest.hasPostData = true;
161
+ cdpRequest.postData = Buffer.isBuffer(request.body)
162
+ ? request.body.toString('utf-8')
163
+ : request.body;
164
+ }
165
+ const event = {
166
+ requestId: request.id,
167
+ loaderId: request.traceId || request.id,
168
+ documentURL: request.url,
169
+ request: cdpRequest,
170
+ timestamp: request.timestamp / 1000,
171
+ wallTime: request.timestamp / 1000,
172
+ initiator: {
173
+ type: 'script',
174
+ stack: this.parseStackTrace(request.stackTrace),
175
+ },
176
+ type: 'Fetch',
177
+ };
178
+ // 尝试使用 inspector.Network API 广播事件
179
+ if (hasNetworkAPI) {
180
+ inspector.Network.requestWillBeSent(event);
181
+ }
182
+ }
183
+ catch {
184
+ // 忽略发送事件时的错误
185
+ }
186
+ }
187
+ /**
188
+ * 发送 Network.responseReceived 事件
189
+ */
190
+ emitResponseReceived(requestId, request, response) {
191
+ if (!this.connected)
192
+ return;
193
+ try {
194
+ const cdpResponse = {
195
+ url: request.url,
196
+ status: response.statusCode,
197
+ statusText: response.statusMessage,
198
+ headers: this.sanitizeHeaders(response.headers),
199
+ mimeType: this.getMimeType(response.headers),
200
+ connectionReused: false,
201
+ connectionId: 0,
202
+ encodedDataLength: 0,
203
+ securityState: request.url.startsWith('https') ? 'secure' : 'insecure',
204
+ };
205
+ const event = {
206
+ requestId,
207
+ loaderId: request.traceId || requestId,
208
+ timestamp: Date.now() / 1000,
209
+ type: 'Fetch',
210
+ response: cdpResponse,
211
+ };
212
+ if (hasNetworkAPI) {
213
+ inspector.Network.responseReceived(event);
214
+ }
215
+ }
216
+ catch {
217
+ // 忽略发送事件时的错误
218
+ }
219
+ }
220
+ /**
221
+ * 发送 Network.loadingFinished 事件
222
+ */
223
+ emitLoadingFinished(requestId, _timing) {
224
+ if (!this.connected)
225
+ return;
226
+ try {
227
+ const event = {
228
+ requestId,
229
+ timestamp: Date.now() / 1000,
230
+ encodedDataLength: 0,
231
+ };
232
+ if (hasNetworkAPI) {
233
+ inspector.Network.loadingFinished(event);
234
+ }
235
+ }
236
+ catch {
237
+ // 忽略发送事件时的错误
238
+ }
239
+ }
240
+ /**
241
+ * 发送 Network.loadingFailed 事件
242
+ */
243
+ emitLoadingFailed(requestId, error) {
244
+ if (!this.connected)
245
+ return;
246
+ try {
247
+ const event = {
248
+ requestId,
249
+ timestamp: Date.now() / 1000,
250
+ type: 'Fetch',
251
+ errorText: error.message,
252
+ canceled: false,
253
+ blockedReason: undefined,
254
+ };
255
+ if (hasNetworkAPI) {
256
+ inspector.Network.loadingFailed(event);
257
+ }
258
+ }
259
+ catch {
260
+ // 忽略发送事件时的错误
261
+ }
262
+ }
263
+ }
264
+ // 全局单例
265
+ let globalBridge = null;
266
+ /**
267
+ * 获取全局 CDP Bridge 实例
268
+ */
269
+ export function getCDPBridge() {
270
+ if (!globalBridge) {
271
+ globalBridge = new CDPBridgeImpl();
272
+ }
273
+ return globalBridge;
274
+ }
275
+ /**
276
+ * 重置全局 CDP Bridge(用于测试)
277
+ */
278
+ export function resetCDPBridge() {
279
+ if (globalBridge) {
280
+ globalBridge.disconnect();
281
+ }
282
+ globalBridge = null;
283
+ }
284
+ /**
285
+ * 创建新的 CDP Bridge 实例(用于测试)
286
+ */
287
+ export function createCDPBridge() {
288
+ return new CDPBridgeImpl();
289
+ }
290
+ /**
291
+ * 检查 Inspector 是否已启用
292
+ */
293
+ export function isInspectorEnabled() {
294
+ try {
295
+ return inspector.url?.() !== undefined;
296
+ }
297
+ catch {
298
+ return false;
299
+ }
300
+ }
301
+ /**
302
+ * 获取 Inspector URL
303
+ */
304
+ export function getInspectorUrl() {
305
+ try {
306
+ return inspector.url?.();
307
+ }
308
+ catch {
309
+ return undefined;
310
+ }
311
+ }
312
+ //# sourceMappingURL=cdp-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-bridge.js","sourceRoot":"","sources":["../../../src/cdp/cdp-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI 入口
4
+ *
5
+ * 使用方式:npx node-network-devtools your-script.js [args...]
6
+ */
7
+ import { spawn } from 'node:child_process';
8
+ import { resolve, dirname } from 'node:path';
9
+ import { fileURLToPath } from 'node:url';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ /**
13
+ * 输出帮助信息
14
+ */
15
+ function printHelp() {
16
+ console.log(`
17
+ \x1b[36mnode-network-devtools\x1b[0m - Node.js 网络请求监听工具
18
+
19
+ \x1b[33m用法:\x1b[0m
20
+ npx node-network-devtools [选项] <脚本> [脚本参数...]
21
+
22
+ \x1b[33m选项:\x1b[0m
23
+ --help, -h 显示帮助信息
24
+ --version, -v 显示版本号
25
+ --inspect-port=PORT 指定 Inspector 端口(默认: 9229)
26
+ --inspect-brk 在脚本开始时暂停执行
27
+ --gui 启用 Web GUI(默认: false)
28
+ --gui-port=PORT 指定 GUI 端口(默认: auto)
29
+ --ws-port=PORT 指定 WebSocket 端口(默认: auto)
30
+ --no-open 不自动打开浏览器
31
+
32
+ \x1b[33m示例:\x1b[0m
33
+ npx node-network-devtools server.js
34
+ npx node-network-devtools --gui server.js
35
+ npx node-network-devtools --gui --gui-port=8080 app.js
36
+ npx node-network-devtools --inspect-port=9230 app.js
37
+ npx node-network-devtools --inspect-brk test.js
38
+
39
+ \x1b[33m环境变量:\x1b[0m
40
+ NND_MAX_REQUESTS 最大存储请求数(默认: 1000)
41
+ NND_MAX_BODY_SIZE 最大 body 大小(默认: 1048576)
42
+ NND_INTERCEPT_HTTP 是否拦截 http/https(默认: true)
43
+ NND_INTERCEPT_UNDICI 是否拦截 undici/fetch(默认: true)
44
+ NND_REDACT_HEADERS 要脱敏的头(逗号分隔,默认: authorization,cookie)
45
+ NND_GUI_ENABLED 是否启用 GUI(默认: false)
46
+ NND_GUI_PORT GUI 端口(默认: auto)
47
+ NND_WS_PORT WebSocket 端口(默认: auto)
48
+ NND_AUTO_OPEN 是否自动打开浏览器(默认: true)
49
+
50
+ \x1b[33m说明:\x1b[0m
51
+ 此工具会自动添加 --inspect 和 --experimental-network-inspection 标志。
52
+ 启动后,打开 Chrome DevTools (chrome://inspect) 即可查看网络请求。
53
+ 使用 --gui 选项可以启用内置的 Web GUI 界面。
54
+
55
+ \x1b[33m注意:\x1b[0m
56
+ Network 面板功能需要 Node.js 20.18.0+ 版本。
57
+ Chrome DevTools Network 面板目前可能还不支持显示这些事件。
58
+ 请求数据仍会被捕获并可通过编程 API 或控制台日志访问。
59
+ `);
60
+ }
61
+ /**
62
+ * 输出版本号
63
+ */
64
+ function printVersion() {
65
+ // 从 package.json 读取版本号
66
+ console.log('0.1.0');
67
+ }
68
+ function parseArgs(args) {
69
+ const result = {
70
+ help: false,
71
+ version: false,
72
+ inspectPort: 9229,
73
+ inspectBrk: false,
74
+ gui: false,
75
+ guiPort: 'auto',
76
+ wsPort: 'auto',
77
+ autoOpen: true,
78
+ script: null,
79
+ scriptArgs: [],
80
+ };
81
+ let i = 0;
82
+ while (i < args.length) {
83
+ const arg = args[i];
84
+ if (arg === '--help' || arg === '-h') {
85
+ result.help = true;
86
+ }
87
+ else if (arg === '--version' || arg === '-v') {
88
+ result.version = true;
89
+ }
90
+ else if (arg === '--inspect-brk') {
91
+ result.inspectBrk = true;
92
+ }
93
+ else if (arg.startsWith('--inspect-port=')) {
94
+ result.inspectPort = parseInt(arg.split('=')[1], 10) || 9229;
95
+ }
96
+ else if (arg === '--gui') {
97
+ result.gui = true;
98
+ }
99
+ else if (arg.startsWith('--gui-port=')) {
100
+ const port = parseInt(arg.split('=')[1], 10);
101
+ result.guiPort = isNaN(port) ? 'auto' : port;
102
+ }
103
+ else if (arg.startsWith('--ws-port=')) {
104
+ const port = parseInt(arg.split('=')[1], 10);
105
+ result.wsPort = isNaN(port) ? 'auto' : port;
106
+ }
107
+ else if (arg === '--no-open') {
108
+ result.autoOpen = false;
109
+ }
110
+ else if (!arg.startsWith('-')) {
111
+ // 第一个非选项参数是脚本路径
112
+ result.script = arg;
113
+ result.scriptArgs = args.slice(i + 1);
114
+ break;
115
+ }
116
+ i++;
117
+ }
118
+ return result;
119
+ }
120
+ /**
121
+ * 主函数
122
+ */
123
+ function main() {
124
+ const args = process.argv.slice(2);
125
+ const parsed = parseArgs(args);
126
+ if (parsed.help) {
127
+ printHelp();
128
+ process.exit(0);
129
+ }
130
+ if (parsed.version) {
131
+ printVersion();
132
+ process.exit(0);
133
+ }
134
+ if (!parsed.script) {
135
+ console.error('\x1b[31m错误:\x1b[0m 请指定要运行的脚本');
136
+ console.error('使用 --help 查看帮助信息');
137
+ process.exit(1);
138
+ }
139
+ // 解析脚本路径
140
+ const scriptPath = resolve(process.cwd(), parsed.script);
141
+ // 构建 Node.js 参数
142
+ const nodeArgs = [];
143
+ // 添加 inspect 标志
144
+ if (parsed.inspectBrk) {
145
+ nodeArgs.push(`--inspect-brk=${parsed.inspectPort}`);
146
+ }
147
+ else {
148
+ nodeArgs.push(`--inspect=${parsed.inspectPort}`);
149
+ }
150
+ // 添加实验性网络检查标志(Node.js 20.18.0+)
151
+ nodeArgs.push('--experimental-network-inspection');
152
+ // 添加 register 入口
153
+ // 计算 register.js 的路径(相对于 CLI 脚本)
154
+ const registerPath = resolve(__dirname, 'register.js');
155
+ nodeArgs.push('--import', registerPath);
156
+ // 添加用户脚本和参数
157
+ nodeArgs.push(scriptPath, ...parsed.scriptArgs);
158
+ // 设置 GUI 相关环境变量
159
+ const env = { ...process.env };
160
+ if (parsed.gui) {
161
+ env.NND_GUI_ENABLED = 'true';
162
+ if (parsed.guiPort !== 'auto') {
163
+ env.NND_GUI_PORT = String(parsed.guiPort);
164
+ }
165
+ if (parsed.wsPort !== 'auto') {
166
+ env.NND_WS_PORT = String(parsed.wsPort);
167
+ }
168
+ env.NND_AUTO_OPEN = parsed.autoOpen ? 'true' : 'false';
169
+ }
170
+ console.log(`\x1b[36m[node-network-devtools]\x1b[0m 启动脚本: ${parsed.script}`);
171
+ console.log(`\x1b[36m[node-network-devtools]\x1b[0m Inspector 端口: ${parsed.inspectPort}`);
172
+ console.log(`\x1b[36m[node-network-devtools]\x1b[0m 实验性网络检查已启用`);
173
+ if (parsed.gui) {
174
+ console.log(`\x1b[36m[node-network-devtools]\x1b[0m Web GUI 已启用`);
175
+ }
176
+ else {
177
+ console.log(`\x1b[36m[node-network-devtools]\x1b[0m 打开 chrome://inspect 查看网络请求`);
178
+ }
179
+ console.log('');
180
+ // 启动子进程
181
+ const child = spawn('node', nodeArgs, {
182
+ stdio: 'inherit',
183
+ env,
184
+ });
185
+ // 转发退出码
186
+ child.on('exit', (code) => {
187
+ process.exit(code ?? 0);
188
+ });
189
+ // 处理错误
190
+ child.on('error', (error) => {
191
+ console.error(`\x1b[31m错误:\x1b[0m 无法启动脚本: ${error.message}`);
192
+ process.exit(1);
193
+ });
194
+ // 处理信号
195
+ process.on('SIGINT', () => {
196
+ child.kill('SIGINT');
197
+ });
198
+ process.on('SIGTERM', () => {
199
+ child.kill('SIGTERM');
200
+ });
201
+ }
202
+ main();
203
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * 配置管理模块
3
+ *
4
+ * 支持通过环境变量和编程方式配置工具行为
5
+ */
6
+ /**
7
+ * 默认配置
8
+ */
9
+ const defaultConfig = {
10
+ maxRequests: 1000,
11
+ maxBodySize: 1024 * 1024, // 1MB
12
+ interceptHttp: true,
13
+ interceptUndici: true,
14
+ ignoreUrls: [],
15
+ redactHeaders: ['authorization', 'cookie'],
16
+ disableBodyCapture: false,
17
+ autoConnect: true,
18
+ inspectorPort: undefined,
19
+ // GUI 配置默认值
20
+ guiEnabled: true,
21
+ guiPort: 'auto',
22
+ wsPort: 'auto',
23
+ guiHost: '127.0.0.1',
24
+ autoOpen: true,
25
+ usePuppeteer: false,
26
+ };
27
+ /**
28
+ * 当前配置(合并后的结果)
29
+ */
30
+ let currentConfig = { ...defaultConfig };
31
+ /**
32
+ * 从环境变量解析布尔值
33
+ */
34
+ function parseEnvBoolean(value, defaultValue) {
35
+ if (value === undefined)
36
+ return defaultValue;
37
+ const lower = value.toLowerCase();
38
+ if (lower === 'true' || lower === '1' || lower === 'yes')
39
+ return true;
40
+ if (lower === 'false' || lower === '0' || lower === 'no')
41
+ return false;
42
+ return defaultValue;
43
+ }
44
+ /**
45
+ * 从环境变量解析数字
46
+ */
47
+ function parseEnvNumber(value, defaultValue) {
48
+ if (value === undefined)
49
+ return defaultValue;
50
+ const num = parseInt(value, 10);
51
+ return isNaN(num) ? defaultValue : num;
52
+ }
53
+ /**
54
+ * 从环境变量解析字符串数组(逗号分隔)
55
+ */
56
+ function parseEnvStringArray(value, defaultValue) {
57
+ if (value === undefined || value.trim() === '')
58
+ return defaultValue;
59
+ return value.split(',').map(s => s.trim().toLowerCase()).filter(s => s.length > 0);
60
+ }
61
+ /**
62
+ * 从环境变量解析端口(支持 'auto' 或数字)
63
+ */
64
+ function parseEnvPort(value, defaultValue) {
65
+ if (value === undefined)
66
+ return defaultValue;
67
+ if (value.toLowerCase() === 'auto')
68
+ return 'auto';
69
+ const num = parseInt(value, 10);
70
+ return isNaN(num) ? defaultValue : num;
71
+ }
72
+ /**
73
+ * 从环境变量加载配置
74
+ */
75
+ function loadFromEnv() {
76
+ const env = process.env;
77
+ return {
78
+ maxRequests: parseEnvNumber(env.NND_MAX_REQUESTS, defaultConfig.maxRequests),
79
+ maxBodySize: parseEnvNumber(env.NND_MAX_BODY_SIZE, defaultConfig.maxBodySize),
80
+ interceptHttp: parseEnvBoolean(env.NND_INTERCEPT_HTTP, defaultConfig.interceptHttp),
81
+ interceptUndici: parseEnvBoolean(env.NND_INTERCEPT_UNDICI, defaultConfig.interceptUndici),
82
+ redactHeaders: parseEnvStringArray(env.NND_REDACT_HEADERS, defaultConfig.redactHeaders),
83
+ disableBodyCapture: parseEnvBoolean(env.NND_DISABLE_BODY_CAPTURE, defaultConfig.disableBodyCapture),
84
+ autoConnect: parseEnvBoolean(env.NND_AUTO_CONNECT, defaultConfig.autoConnect),
85
+ inspectorPort: env.NND_INSPECTOR_PORT ? parseEnvNumber(env.NND_INSPECTOR_PORT, 0) : undefined,
86
+ // GUI 配置
87
+ guiEnabled: parseEnvBoolean(env.NND_GUI_ENABLED, defaultConfig.guiEnabled),
88
+ guiPort: parseEnvPort(env.NND_GUI_PORT, defaultConfig.guiPort),
89
+ wsPort: parseEnvPort(env.NND_WS_PORT, defaultConfig.wsPort),
90
+ guiHost: env.NND_GUI_HOST || defaultConfig.guiHost,
91
+ autoOpen: parseEnvBoolean(env.NND_AUTO_OPEN, defaultConfig.autoOpen),
92
+ usePuppeteer: parseEnvBoolean(env.NND_USE_PUPPETEER, defaultConfig.usePuppeteer),
93
+ };
94
+ }
95
+ /**
96
+ * 初始化配置(合并默认值和环境变量)
97
+ */
98
+ function initConfig() {
99
+ const envConfig = loadFromEnv();
100
+ return {
101
+ ...defaultConfig,
102
+ ...envConfig,
103
+ // ignoreUrls 需要特殊处理,环境变量不支持正则
104
+ ignoreUrls: defaultConfig.ignoreUrls,
105
+ };
106
+ }
107
+ // 初始化时加载配置
108
+ currentConfig = initConfig();
109
+ /**
110
+ * 获取当前配置
111
+ */
112
+ export function getConfig() {
113
+ return currentConfig;
114
+ }
115
+ /**
116
+ * 设置配置(合并到当前配置)
117
+ */
118
+ export function setConfig(config) {
119
+ currentConfig = {
120
+ ...currentConfig,
121
+ ...config,
122
+ };
123
+ }
124
+ /**
125
+ * 重置配置为默认值
126
+ */
127
+ export function resetConfig() {
128
+ currentConfig = initConfig();
129
+ }
130
+ /**
131
+ * 获取默认配置(用于测试)
132
+ */
133
+ export function getDefaultConfig() {
134
+ return defaultConfig;
135
+ }
136
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}