hono-status-monitor 1.0.0 → 1.0.2

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 CHANGED
@@ -5,7 +5,8 @@
5
5
 
6
6
  Real-time server monitoring dashboard for **Hono.js** applications with WebSocket updates. Express-status-monitor style metrics powered by Socket.io.
7
7
 
8
- ![Status Monitor Dashboard](https://via.placeholder.com/800x450/1a1a1a/fff?text=Status+Monitor+Dashboard)
8
+ <img width="403" height="736" alt="Screenshot 2026-01-01 at 11 58 25 AM" src="https://github.com/user-attachments/assets/f793b5f0-a10e-4699-98ab-b4708703d024" />
9
+
9
10
 
10
11
  ## ✨ Features
11
12
 
@@ -111,7 +112,10 @@ const monitor = statusMonitor({
111
112
  return path
112
113
  .replace(/\/users\/\d+/g, '/users/:id')
113
114
  .replace(/\/posts\/[a-f0-9]{24}/g, '/posts/:id');
114
- }
115
+ },
116
+
117
+ // Enable cluster mode for PM2 (auto-detected by default)
118
+ clusterMode: true
115
119
  });
116
120
  ```
117
121
 
@@ -281,6 +285,67 @@ const monitor = statusMonitor({
281
285
  });
282
286
  ```
283
287
 
288
+ ### PM2 / Cluster Mode Support
289
+
290
+ To enable metrics aggregation across multiple processes (Cluster Mode), you need a specific entry point script that handles message relaying between workers.
291
+
292
+ 1. **Create a `cluster.ts` (or `.js`) entry file:**
293
+
294
+ ```typescript
295
+ import cluster from 'node:cluster';
296
+ import * as os from 'node:os';
297
+ import { dirname } from 'node:path';
298
+ import { fileURLToPath } from 'node:url';
299
+
300
+ const __dirname = dirname(fileURLToPath(import.meta.url));
301
+ const numCPUs = os.cpus().length;
302
+
303
+ if (cluster.isPrimary) {
304
+ console.log(`Primary ${process.pid} is running`);
305
+
306
+ // Fork workers
307
+ for (let i = 0; i < numCPUs; i++) {
308
+ const worker = cluster.fork();
309
+
310
+ // Relay messages between workers
311
+ worker.on('message', (message) => {
312
+ if (message?.type === 'worker-metrics') {
313
+ // Broadcast to all workers (including sender)
314
+ for (const id in cluster.workers) {
315
+ cluster.workers[id]?.send(message);
316
+ }
317
+ }
318
+ });
319
+ }
320
+
321
+ cluster.on('exit', (worker) => {
322
+ console.log(`worker ${worker.process.pid} died`);
323
+ // Replace dead worker
324
+ const newWorker = cluster.fork();
325
+ newWorker.on('message', (message) => {
326
+ if (message?.type === 'worker-metrics') {
327
+ for (const id in cluster.workers) {
328
+ cluster.workers[id]?.send(message);
329
+ }
330
+ }
331
+ });
332
+ });
333
+ } else {
334
+ // Workers share the TCP connection in this file
335
+ await import('./index'); // Path to your main app file
336
+ }
337
+ ```
338
+
339
+ 2. **Run this cluster script with PM2:**
340
+
341
+ ```bash
342
+ # Start the cluster script as a SINGLE PM2 instance
343
+ # (The script itself manages the worker processes)
344
+ pm2 start cluster.ts --name my-app
345
+ ```
346
+
347
+ **Note:** Do NOT use `pm2 start app.ts -i max` directly, as PM2's default isolation prevents workers from sharing metrics without an external adapter (like Redis). Using the script above provides a zero-dependency aggregation solution.
348
+
284
349
  ## 🛡️ Security Considerations
285
350
 
286
351
  The status dashboard exposes server metrics. Consider:
