network-terminal 1.0.9 → 1.0.10

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.
@@ -1,70 +1,510 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/vite-plugin.ts
2
- var VIRTUAL_MODULE_ID = "virtual:network-terminal";
3
- var RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
4
- function networkTerminal(options = {}) {
5
- const {
6
- position = "bottom",
7
- maxLogs = 100,
8
- height = "450px",
9
- zIndex = 9999
10
- } = options;
11
- return {
12
- name: "vite-plugin-network-terminal",
13
- apply: "serve",
14
- // Only apply during development
15
- resolveId(id) {
16
- if (id === VIRTUAL_MODULE_ID) {
17
- return RESOLVED_VIRTUAL_MODULE_ID;
18
- }
19
- },
20
- load(id) {
21
- if (id === RESOLVED_VIRTUAL_MODULE_ID) {
22
- return `
23
- import React from 'react';
24
- import ReactDOM from 'react-dom/client';
25
- import { NetworkTerminal } from 'network-terminal';
26
-
27
- function initNetworkTerminal() {
28
- const containerId = '__network-terminal-root__';
29
- let container = document.getElementById(containerId);
30
-
31
- if (!container) {
32
- container = document.createElement('div');
33
- container.id = containerId;
34
- document.body.appendChild(container);
35
- }
9
+ import { createServer } from "http";
10
+ var networkLogs = [];
11
+ var sseClients = /* @__PURE__ */ new Set();
12
+ function broadcastLog(log) {
13
+ const data = JSON.stringify(log);
14
+ sseClients.forEach((client) => {
15
+ client.write(`data: ${data}
36
16
 
37
- const root = ReactDOM.createRoot(container);
38
- root.render(
39
- React.createElement(NetworkTerminal, {
40
- position: '${position}',
41
- maxLogs: ${maxLogs},
42
- height: '${height}',
43
- zIndex: ${zIndex},
44
- defaultVisible: false,
45
- })
46
- );
17
+ `);
18
+ });
47
19
  }
20
+ function getDashboardHTML(_port) {
21
+ return `
22
+ <!DOCTYPE html>
23
+ <html lang="en">
24
+ <head>
25
+ <meta charset="UTF-8">
26
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
27
+ <title>Network Terminal</title>
28
+ <style>
29
+ * { margin: 0; padding: 0; box-sizing: border-box; }
30
+ body {
31
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
32
+ background: #0a0e17;
33
+ color: #e2e8f0;
34
+ height: 100vh;
35
+ overflow: hidden;
36
+ }
37
+ .header {
38
+ background: #0f172a;
39
+ padding: 12px 24px;
40
+ border-bottom: 2px solid #4ade80;
41
+ display: flex;
42
+ justify-content: space-between;
43
+ align-items: center;
44
+ }
45
+ .title { color: #4ade80; font-size: 18px; font-weight: bold; }
46
+ .subtitle { color: #64748b; font-size: 12px; margin-top: 4px; }
47
+ .controls { display: flex; gap: 12px; align-items: center; }
48
+ .btn {
49
+ background: #1e293b;
50
+ border: 1px solid #334155;
51
+ color: #94a3b8;
52
+ padding: 8px 16px;
53
+ border-radius: 6px;
54
+ cursor: pointer;
55
+ font-size: 12px;
56
+ font-family: inherit;
57
+ }
58
+ .btn:hover { background: #334155; color: #e2e8f0; }
59
+ .container { display: flex; height: calc(100vh - 80px); }
60
+ .panel {
61
+ flex: 1;
62
+ display: flex;
63
+ flex-direction: column;
64
+ border-right: 1px solid #1e293b;
65
+ }
66
+ .panel:last-child { border-right: none; }
67
+ .panel-header {
68
+ background: #0f172a;
69
+ padding: 12px 16px;
70
+ border-bottom: 1px solid #1e293b;
71
+ display: flex;
72
+ justify-content: space-between;
73
+ align-items: center;
74
+ }
75
+ .panel-title { font-weight: bold; font-size: 14px; }
76
+ .panel-title.request { color: #3b82f6; }
77
+ .panel-title.response { color: #22c55e; }
78
+ .panel-count {
79
+ background: #1e293b;
80
+ padding: 2px 8px;
81
+ border-radius: 10px;
82
+ font-size: 11px;
83
+ color: #64748b;
84
+ }
85
+ .logs { flex: 1; overflow-y: auto; padding: 8px; }
86
+ .log-entry {
87
+ background: #0f172a;
88
+ border: 1px solid #1e293b;
89
+ border-radius: 8px;
90
+ margin-bottom: 8px;
91
+ overflow: hidden;
92
+ cursor: pointer;
93
+ transition: border-color 0.2s;
94
+ }
95
+ .log-entry:hover { border-color: #334155; }
96
+ .log-entry.selected { border-color: #4ade80; }
97
+ .log-header {
98
+ display: flex;
99
+ align-items: center;
100
+ gap: 12px;
101
+ padding: 10px 12px;
102
+ background: #1e293b;
103
+ }
104
+ .method {
105
+ font-weight: bold;
106
+ font-size: 11px;
107
+ padding: 3px 8px;
108
+ border-radius: 4px;
109
+ }
110
+ .method.GET { background: #166534; color: #4ade80; }
111
+ .method.POST { background: #1e40af; color: #60a5fa; }
112
+ .method.PUT { background: #a16207; color: #fcd34d; }
113
+ .method.DELETE { background: #991b1b; color: #fca5a5; }
114
+ .method.PATCH { background: #7c3aed; color: #c4b5fd; }
115
+ .status { font-size: 11px; padding: 3px 8px; border-radius: 4px; }
116
+ .status.success { background: #166534; color: #4ade80; }
117
+ .status.error { background: #991b1b; color: #fca5a5; }
118
+ .status.pending { background: #374151; color: #9ca3af; }
119
+ .url {
120
+ flex: 1;
121
+ font-size: 12px;
122
+ color: #94a3b8;
123
+ overflow: hidden;
124
+ text-overflow: ellipsis;
125
+ white-space: nowrap;
126
+ }
127
+ .duration { font-size: 11px; color: #64748b; }
128
+ .timestamp { font-size: 10px; color: #475569; }
129
+ .log-body { padding: 12px; font-size: 11px; max-height: 300px; overflow: auto; }
130
+ .log-body pre {
131
+ margin: 0;
132
+ white-space: pre-wrap;
133
+ word-break: break-all;
134
+ color: #cbd5e1;
135
+ line-height: 1.5;
136
+ }
137
+ .log-body.empty { color: #475569; font-style: italic; }
138
+ .empty-state {
139
+ display: flex;
140
+ flex-direction: column;
141
+ align-items: center;
142
+ justify-content: center;
143
+ height: 100%;
144
+ color: #475569;
145
+ text-align: center;
146
+ padding: 20px;
147
+ }
148
+ .empty-state svg { width: 48px; height: 48px; margin-bottom: 16px; opacity: 0.5; }
149
+ .status-dot {
150
+ width: 8px;
151
+ height: 8px;
152
+ border-radius: 50%;
153
+ background: #22c55e;
154
+ animation: pulse 2s infinite;
155
+ }
156
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
157
+ .status-dot.disconnected { background: #ef4444; animation: none; }
158
+ </style>
159
+ </head>
160
+ <body>
161
+ <div class="header">
162
+ <div>
163
+ <div class="title">>_ Network Terminal</div>
164
+ <div class="subtitle">Vite Plugin - Monitoring fetch/XHR requests</div>
165
+ </div>
166
+ <div class="controls">
167
+ <div class="status-dot" id="statusDot"></div>
168
+ <button class="btn" onclick="clearLogs()">Clear All</button>
169
+ </div>
170
+ </div>
48
171
 
49
- if (document.readyState === 'loading') {
50
- document.addEventListener('DOMContentLoaded', initNetworkTerminal);
51
- } else {
52
- initNetworkTerminal();
53
- }
172
+ <div class="container">
173
+ <div class="panel">
174
+ <div class="panel-header">
175
+ <span class="panel-title request">\u2B06 REQUESTS</span>
176
+ <span class="panel-count" id="requestCount">0</span>
177
+ </div>
178
+ <div class="logs" id="requestLogs">
179
+ <div class="empty-state">
180
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
181
+ <path d="M12 19V5M5 12l7-7 7 7"/>
182
+ </svg>
183
+ <div>Waiting for requests...</div>
184
+ <div style="margin-top: 8px; font-size: 11px;">Make fetch/XHR requests in your app</div>
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <div class="panel">
190
+ <div class="panel-header">
191
+ <span class="panel-title response">\u2B07 RESPONSES</span>
192
+ <span class="panel-count" id="responseCount">0</span>
193
+ </div>
194
+ <div class="logs" id="responseLogs">
195
+ <div class="empty-state">
196
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
197
+ <path d="M12 5v14M5 12l7 7 7-7"/>
198
+ </svg>
199
+ <div>Waiting for responses...</div>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+
205
+ <script>
206
+ const logs = new Map();
207
+ let selectedId = null;
208
+
209
+ function formatJson(data) {
210
+ if (!data) return null;
211
+ if (typeof data === 'string') {
212
+ try { data = JSON.parse(data); }
213
+ catch (e) { return escapeHtml(data.substring(0, 2000)); }
214
+ }
215
+ return escapeHtml(JSON.stringify(data, null, 2));
216
+ }
217
+
218
+ function escapeHtml(str) {
219
+ if (typeof str !== 'string') str = String(str);
220
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
221
+ }
222
+
223
+ function formatTime(timestamp) {
224
+ const date = new Date(timestamp);
225
+ return date.toLocaleTimeString('en-US', { hour12: false }) + '.' +
226
+ String(date.getMilliseconds()).padStart(3, '0');
227
+ }
228
+
229
+ function getLogsArray() {
230
+ return Array.from(logs.values()).sort((a, b) =>
231
+ new Date(b.timestamp) - new Date(a.timestamp)
232
+ );
233
+ }
234
+
235
+ function renderLogs() {
236
+ const logsArray = getLogsArray();
237
+ const requestContainer = document.getElementById('requestLogs');
238
+ const responseContainer = document.getElementById('responseLogs');
239
+
240
+ document.getElementById('requestCount').textContent = logsArray.length;
241
+ document.getElementById('responseCount').textContent = logsArray.filter(l => l.status).length;
242
+
243
+ if (logsArray.length === 0) {
244
+ requestContainer.innerHTML = '<div class="empty-state"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 19V5M5 12l7-7 7 7"/></svg><div>Waiting for requests...</div></div>';
245
+ responseContainer.innerHTML = '<div class="empty-state"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12l7 7 7-7"/></svg><div>Waiting for responses...</div></div>';
246
+ return;
247
+ }
248
+
249
+ requestContainer.innerHTML = logsArray.map(log => {
250
+ const isSelected = selectedId === log.id;
251
+ const bodyContent = formatJson(log.requestBody);
252
+ return '<div class="log-entry '+(isSelected ? 'selected' : '')+'" onclick="selectLog(\\''+log.id+'\\')"><div class="log-header"><span class="method '+log.method+'">'+log.method+'</span><span class="url" title="'+escapeHtml(log.url)+'">'+log.url+'</span><span class="timestamp">'+formatTime(log.timestamp)+'</span></div>'+(isSelected ? '<div class="log-body '+(bodyContent ? '' : 'empty')+'">'+(bodyContent ? '<pre>'+bodyContent+'</pre>' : 'No request body')+'</div>' : '')+'</div>';
253
+ }).join('');
254
+
255
+ responseContainer.innerHTML = logsArray.map(log => {
256
+ const isSelected = selectedId === log.id;
257
+ const statusClass = !log.status ? 'pending' : log.status < 400 ? 'success' : 'error';
258
+ const bodyContent = formatJson(log.responseBody);
259
+ return '<div class="log-entry '+(isSelected ? 'selected' : '')+'" onclick="selectLog(\\''+log.id+'\\')"><div class="log-header"><span class="status '+statusClass+'">'+(log.status || '...')+'</span><span class="url" title="'+escapeHtml(log.url)+'">'+log.url+'</span><span class="duration">'+(log.duration ? log.duration + 'ms' : '')+'</span></div>'+(isSelected ? '<div class="log-body '+(bodyContent ? '' : 'empty')+'">'+(bodyContent ? '<pre>'+bodyContent+'</pre>' : (log.status ? 'No response body' : 'Pending...'))+'</div>' : '')+'</div>';
260
+ }).join('');
261
+ }
262
+
263
+ function selectLog(id) {
264
+ selectedId = selectedId === id ? null : id;
265
+ renderLogs();
266
+ }
267
+
268
+ function clearLogs() {
269
+ logs.clear();
270
+ selectedId = null;
271
+ renderLogs();
272
+ fetch('/clear', { method: 'POST' });
273
+ }
274
+
275
+ function addLog(log) {
276
+ logs.set(log.id, log);
277
+ if (logs.size > 100) {
278
+ const oldest = getLogsArray().pop();
279
+ if (oldest) logs.delete(oldest.id);
280
+ }
281
+ renderLogs();
282
+ }
283
+
284
+ function connect() {
285
+ const evtSource = new EventSource('/events');
286
+ evtSource.onopen = () => document.getElementById('statusDot').classList.remove('disconnected');
287
+ evtSource.onmessage = (event) => addLog(JSON.parse(event.data));
288
+ evtSource.onerror = () => {
289
+ document.getElementById('statusDot').classList.add('disconnected');
290
+ evtSource.close();
291
+ setTimeout(connect, 2000);
292
+ };
293
+ }
294
+
295
+ connect();
296
+ renderLogs();
297
+ </script>
298
+ </body>
299
+ </html>
54
300
  `;
301
+ }
302
+ function getMonitorScript(port) {
303
+ return `
304
+ (function() {
305
+ if (window.__networkTerminalActive) return;
306
+ window.__networkTerminalActive = true;
307
+
308
+ var DASHBOARD_URL = 'http://localhost:${port}';
309
+
310
+ function sendLog(log) {
311
+ var xhr = new XMLHttpRequest();
312
+ xhr.open('POST', DASHBOARD_URL + '/log', true);
313
+ xhr.setRequestHeader('Content-Type', 'application/json');
314
+ xhr.send(JSON.stringify(log));
315
+ }
316
+
317
+ function tryParse(data) {
318
+ if (!data) return null;
319
+ if (typeof data === 'object') return data;
320
+ try { return JSON.parse(data); } catch (e) { return data; }
321
+ }
322
+
323
+ var originalFetch = window.fetch;
324
+ window.fetch = function() {
325
+ var args = arguments;
326
+ var startTime = Date.now();
327
+ var input = args[0];
328
+ var options = args[1] || {};
329
+ var url = typeof input === 'string' ? input : (input.url || input.toString());
330
+ var method = (options.method || 'GET').toUpperCase();
331
+
332
+ if (url.includes('localhost:${port}')) {
333
+ return originalFetch.apply(this, args);
334
+ }
335
+
336
+ var log = {
337
+ id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
338
+ method: method,
339
+ url: url,
340
+ timestamp: new Date().toISOString(),
341
+ requestBody: options.body ? tryParse(options.body) : null,
342
+ status: null,
343
+ responseBody: null,
344
+ duration: null,
345
+ };
346
+
347
+ sendLog(log);
348
+
349
+ return originalFetch.apply(this, args).then(function(response) {
350
+ log.status = response.status;
351
+ log.duration = Date.now() - startTime;
352
+ var cloned = response.clone();
353
+ cloned.text().then(function(text) {
354
+ log.responseBody = tryParse(text);
355
+ sendLog(log);
356
+ }).catch(function() { sendLog(log); });
357
+ return response;
358
+ }).catch(function(error) {
359
+ log.status = 0;
360
+ log.duration = Date.now() - startTime;
361
+ log.error = error.message;
362
+ sendLog(log);
363
+ throw error;
364
+ });
365
+ };
366
+
367
+ var OriginalXHR = window.XMLHttpRequest;
368
+ window.XMLHttpRequest = function() {
369
+ var xhr = new OriginalXHR();
370
+ var method, url, requestBody, startTime;
371
+
372
+ var originalOpen = xhr.open;
373
+ xhr.open = function(m, u) {
374
+ method = m;
375
+ url = u;
376
+ return originalOpen.apply(this, arguments);
377
+ };
378
+
379
+ var originalSend = xhr.send;
380
+ xhr.send = function(body) {
381
+ if (url && url.includes('localhost:${port}')) {
382
+ return originalSend.apply(this, arguments);
55
383
  }
384
+
385
+ startTime = Date.now();
386
+ requestBody = body;
387
+
388
+ var log = {
389
+ id: Date.now().toString() + Math.random().toString(36).substr(2, 9),
390
+ method: (method || 'GET').toUpperCase(),
391
+ url: url,
392
+ timestamp: new Date().toISOString(),
393
+ requestBody: tryParse(requestBody),
394
+ status: null,
395
+ responseBody: null,
396
+ duration: null,
397
+ };
398
+
399
+ sendLog(log);
400
+
401
+ xhr.addEventListener('loadend', function() {
402
+ log.status = xhr.status;
403
+ log.duration = Date.now() - startTime;
404
+ log.responseBody = tryParse(xhr.responseText);
405
+ sendLog(log);
406
+ });
407
+
408
+ return originalSend.apply(this, arguments);
409
+ };
410
+
411
+ return xhr;
412
+ };
413
+
414
+ console.log('[Network Terminal] \u2713 Active - Dashboard: http://localhost:${port}');
415
+ })();
416
+ `;
417
+ }
418
+ function networkTerminal(options = {}) {
419
+ const { port = 4001, open = true } = options;
420
+ let dashboardServer = null;
421
+ return {
422
+ name: "vite-plugin-network-terminal",
423
+ apply: "serve",
424
+ configureServer(_server) {
425
+ dashboardServer = createServer((req, res) => {
426
+ res.setHeader("Access-Control-Allow-Origin", "*");
427
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
428
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
429
+ if (req.method === "OPTIONS") {
430
+ res.writeHead(204);
431
+ res.end();
432
+ return;
433
+ }
434
+ if (req.url === "/events") {
435
+ res.writeHead(200, {
436
+ "Content-Type": "text/event-stream",
437
+ "Cache-Control": "no-cache",
438
+ "Connection": "keep-alive"
439
+ });
440
+ sseClients.add(res);
441
+ networkLogs.forEach((log) => {
442
+ res.write(`data: ${JSON.stringify(log)}
443
+
444
+ `);
445
+ });
446
+ req.on("close", () => sseClients.delete(res));
447
+ return;
448
+ }
449
+ if (req.url === "/log" && req.method === "POST") {
450
+ let body = "";
451
+ req.on("data", (chunk) => body += chunk);
452
+ req.on("end", () => {
453
+ try {
454
+ const log = JSON.parse(body);
455
+ const existingIndex = networkLogs.findIndex((l) => l.id === log.id);
456
+ if (existingIndex >= 0) {
457
+ networkLogs[existingIndex] = log;
458
+ } else {
459
+ networkLogs.unshift(log);
460
+ if (networkLogs.length > 100) networkLogs.pop();
461
+ }
462
+ broadcastLog(log);
463
+ } catch (e) {
464
+ }
465
+ res.writeHead(200);
466
+ res.end("OK");
467
+ });
468
+ return;
469
+ }
470
+ if (req.url === "/clear" && req.method === "POST") {
471
+ networkLogs.length = 0;
472
+ res.writeHead(200);
473
+ res.end("OK");
474
+ return;
475
+ }
476
+ res.writeHead(200, { "Content-Type": "text/html" });
477
+ res.end(getDashboardHTML(port));
478
+ });
479
+ dashboardServer.listen(port, () => {
480
+ console.log(`
481
+ \x1B[32m>_ Network Terminal\x1B[0m`);
482
+ console.log(` Dashboard: \x1B[36mhttp://localhost:${port}\x1B[0m
483
+ `);
484
+ if (open) {
485
+ const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
486
+ __require("child_process").exec(`${openCmd} http://localhost:${port}`);
487
+ }
488
+ });
489
+ dashboardServer.on("error", (err) => {
490
+ if (err.code === "EADDRINUSE") {
491
+ console.log(`
492
+ \x1B[33m[Network Terminal]\x1B[0m Port ${port} in use, dashboard disabled
493
+ `);
494
+ }
495
+ });
56
496
  },
57
497
  transformIndexHtml(html) {
58
- return {
59
- html,
60
- tags: [
61
- {
62
- tag: "script",
63
- attrs: { type: "module", src: "/@id/__x00__virtual:network-terminal" },
64
- injectTo: "body"
65
- }
66
- ]
67
- };
498
+ const script = `<script>${getMonitorScript(port)}</script>`;
499
+ if (html.includes("</head>")) {
500
+ return html.replace("</head>", script + "</head>");
501
+ }
502
+ return script + html;
503
+ },
504
+ buildEnd() {
505
+ if (dashboardServer) {
506
+ dashboardServer.close();
507
+ }
68
508
  }
69
509
  };
70
510
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vite-plugin.ts"],"sourcesContent":["import type { Plugin } from 'vite';\n\nexport interface NetworkTerminalPluginOptions {\n /** Position of the terminal: 'top' or 'bottom' (default: 'bottom') */\n position?: 'top' | 'bottom';\n /** Maximum number of logs to keep (default: 100) */\n maxLogs?: number;\n /** Terminal height (default: '450px') */\n height?: string;\n /** CSS z-index (default: 9999) */\n zIndex?: number;\n}\n\nconst VIRTUAL_MODULE_ID = 'virtual:network-terminal';\nconst RESOLVED_VIRTUAL_MODULE_ID = '\\0' + VIRTUAL_MODULE_ID;\n\nexport function networkTerminal(options: NetworkTerminalPluginOptions = {}): Plugin {\n const {\n position = 'bottom',\n maxLogs = 100,\n height = '450px',\n zIndex = 9999,\n } = options;\n\n return {\n name: 'vite-plugin-network-terminal',\n apply: 'serve', // Only apply during development\n\n resolveId(id) {\n if (id === VIRTUAL_MODULE_ID) {\n return RESOLVED_VIRTUAL_MODULE_ID;\n }\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_MODULE_ID) {\n return `\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { NetworkTerminal } from 'network-terminal';\n\nfunction initNetworkTerminal() {\n const containerId = '__network-terminal-root__';\n let container = document.getElementById(containerId);\n\n if (!container) {\n container = document.createElement('div');\n container.id = containerId;\n document.body.appendChild(container);\n }\n\n const root = ReactDOM.createRoot(container);\n root.render(\n React.createElement(NetworkTerminal, {\n position: '${position}',\n maxLogs: ${maxLogs},\n height: '${height}',\n zIndex: ${zIndex},\n defaultVisible: false,\n })\n );\n}\n\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initNetworkTerminal);\n} else {\n initNetworkTerminal();\n}\n`;\n }\n },\n\n transformIndexHtml(html) {\n return {\n html,\n tags: [\n {\n tag: 'script',\n attrs: { type: 'module', src: '/@id/__x00__virtual:network-terminal' },\n injectTo: 'body',\n },\n ],\n };\n },\n };\n}\n\nexport default networkTerminal;\n"],"mappings":";AAaA,IAAM,oBAAoB;AAC1B,IAAM,6BAA6B,OAAO;AAEnC,SAAS,gBAAgB,UAAwC,CAAC,GAAW;AAClF,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,UAAU;AAAA,IACV,SAAS;AAAA,IACT,SAAS;AAAA,EACX,IAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA;AAAA,IAEP,UAAU,IAAI;AACZ,UAAI,OAAO,mBAAmB;AAC5B,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,KAAK,IAAI;AACP,UAAI,OAAO,4BAA4B;AACrC,eAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAkBI,QAAQ;AAAA,iBACV,OAAO;AAAA,iBACP,MAAM;AAAA,gBACP,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYhB;AAAA,IACF;AAAA,IAEA,mBAAmB,MAAM;AACvB,aAAO;AAAA,QACL;AAAA,QACA,MAAM;AAAA,UACJ;AAAA,YACE,KAAK;AAAA,YACL,OAAO,EAAE,MAAM,UAAU,KAAK,uCAAuC;AAAA,YACrE,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,sBAAQ;","names":[]}
1
+ {"version":3,"sources":["../src/vite-plugin.ts"],"sourcesContent":["import type { Plugin, ViteDevServer } from 'vite';\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\n\nexport interface NetworkTerminalPluginOptions {\n /** Port for the dashboard (default: 4001) */\n port?: number;\n /** Auto-open dashboard in browser (default: true) */\n open?: boolean;\n}\n\n// Store network logs\nconst networkLogs: any[] = [];\nconst sseClients = new Set<ServerResponse>();\n\nfunction broadcastLog(log: any) {\n const data = JSON.stringify(log);\n sseClients.forEach(client => {\n client.write(`data: ${data}\\n\\n`);\n });\n}\n\nfunction getDashboardHTML(_port: number): string {\n return `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Network Terminal</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n background: #0a0e17;\n color: #e2e8f0;\n height: 100vh;\n overflow: hidden;\n }\n .header {\n background: #0f172a;\n padding: 12px 24px;\n border-bottom: 2px solid #4ade80;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .title { color: #4ade80; font-size: 18px; font-weight: bold; }\n .subtitle { color: #64748b; font-size: 12px; margin-top: 4px; }\n .controls { display: flex; gap: 12px; align-items: center; }\n .btn {\n background: #1e293b;\n border: 1px solid #334155;\n color: #94a3b8;\n padding: 8px 16px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 12px;\n font-family: inherit;\n }\n .btn:hover { background: #334155; color: #e2e8f0; }\n .container { display: flex; height: calc(100vh - 80px); }\n .panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border-right: 1px solid #1e293b;\n }\n .panel:last-child { border-right: none; }\n .panel-header {\n background: #0f172a;\n padding: 12px 16px;\n border-bottom: 1px solid #1e293b;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .panel-title { font-weight: bold; font-size: 14px; }\n .panel-title.request { color: #3b82f6; }\n .panel-title.response { color: #22c55e; }\n .panel-count {\n background: #1e293b;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n color: #64748b;\n }\n .logs { flex: 1; overflow-y: auto; padding: 8px; }\n .log-entry {\n background: #0f172a;\n border: 1px solid #1e293b;\n border-radius: 8px;\n margin-bottom: 8px;\n overflow: hidden;\n cursor: pointer;\n transition: border-color 0.2s;\n }\n .log-entry:hover { border-color: #334155; }\n .log-entry.selected { border-color: #4ade80; }\n .log-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n background: #1e293b;\n }\n .method {\n font-weight: bold;\n font-size: 11px;\n padding: 3px 8px;\n border-radius: 4px;\n }\n .method.GET { background: #166534; color: #4ade80; }\n .method.POST { background: #1e40af; color: #60a5fa; }\n .method.PUT { background: #a16207; color: #fcd34d; }\n .method.DELETE { background: #991b1b; color: #fca5a5; }\n .method.PATCH { background: #7c3aed; color: #c4b5fd; }\n .status { font-size: 11px; padding: 3px 8px; border-radius: 4px; }\n .status.success { background: #166534; color: #4ade80; }\n .status.error { background: #991b1b; color: #fca5a5; }\n .status.pending { background: #374151; color: #9ca3af; }\n .url {\n flex: 1;\n font-size: 12px;\n color: #94a3b8;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .duration { font-size: 11px; color: #64748b; }\n .timestamp { font-size: 10px; color: #475569; }\n .log-body { padding: 12px; font-size: 11px; max-height: 300px; overflow: auto; }\n .log-body pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n color: #cbd5e1;\n line-height: 1.5;\n }\n .log-body.empty { color: #475569; font-style: italic; }\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #475569;\n text-align: center;\n padding: 20px;\n }\n .empty-state svg { width: 48px; height: 48px; margin-bottom: 16px; opacity: 0.5; }\n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #22c55e;\n animation: pulse 2s infinite;\n }\n @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }\n .status-dot.disconnected { background: #ef4444; animation: none; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <div>\n <div class=\"title\">>_ Network Terminal</div>\n <div class=\"subtitle\">Vite Plugin - Monitoring fetch/XHR requests</div>\n </div>\n <div class=\"controls\">\n <div class=\"status-dot\" id=\"statusDot\"></div>\n <button class=\"btn\" onclick=\"clearLogs()\">Clear All</button>\n </div>\n </div>\n\n <div class=\"container\">\n <div class=\"panel\">\n <div class=\"panel-header\">\n <span class=\"panel-title request\">⬆ REQUESTS</span>\n <span class=\"panel-count\" id=\"requestCount\">0</span>\n </div>\n <div class=\"logs\" id=\"requestLogs\">\n <div class=\"empty-state\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 19V5M5 12l7-7 7 7\"/>\n </svg>\n <div>Waiting for requests...</div>\n <div style=\"margin-top: 8px; font-size: 11px;\">Make fetch/XHR requests in your app</div>\n </div>\n </div>\n </div>\n\n <div class=\"panel\">\n <div class=\"panel-header\">\n <span class=\"panel-title response\">⬇ RESPONSES</span>\n <span class=\"panel-count\" id=\"responseCount\">0</span>\n </div>\n <div class=\"logs\" id=\"responseLogs\">\n <div class=\"empty-state\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 5v14M5 12l7 7 7-7\"/>\n </svg>\n <div>Waiting for responses...</div>\n </div>\n </div>\n </div>\n </div>\n\n <script>\n const logs = new Map();\n let selectedId = null;\n\n function formatJson(data) {\n if (!data) return null;\n if (typeof data === 'string') {\n try { data = JSON.parse(data); }\n catch (e) { return escapeHtml(data.substring(0, 2000)); }\n }\n return escapeHtml(JSON.stringify(data, null, 2));\n }\n\n function escapeHtml(str) {\n if (typeof str !== 'string') str = String(str);\n return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n\n function formatTime(timestamp) {\n const date = new Date(timestamp);\n return date.toLocaleTimeString('en-US', { hour12: false }) + '.' +\n String(date.getMilliseconds()).padStart(3, '0');\n }\n\n function getLogsArray() {\n return Array.from(logs.values()).sort((a, b) =>\n new Date(b.timestamp) - new Date(a.timestamp)\n );\n }\n\n function renderLogs() {\n const logsArray = getLogsArray();\n const requestContainer = document.getElementById('requestLogs');\n const responseContainer = document.getElementById('responseLogs');\n\n document.getElementById('requestCount').textContent = logsArray.length;\n document.getElementById('responseCount').textContent = logsArray.filter(l => l.status).length;\n\n if (logsArray.length === 0) {\n requestContainer.innerHTML = '<div class=\"empty-state\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 19V5M5 12l7-7 7 7\"/></svg><div>Waiting for requests...</div></div>';\n responseContainer.innerHTML = '<div class=\"empty-state\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M12 5v14M5 12l7 7 7-7\"/></svg><div>Waiting for responses...</div></div>';\n return;\n }\n\n requestContainer.innerHTML = logsArray.map(log => {\n const isSelected = selectedId === log.id;\n const bodyContent = formatJson(log.requestBody);\n return '<div class=\"log-entry '+(isSelected ? 'selected' : '')+'\" onclick=\"selectLog(\\\\''+log.id+'\\\\')\"><div class=\"log-header\"><span class=\"method '+log.method+'\">'+log.method+'</span><span class=\"url\" title=\"'+escapeHtml(log.url)+'\">'+log.url+'</span><span class=\"timestamp\">'+formatTime(log.timestamp)+'</span></div>'+(isSelected ? '<div class=\"log-body '+(bodyContent ? '' : 'empty')+'\">'+(bodyContent ? '<pre>'+bodyContent+'</pre>' : 'No request body')+'</div>' : '')+'</div>';\n }).join('');\n\n responseContainer.innerHTML = logsArray.map(log => {\n const isSelected = selectedId === log.id;\n const statusClass = !log.status ? 'pending' : log.status < 400 ? 'success' : 'error';\n const bodyContent = formatJson(log.responseBody);\n return '<div class=\"log-entry '+(isSelected ? 'selected' : '')+'\" onclick=\"selectLog(\\\\''+log.id+'\\\\')\"><div class=\"log-header\"><span class=\"status '+statusClass+'\">'+(log.status || '...')+'</span><span class=\"url\" title=\"'+escapeHtml(log.url)+'\">'+log.url+'</span><span class=\"duration\">'+(log.duration ? log.duration + 'ms' : '')+'</span></div>'+(isSelected ? '<div class=\"log-body '+(bodyContent ? '' : 'empty')+'\">'+(bodyContent ? '<pre>'+bodyContent+'</pre>' : (log.status ? 'No response body' : 'Pending...'))+'</div>' : '')+'</div>';\n }).join('');\n }\n\n function selectLog(id) {\n selectedId = selectedId === id ? null : id;\n renderLogs();\n }\n\n function clearLogs() {\n logs.clear();\n selectedId = null;\n renderLogs();\n fetch('/clear', { method: 'POST' });\n }\n\n function addLog(log) {\n logs.set(log.id, log);\n if (logs.size > 100) {\n const oldest = getLogsArray().pop();\n if (oldest) logs.delete(oldest.id);\n }\n renderLogs();\n }\n\n function connect() {\n const evtSource = new EventSource('/events');\n evtSource.onopen = () => document.getElementById('statusDot').classList.remove('disconnected');\n evtSource.onmessage = (event) => addLog(JSON.parse(event.data));\n evtSource.onerror = () => {\n document.getElementById('statusDot').classList.add('disconnected');\n evtSource.close();\n setTimeout(connect, 2000);\n };\n }\n\n connect();\n renderLogs();\n </script>\n</body>\n</html>\n`;\n}\n\nfunction getMonitorScript(port: number): string {\n return `\n(function() {\n if (window.__networkTerminalActive) return;\n window.__networkTerminalActive = true;\n\n var DASHBOARD_URL = 'http://localhost:${port}';\n\n function sendLog(log) {\n var xhr = new XMLHttpRequest();\n xhr.open('POST', DASHBOARD_URL + '/log', true);\n xhr.setRequestHeader('Content-Type', 'application/json');\n xhr.send(JSON.stringify(log));\n }\n\n function tryParse(data) {\n if (!data) return null;\n if (typeof data === 'object') return data;\n try { return JSON.parse(data); } catch (e) { return data; }\n }\n\n var originalFetch = window.fetch;\n window.fetch = function() {\n var args = arguments;\n var startTime = Date.now();\n var input = args[0];\n var options = args[1] || {};\n var url = typeof input === 'string' ? input : (input.url || input.toString());\n var method = (options.method || 'GET').toUpperCase();\n\n if (url.includes('localhost:${port}')) {\n return originalFetch.apply(this, args);\n }\n\n var log = {\n id: Date.now().toString() + Math.random().toString(36).substr(2, 9),\n method: method,\n url: url,\n timestamp: new Date().toISOString(),\n requestBody: options.body ? tryParse(options.body) : null,\n status: null,\n responseBody: null,\n duration: null,\n };\n\n sendLog(log);\n\n return originalFetch.apply(this, args).then(function(response) {\n log.status = response.status;\n log.duration = Date.now() - startTime;\n var cloned = response.clone();\n cloned.text().then(function(text) {\n log.responseBody = tryParse(text);\n sendLog(log);\n }).catch(function() { sendLog(log); });\n return response;\n }).catch(function(error) {\n log.status = 0;\n log.duration = Date.now() - startTime;\n log.error = error.message;\n sendLog(log);\n throw error;\n });\n };\n\n var OriginalXHR = window.XMLHttpRequest;\n window.XMLHttpRequest = function() {\n var xhr = new OriginalXHR();\n var method, url, requestBody, startTime;\n\n var originalOpen = xhr.open;\n xhr.open = function(m, u) {\n method = m;\n url = u;\n return originalOpen.apply(this, arguments);\n };\n\n var originalSend = xhr.send;\n xhr.send = function(body) {\n if (url && url.includes('localhost:${port}')) {\n return originalSend.apply(this, arguments);\n }\n\n startTime = Date.now();\n requestBody = body;\n\n var log = {\n id: Date.now().toString() + Math.random().toString(36).substr(2, 9),\n method: (method || 'GET').toUpperCase(),\n url: url,\n timestamp: new Date().toISOString(),\n requestBody: tryParse(requestBody),\n status: null,\n responseBody: null,\n duration: null,\n };\n\n sendLog(log);\n\n xhr.addEventListener('loadend', function() {\n log.status = xhr.status;\n log.duration = Date.now() - startTime;\n log.responseBody = tryParse(xhr.responseText);\n sendLog(log);\n });\n\n return originalSend.apply(this, arguments);\n };\n\n return xhr;\n };\n\n console.log('[Network Terminal] ✓ Active - Dashboard: http://localhost:${port}');\n})();\n`;\n}\n\nexport function networkTerminal(options: NetworkTerminalPluginOptions = {}): Plugin {\n const { port = 4001, open = true } = options;\n let dashboardServer: ReturnType<typeof createServer> | null = null;\n\n return {\n name: 'vite-plugin-network-terminal',\n apply: 'serve',\n\n configureServer(_server: ViteDevServer) {\n // Start dashboard server\n dashboardServer = createServer((req: IncomingMessage, res: ServerResponse) => {\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (req.url === '/events') {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n sseClients.add(res);\n networkLogs.forEach(log => {\n res.write(`data: ${JSON.stringify(log)}\\n\\n`);\n });\n req.on('close', () => sseClients.delete(res));\n return;\n }\n\n if (req.url === '/log' && req.method === 'POST') {\n let body = '';\n req.on('data', (chunk: Buffer) => body += chunk);\n req.on('end', () => {\n try {\n const log = JSON.parse(body);\n const existingIndex = networkLogs.findIndex(l => l.id === log.id);\n if (existingIndex >= 0) {\n networkLogs[existingIndex] = log;\n } else {\n networkLogs.unshift(log);\n if (networkLogs.length > 100) networkLogs.pop();\n }\n broadcastLog(log);\n } catch (e) {}\n res.writeHead(200);\n res.end('OK');\n });\n return;\n }\n\n if (req.url === '/clear' && req.method === 'POST') {\n networkLogs.length = 0;\n res.writeHead(200);\n res.end('OK');\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(getDashboardHTML(port));\n });\n\n dashboardServer.listen(port, () => {\n console.log(`\\n \\x1b[32m>_ Network Terminal\\x1b[0m`);\n console.log(` Dashboard: \\x1b[36mhttp://localhost:${port}\\x1b[0m\\n`);\n\n if (open) {\n const openCmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n require('child_process').exec(`${openCmd} http://localhost:${port}`);\n }\n });\n\n dashboardServer.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n console.log(`\\n \\x1b[33m[Network Terminal]\\x1b[0m Port ${port} in use, dashboard disabled\\n`);\n }\n });\n },\n\n transformIndexHtml(html: string) {\n const script = `<script>${getMonitorScript(port)}</script>`;\n if (html.includes('</head>')) {\n return html.replace('</head>', script + '</head>');\n }\n return script + html;\n },\n\n buildEnd() {\n if (dashboardServer) {\n dashboardServer.close();\n }\n },\n };\n}\n\nexport default networkTerminal;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "network-terminal",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "A browser-based terminal UI for monitoring Fetch/XHR requests with real-time display of routes, payloads, and responses",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -65,6 +65,7 @@
65
65
  }
66
66
  },
67
67
  "devDependencies": {
68
+ "@types/node": "^25.0.10",
68
69
  "@types/react": "^18.2.0",
69
70
  "@types/react-dom": "^18.2.0",
70
71
  "tsup": "^8.0.0",