@@ -301,11 +366,64 @@ app.use('/status/*', basicAuth({
301
366
  app.route('/status', monitor.routes);
302
367
  ```
303
368
 
369
+ ## ☁️ Cloudflare Workers / Edge Support
370
+
371
+ This package automatically detects Cloudflare Workers and edge runtimes, providing a lightweight monitor with available metrics.
372
+
373
+ ### Available Metrics in Edge Environments
374
+
375
+ | Metric | Available | Notes |
376
+ |--------|-----------|-------|
377
+ | Request count & RPS | ✅ | Fully supported |
378
+ | Response time percentiles | ✅ | P50, P95, P99, Avg |
379
+ | Status code breakdown | ✅ | 2xx, 3xx, 4xx, 5xx |
380
+ | Route analytics | ✅ | Top routes, slowest routes |
381
+ | Error tracking | ✅ | Recent errors with timestamps |
382
+ | CPU / Memory / Heap | ❌ | Not available in Workers |
383
+ | Event loop lag | ❌ | Not available in Workers |
384
+ | Load average | ❌ | Not available in Workers |
385
+ | WebSocket real-time | ❌ | Uses polling (5s interval) |
386
+
387
+ ### Usage in Cloudflare Workers
388
+
389
+ ```typescript
390
+ import { Hono } from 'hono';
391
+ import { statusMonitor } from 'hono-status-monitor';
392
+
393
+ const app = new Hono();
394
+
395
+ // Create status monitor - automatically detects edge environment
396
+ const monitor = statusMonitor();
397
+
398
+ // Add middleware to track requests
399
+ app.use('*', monitor.middleware);
400
+
401
+ // Mount status dashboard
402
+ app.route('/status', monitor.routes);
403
+
404
+ // Your routes
405
+ app.get('/', (c) => c.text('Hello from Cloudflare Workers!'));
406
+
407
+ export default app;
408
+ ```
409
+
410
+ > **Note:** In Cloudflare Workers, the dashboard uses HTTP polling (every 5 seconds) instead of WebSocket for updates. The dashboard will display an "Edge Mode" indicator.
411
+
412
+ ### Force Edge Mode
413
+
414
+ You can explicitly use the edge-compatible monitor:
415
+
416
+ ```typescript
417
+ import { statusMonitorEdge } from 'hono-status-monitor';
418
+
419
+ const monitor = statusMonitorEdge();
420
+ ```
421
+
304
422
  ## 📋 Requirements
305
423
 
306
- - Node.js >= 18.0.0
424
+ - Node.js >= 18.0.0 (for Node.js mode)
307
425
  - Hono.js >= 4.0.0
308
- - @hono/node-server >= 1.0.0
426
+ - @hono/node-server >= 1.0.0 (for Node.js mode only)
309
427
 
310
428
  ## 🤝 Contributing
311
429
 
@@ -318,3 +436,4 @@ MIT © [Vinit Kumar Goel](https://github.com/vinitkumargoel)
318
436
  ---
319
437
 
320
438
  Made with ❤️ for the Hono.js community
439
+
@@ -0,0 +1,29 @@
1
+ import type { MetricsSnapshot, ChartData, WorkerInfo, WorkerMetricsMessage } from './types.js';
2
+ /**
3
+ * Check if running in cluster mode (PM2 or native Node.js cluster)
4
+ */
5
+ export declare function isClusterWorker(): boolean;
6
+ /**
7
+ * Check if this is the primary/master process
8
+ */
9
+ export declare function isClusterMaster(): boolean;
10
+ /**
11
+ * Get worker ID
12
+ */
13
+ export declare function getWorkerId(): number;
14
+ /**
15
+ * Send metrics from worker to parent process (for PM2 cluster mode)
16
+ */
17
+ export declare function sendMetricsToMaster(metrics: Partial<MetricsSnapshot>, charts: ChartData): void;
18
+ /**
19
+ * Create a cluster aggregator for the master process
20
+ */
21
+ export declare function createClusterAggregator(): {
22
+ updateWorkerMetrics: (message: WorkerMetricsMessage) => void;
23
+ getWorkerInfo: () => WorkerInfo[];
24
+ aggregateMetrics: (baseSnapshot: MetricsSnapshot) => MetricsSnapshot;
25
+ aggregateCharts: (baseCharts: ChartData) => ChartData;
26
+ readonly workerCount: number;
27
+ };
28
+ export type ClusterAggregator = ReturnType<typeof createClusterAggregator>;
29
+ //# sourceMappingURL=cluster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../src/cluster.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACR,eAAe,EACf,SAAS,EACT,UAAU,EACV,oBAAoB,EAIvB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAUpC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,MAAM,EAAE,SAAS,GAClB,IAAI,CAgBN;AAcD;;GAEG;AACH,wBAAgB,uBAAuB;mCAOG,oBAAoB,KAAG,IAAI;yBAwBvC,UAAU,EAAE;qCAeE,eAAe,KAAG,eAAe;kCAsHpC,SAAS,KAAG,SAAS;;EAsE7D;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,256 @@
1
+ // =============================================================================
2
+ // HONO STATUS MONITOR - CLUSTER UTILITIES
3
+ // PM2 / Node.js Cluster mode support for metrics aggregation
4
+ // =============================================================================
5
+ import cluster from 'cluster';
6
+ /**
7
+ * Check if running in cluster mode (PM2 or native Node.js cluster)
8
+ */
9
+ export function isClusterWorker() {
10
+ return cluster.isWorker || !!process.env.PM2_HOME || !!process.env.NODE_APP_INSTANCE;
11
+ }
12
+ /**
13
+ * Check if this is the primary/master process
14
+ */
15
+ export function isClusterMaster() {
16
+ return cluster.isPrimary || cluster.isMaster;
17
+ }
18
+ /**
19
+ * Get worker ID
20
+ */
21
+ export function getWorkerId() {
22
+ if (cluster.worker) {
23
+ return cluster.worker.id;
24
+ }
25
+ // PM2 instance ID
26
+ const instanceId = process.env.NODE_APP_INSTANCE;
27
+ if (instanceId) {
28
+ return parseInt(instanceId, 10);
29
+ }
30
+ return 0;
31
+ }
32
+ /**
33
+ * Send metrics from worker to parent process (for PM2 cluster mode)
34
+ */
35
+ export function sendMetricsToMaster(metrics, charts) {
36
+ if (!process.send)
37
+ return;
38
+ const message = {
39
+ type: 'worker-metrics',
40
+ workerId: getWorkerId(),
41
+ pid: process.pid,
42
+ metrics,
43
+ charts
44
+ };
45
+ try {
46
+ process.send(message);
47
+ }
48
+ catch (error) {
49
+ // Silently ignore send errors (master may have died)
50
+ }
51
+ }
52
+ /**
53
+ * Create a cluster aggregator for the master process
54
+ */
55
+ export function createClusterAggregator() {
56
+ const workerMetrics = {};
57
+ const WORKER_TIMEOUT_MS = 10000; // Consider worker dead after 10s no update
58
+ /**
59
+ * Update metrics from a worker
60
+ */
61
+ function updateWorkerMetrics(message) {
62
+ workerMetrics[message.workerId] = {
63
+ pid: message.pid,
64
+ metrics: message.metrics,
65
+ charts: message.charts,
66
+ lastUpdate: Date.now()
67
+ };
68
+ }
69
+ /**
70
+ * Clean up stale workers
71
+ */
72
+ function cleanupStaleWorkers() {
73
+ const now = Date.now();
74
+ for (const workerId of Object.keys(workerMetrics)) {
75
+ if (now - workerMetrics[parseInt(workerId)].lastUpdate > WORKER_TIMEOUT_MS) {
76
+ delete workerMetrics[parseInt(workerId)];
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * Get all active worker info
82
+ */
83
+ function getWorkerInfo() {
84
+ cleanupStaleWorkers();
85
+ return Object.values(workerMetrics).map(w => ({
86
+ pid: w.pid,
87
+ cpu: w.metrics.cpu || 0,
88
+ memoryMB: w.metrics.memoryMB || 0,
89
+ rps: w.metrics.rps || 0,
90
+ totalRequests: w.metrics.totalRequests || 0,
91
+ responseTime: w.metrics.responseTime || 0
92
+ }));
93
+ }
94
+ /**
95
+ * Aggregate metrics from all workers
96
+ */
97
+ function aggregateMetrics(baseSnapshot) {
98
+ cleanupStaleWorkers();
99
+ const workers = Object.values(workerMetrics);
100
+ if (workers.length === 0) {
101
+ return baseSnapshot;
102
+ }
103
+ // Sum metrics that should be totaled across workers
104
+ let totalRps = 0;
105
+ let totalRequests = 0;
106
+ let totalActiveConnections = 0;
107
+ let totalErrorRate = 0;
108
+ // Average metrics that should be averaged
109
+ let totalCpu = 0;
110
+ let totalResponseTime = 0;
111
+ let workerCount = 0;
112
+ // Aggregate status codes
113
+ const aggregatedStatusCodes = {};
114
+ // Aggregate rate limit stats
115
+ let totalRateLimitBlocked = 0;
116
+ let totalRateLimitTotal = 0;
117
+ // Aggregate routes
118
+ const routeMap = new Map();
119
+ for (const worker of workers) {
120
+ const m = worker.metrics;
121
+ workerCount++;
122
+ // Sum
123
+ totalRps += m.rps || 0;
124
+ totalRequests += m.totalRequests || 0;
125
+ totalActiveConnections += m.activeConnections || 0;
126
+ // For averaging
127
+ totalCpu += m.cpu || 0;
128
+ totalResponseTime += m.responseTime || 0;
129
+ totalErrorRate += m.errorRate || 0;
130
+ // Aggregate status codes
131
+ if (m.statusCodes) {
132
+ for (const [code, count] of Object.entries(m.statusCodes)) {
133
+ aggregatedStatusCodes[code] = (aggregatedStatusCodes[code] || 0) + count;
134
+ }
135
+ }
136
+ // Aggregate rate limit stats
137
+ if (m.rateLimitStats) {
138
+ totalRateLimitBlocked += m.rateLimitStats.blocked || 0;
139
+ totalRateLimitTotal += m.rateLimitStats.total || 0;
140
+ }
141
+ // Aggregate routes
142
+ const allRoutes = [
143
+ ...(m.topRoutes || []),
144
+ ...(m.slowestRoutes || []),
145
+ ...(m.errorRoutes || [])
146
+ ];
147
+ for (const route of allRoutes) {
148
+ const key = `${route.method}:${route.path}`;
149
+ const existing = routeMap.get(key);
150
+ if (existing) {
151
+ existing.count += route.count;
152
+ existing.totalTime += route.totalTime;
153
+ existing.avgTime = existing.totalTime / existing.count;
154
+ existing.minTime = Math.min(existing.minTime, route.minTime);
155
+ existing.maxTime = Math.max(existing.maxTime, route.maxTime);
156
+ existing.errors += route.errors;
157
+ existing.lastAccess = Math.max(existing.lastAccess, route.lastAccess);
158
+ }
159
+ else {
160
+ routeMap.set(key, { ...route });
161
+ }
162
+ }
163
+ }
164
+ // Calculate averages
165
+ const avgCpu = workerCount > 0 ? totalCpu / workerCount : baseSnapshot.cpu;
166
+ const avgResponseTime = workerCount > 0 ? totalResponseTime / workerCount : baseSnapshot.responseTime;
167
+ const avgErrorRate = workerCount > 0 ? totalErrorRate / workerCount : baseSnapshot.errorRate;
168
+ // Get aggregated routes
169
+ const allRoutes = Array.from(routeMap.values());
170
+ const topRoutes = allRoutes.sort((a, b) => b.count - a.count).slice(0, 10);
171
+ const slowestRoutes = allRoutes.filter(r => r.count > 0).sort((a, b) => b.avgTime - a.avgTime).slice(0, 10);
172
+ const errorRoutes = allRoutes.filter(r => r.errors > 0).sort((a, b) => b.errors - a.errors).slice(0, 10);
173
+ return {
174
+ ...baseSnapshot,
175
+ cpu: Math.round(avgCpu * 10) / 10,
176
+ responseTime: Math.round(avgResponseTime * 100) / 100,
177
+ rps: totalRps,
178
+ totalRequests,
179
+ activeConnections: totalActiveConnections,
180
+ errorRate: Math.round(avgErrorRate * 100) / 100,
181
+ statusCodes: Object.keys(aggregatedStatusCodes).length > 0
182
+ ? aggregatedStatusCodes
183
+ : baseSnapshot.statusCodes,
184
+ rateLimitStats: {
185
+ blocked: totalRateLimitBlocked,
186
+ total: totalRateLimitTotal
187
+ },
188
+ topRoutes,
189
+ slowestRoutes,
190
+ errorRoutes,
191
+ workers: getWorkerInfo(),
192
+ workerCount
193
+ };
194
+ }
195
+ /**
196
+ * Aggregate chart data from all workers
197
+ */
198
+ function aggregateCharts(baseCharts) {
199
+ cleanupStaleWorkers();
200
+ const workers = Object.values(workerMetrics);
201
+ if (workers.length === 0) {
202
+ return baseCharts;
203
+ }
204
+ // For charts, we need to merge data points by timestamp
205
+ const mergeChartData = (base, workerCharts, key, aggregationType) => {
206
+ const timeMap = new Map();
207
+ // Add base data
208
+ for (const point of base) {
209
+ timeMap.set(point.timestamp, { sum: point.value, count: 1 });
210
+ }
211
+ // Add worker data
212
+ for (const wc of workerCharts) {
213
+ const data = wc[key];
214
+ for (const point of data) {
215
+ const existing = timeMap.get(point.timestamp);
216
+ if (existing) {
217
+ existing.sum += point.value;
218
+ existing.count++;
219
+ }
220
+ else {
221
+ timeMap.set(point.timestamp, { sum: point.value, count: 1 });
222
+ }
223
+ }
224
+ }
225
+ // Convert back to array
226
+ const result = [];
227
+ for (const [timestamp, { sum, count }] of timeMap.entries()) {
228
+ const value = aggregationType === 'sum' ? sum : sum / count;
229
+ result.push({ timestamp, value: Math.round(value * 100) / 100 });
230
+ }
231
+ return result.sort((a, b) => a.timestamp - b.timestamp);
232
+ };
233
+ const workerCharts = workers.map(w => w.charts);
234
+ return {
235
+ cpu: mergeChartData(baseCharts.cpu, workerCharts, 'cpu', 'avg'),
236
+ memory: mergeChartData(baseCharts.memory, workerCharts, 'memory', 'avg'),
237
+ heap: mergeChartData(baseCharts.heap, workerCharts, 'heap', 'avg'),
238
+ loadAvg: mergeChartData(baseCharts.loadAvg, workerCharts, 'loadAvg', 'avg'),
239
+ responseTime: mergeChartData(baseCharts.responseTime, workerCharts, 'responseTime', 'avg'),
240
+ rps: mergeChartData(baseCharts.rps, workerCharts, 'rps', 'sum'),
241
+ eventLoopLag: mergeChartData(baseCharts.eventLoopLag, workerCharts, 'eventLoopLag', 'avg'),
242
+ errorRate: mergeChartData(baseCharts.errorRate, workerCharts, 'errorRate', 'avg')
243
+ };
244
+ }
245
+ return {
246
+ updateWorkerMetrics,
247
+ getWorkerInfo,
248
+ aggregateMetrics,
249
+ aggregateCharts,
250
+ get workerCount() {
251
+ cleanupStaleWorkers();
252
+ return Object.keys(workerMetrics).length;
253
+ }
254
+ };
255
+ }
256
+ //# sourceMappingURL=cluster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.js","sourceRoot":"","sources":["../src/cluster.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,6DAA6D;AAC7D,gFAAgF;AAEhF,OAAO,OAAO,MAAM,SAAS,CAAC;AAW9B;;GAEG;AACH,MAAM,UAAU,eAAe;IAC3B,OAAO,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC3B,OAAO,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACvB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IAC7B,CAAC;IACD,kBAAkB;IAClB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACjD,IAAI,UAAU,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,CAAC,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAC/B,OAAiC,EACjC,MAAiB;IAEjB,IAAI,CAAC,OAAO,CAAC,IAAI;QAAE,OAAO;IAE1B,MAAM,OAAO,GAAyB;QAClC,IAAI,EAAE,gBAAgB;QACtB,QAAQ,EAAE,WAAW,EAAE;QACvB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO;QACP,MAAM;KACT,CAAC;IAEF,IAAI,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,qDAAqD;IACzD,CAAC;AACL,CAAC;AAcD;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACnC,MAAM,aAAa,GAAuB,EAAE,CAAC;IAC7C,MAAM,iBAAiB,GAAG,KAAK,CAAC,CAAC,2CAA2C;IAE5E;;OAEG;IACH,SAAS,mBAAmB,CAAC,OAA6B;QACtD,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG;YAC9B,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;SACzB,CAAC;IACN,CAAC;IAED;;OAEG;IACH,SAAS,mBAAmB;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,GAAG,iBAAiB,EAAE,CAAC;gBACzE,OAAO,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC7C,CAAC;QACL,CAAC;IACL,CAAC;IAED;;OAEG;IACH,SAAS,aAAa;QAClB,mBAAmB,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC1C,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;YACvB,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC;YACjC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;YACvB,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,IAAI,CAAC;YAC3C,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,IAAI,CAAC;SAC5C,CAAC,CAAC,CAAC;IACR,CAAC;IAED;;OAEG;IACH,SAAS,gBAAgB,CAAC,YAA6B;QACnD,mBAAmB,EAAE,CAAC;QAEtB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,YAAY,CAAC;QACxB,CAAC;QAED,oDAAoD;QACpD,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,aAAa,GAAG,CAAC,CAAC;QACtB,IAAI,sBAAsB,GAAG,CAAC,CAAC;QAC/B,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,0CAA0C;QAC1C,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAC1B,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,yBAAyB;QACzB,MAAM,qBAAqB,GAAoB,EAAE,CAAC;QAElD,6BAA6B;QAC7B,IAAI,qBAAqB,GAAG,CAAC,CAAC;QAC9B,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAE5B,mBAAmB;QACnB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;QAE/C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;YACzB,WAAW,EAAE,CAAC;YAEd,MAAM;YACN,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YACvB,aAAa,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC;YACtC,sBAAsB,IAAI,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC;YAEnD,gBAAgB;YAChB,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YACvB,iBAAiB,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YACzC,cAAc,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;YAEnC,yBAAyB;YACzB,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;gBAChB,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC;oBACxD,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAI,KAAgB,CAAC;gBACzF,CAAC;YACL,CAAC;YAED,6BAA6B;YAC7B,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,qBAAqB,IAAI,CAAC,CAAC,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC;gBACvD,mBAAmB,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC;YACvD,CAAC;YAED,mBAAmB;YACnB,MAAM,SAAS,GAAG;gBACd,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;gBACtB,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,EAAE,CAAC;gBAC1B,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;aAC3B,CAAC;YAEF,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;gBAC5B,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAEnC,IAAI,QAAQ,EAAE,CAAC;oBACX,QAAQ,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC;oBAC9B,QAAQ,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC;oBACtC,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC;oBACvD,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC7D,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC7D,QAAQ,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;oBAChC,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC1E,CAAC;qBAAM,CAAC;oBACJ,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;gBACpC,CAAC;YACL,CAAC;QACL,CAAC;QAED,qBAAqB;QACrB,MAAM,MAAM,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC;QAC3E,MAAM,eAAe,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC;QACtG,MAAM,YAAY,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC;QAE7F,wBAAwB;QACxB,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3E,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5G,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEzG,OAAO;YACH,GAAG,YAAY;YACf,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE;YACjC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,GAAG,CAAC,GAAG,GAAG;YACrD,GAAG,EAAE,QAAQ;YACb,aAAa;YACb,iBAAiB,EAAE,sBAAsB;YACzC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG;YAC/C,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,MAAM,GAAG,CAAC;gBACtD,CAAC,CAAC,qBAAqB;gBACvB,CAAC,CAAC,YAAY,CAAC,WAAW;YAC9B,cAAc,EAAE;gBACZ,OAAO,EAAE,qBAAqB;gBAC9B,KAAK,EAAE,mBAAmB;aAC7B;YACD,SAAS;YACT,aAAa;YACb,WAAW;YACX,OAAO,EAAE,aAAa,EAAE;YACxB,WAAW;SACd,CAAC;IACN,CAAC;IAED;;OAEG;IACH,SAAS,eAAe,CAAC,UAAqB;QAC1C,mBAAmB,EAAE,CAAC;QAEtB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,UAAU,CAAC;QACtB,CAAC;QAED,wDAAwD;QACxD,MAAM,cAAc,GAAG,CACnB,IAAuB,EACvB,YAAyB,EACzB,GAAoB,EACpB,eAA8B,EACb,EAAE;YACnB,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0C,CAAC;YAElE,gBAAgB;YAChB,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACjE,CAAC;YAED,kBAAkB;YAClB,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,EAAE,CAAC,GAAG,CAAsB,CAAC;gBAC1C,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;oBAC9C,IAAI,QAAQ,EAAE,CAAC;wBACX,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC;wBAC5B,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACrB,CAAC;yBAAM,CAAC;wBACJ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBACjE,CAAC;gBACL,CAAC;YACL,CAAC;YAED,wBAAwB;YACxB,MAAM,MAAM,GAAsB,EAAE,CAAC;YACrC,KAAK,MAAM,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC1D,MAAM,KAAK,GAAG,eAAe,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC;gBAC5D,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;YACrE,CAAC;YAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAC5D,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAEhD,OAAO;YACH,GAAG,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC;YAC/D,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,CAAC;YACxE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC;YAClE,OAAO,EAAE,cAAc,CAAC,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,CAAC;YAC3E,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,CAAC;YAC1F,GAAG,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,CAAC;YAC/D,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,KAAK,CAAC;YAC1F,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,CAAC;SACpF,CAAC;IACN,CAAC;IAED,OAAO;QACH,mBAAmB;QACnB,aAAa;QACb,gBAAgB;QAChB,eAAe;QACf,IAAI,WAAW;YACX,mBAAmB,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;QAC7C,CAAC;KACJ,CAAC;AACN,CAAC"}
@@ -3,4 +3,17 @@ import type { DashboardProps } from './types.js';
3
3
  * Generate the status dashboard HTML
4
4
  */
5
5
  export declare function generateDashboard({ hostname, uptime, socketPath, title }: DashboardProps): string;
6
+ /**
7
+ * Edge Dashboard Props (no socketPath)
8
+ */
9
+ export interface EdgeDashboardProps {
10
+ hostname: string;
11
+ uptime: string;
12
+ title: string;
13
+ }
14
+ /**
15
+ * Generate the edge-compatible status dashboard HTML
16
+ * Uses polling instead of WebSocket, only shows available metrics
17
+ */
18
+ export declare function generateEdgeDashboard({ hostname, uptime, title }: EdgeDashboardProps): string;
6
19
  //# sourceMappingURL=dashboard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,MAAM,CA6bjG"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,MAAM,CA6bjG;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,kBAAkB,GAAG,MAAM,CAkY7F"}