@superdangerous/app-framework 4.9.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.
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/dist/api/logsRouter.d.ts +20 -0
- package/dist/api/logsRouter.d.ts.map +1 -0
- package/dist/api/logsRouter.js +515 -0
- package/dist/api/logsRouter.js.map +1 -0
- package/dist/cli/dev-server.d.ts +7 -0
- package/dist/cli/dev-server.d.ts.map +1 -0
- package/dist/cli/dev-server.js +640 -0
- package/dist/cli/dev-server.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/StandardServer.d.ts +129 -0
- package/dist/core/StandardServer.d.ts.map +1 -0
- package/dist/core/StandardServer.js +453 -0
- package/dist/core/StandardServer.js.map +1 -0
- package/dist/core/apiResponse.d.ts +69 -0
- package/dist/core/apiResponse.d.ts.map +1 -0
- package/dist/core/apiResponse.js +127 -0
- package/dist/core/apiResponse.js.map +1 -0
- package/dist/core/healthCheck.d.ts +160 -0
- package/dist/core/healthCheck.d.ts.map +1 -0
- package/dist/core/healthCheck.js +398 -0
- package/dist/core/healthCheck.js.map +1 -0
- package/dist/core/index.d.ts +40 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +40 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +117 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +826 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/portUtils.d.ts +71 -0
- package/dist/core/portUtils.d.ts.map +1 -0
- package/dist/core/portUtils.js +240 -0
- package/dist/core/portUtils.js.map +1 -0
- package/dist/core/storageService.d.ts +119 -0
- package/dist/core/storageService.d.ts.map +1 -0
- package/dist/core/storageService.js +405 -0
- package/dist/core/storageService.js.map +1 -0
- package/dist/desktop/bundler.d.ts +40 -0
- package/dist/desktop/bundler.d.ts.map +1 -0
- package/dist/desktop/bundler.js +176 -0
- package/dist/desktop/bundler.js.map +1 -0
- package/dist/desktop/index.d.ts +25 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/index.js +15 -0
- package/dist/desktop/index.js.map +1 -0
- package/dist/desktop/native-modules.d.ts +66 -0
- package/dist/desktop/native-modules.d.ts.map +1 -0
- package/dist/desktop/native-modules.js +200 -0
- package/dist/desktop/native-modules.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/LogCategories.d.ts +87 -0
- package/dist/logging/LogCategories.d.ts.map +1 -0
- package/dist/logging/LogCategories.js +205 -0
- package/dist/logging/LogCategories.js.map +1 -0
- package/dist/middleware/aiErrorHandler.d.ts +31 -0
- package/dist/middleware/aiErrorHandler.d.ts.map +1 -0
- package/dist/middleware/aiErrorHandler.js +181 -0
- package/dist/middleware/aiErrorHandler.js.map +1 -0
- package/dist/middleware/auth.d.ts +101 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +230 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +56 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +123 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +13 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +85 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/fileUpload.d.ts +62 -0
- package/dist/middleware/fileUpload.d.ts.map +1 -0
- package/dist/middleware/fileUpload.js +175 -0
- package/dist/middleware/fileUpload.js.map +1 -0
- package/dist/middleware/health.d.ts +48 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +143 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/index.d.ts +20 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +18 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/openapi.d.ts +64 -0
- package/dist/middleware/openapi.d.ts.map +1 -0
- package/dist/middleware/openapi.js +258 -0
- package/dist/middleware/openapi.js.map +1 -0
- package/dist/middleware/requestLogging.d.ts +22 -0
- package/dist/middleware/requestLogging.d.ts.map +1 -0
- package/dist/middleware/requestLogging.js +61 -0
- package/dist/middleware/requestLogging.js.map +1 -0
- package/dist/middleware/session.d.ts +84 -0
- package/dist/middleware/session.d.ts.map +1 -0
- package/dist/middleware/session.js +189 -0
- package/dist/middleware/session.js.map +1 -0
- package/dist/middleware/validation.d.ts +1337 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +483 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/services/aiService.d.ts +180 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +547 -0
- package/dist/services/aiService.js.map +1 -0
- package/dist/services/conversationStorage.d.ts +38 -0
- package/dist/services/conversationStorage.d.ts.map +1 -0
- package/dist/services/conversationStorage.js +158 -0
- package/dist/services/conversationStorage.js.map +1 -0
- package/dist/services/crossPlatformBuffer.d.ts +84 -0
- package/dist/services/crossPlatformBuffer.d.ts.map +1 -0
- package/dist/services/crossPlatformBuffer.js +246 -0
- package/dist/services/crossPlatformBuffer.js.map +1 -0
- package/dist/services/index.d.ts +17 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/networkService.d.ts +81 -0
- package/dist/services/networkService.d.ts.map +1 -0
- package/dist/services/networkService.js +268 -0
- package/dist/services/networkService.js.map +1 -0
- package/dist/services/queueService.d.ts +112 -0
- package/dist/services/queueService.d.ts.map +1 -0
- package/dist/services/queueService.js +338 -0
- package/dist/services/queueService.js.map +1 -0
- package/dist/services/settingsService.d.ts +135 -0
- package/dist/services/settingsService.d.ts.map +1 -0
- package/dist/services/settingsService.js +425 -0
- package/dist/services/settingsService.js.map +1 -0
- package/dist/services/systemMonitor.d.ts +208 -0
- package/dist/services/systemMonitor.d.ts.map +1 -0
- package/dist/services/systemMonitor.js +693 -0
- package/dist/services/systemMonitor.js.map +1 -0
- package/dist/services/updateService.d.ts +78 -0
- package/dist/services/updateService.d.ts.map +1 -0
- package/dist/services/updateService.js +252 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/websocketEvents.d.ts +372 -0
- package/dist/services/websocketEvents.d.ts.map +1 -0
- package/dist/services/websocketEvents.js +338 -0
- package/dist/services/websocketEvents.js.map +1 -0
- package/dist/services/websocketServer.d.ts +80 -0
- package/dist/services/websocketServer.d.ts.map +1 -0
- package/dist/services/websocketServer.js +299 -0
- package/dist/services/websocketServer.js.map +1 -0
- package/dist/settings/SettingsSchema.d.ts +151 -0
- package/dist/settings/SettingsSchema.d.ts.map +1 -0
- package/dist/settings/SettingsSchema.js +424 -0
- package/dist/settings/SettingsSchema.js.map +1 -0
- package/dist/testing/TestServer.d.ts +69 -0
- package/dist/testing/TestServer.d.ts.map +1 -0
- package/dist/testing/TestServer.js +250 -0
- package/dist/testing/TestServer.js.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/appPaths.d.ts +74 -0
- package/dist/utils/appPaths.d.ts.map +1 -0
- package/dist/utils/appPaths.js +162 -0
- package/dist/utils/appPaths.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +50 -0
- package/dist/utils/fs-utils.d.ts.map +1 -0
- package/dist/utils/fs-utils.js +114 -0
- package/dist/utils/fs-utils.js.map +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/standardConfig.d.ts +61 -0
- package/dist/utils/standardConfig.d.ts.map +1 -0
- package/dist/utils/standardConfig.js +109 -0
- package/dist/utils/standardConfig.js.map +1 -0
- package/dist/utils/startupBanner.d.ts +34 -0
- package/dist/utils/startupBanner.d.ts.map +1 -0
- package/dist/utils/startupBanner.js +169 -0
- package/dist/utils/startupBanner.js.map +1 -0
- package/dist/utils/startupLogger.d.ts +45 -0
- package/dist/utils/startupLogger.d.ts.map +1 -0
- package/dist/utils/startupLogger.js +200 -0
- package/dist/utils/startupLogger.js.map +1 -0
- package/package.json +151 -0
- package/src/api/logsRouter.ts +600 -0
- package/src/cli/dev-server.ts +803 -0
- package/src/cli/index.ts +31 -0
- package/src/core/StandardServer.ts +587 -0
- package/src/core/apiResponse.ts +202 -0
- package/src/core/healthCheck.ts +565 -0
- package/src/core/index.ts +80 -0
- package/src/core/logger.ts +1092 -0
- package/src/core/portUtils.ts +319 -0
- package/src/core/storageService.ts +595 -0
- package/src/desktop/bundler.ts +271 -0
- package/src/desktop/index.ts +18 -0
- package/src/desktop/native-modules.ts +289 -0
- package/src/index.ts +142 -0
- package/src/logging/LogCategories.ts +302 -0
- package/src/middleware/aiErrorHandler.ts +278 -0
- package/src/middleware/auth.ts +329 -0
- package/src/middleware/cors.ts +187 -0
- package/src/middleware/errorHandler.ts +103 -0
- package/src/middleware/fileUpload.ts +252 -0
- package/src/middleware/health.ts +206 -0
- package/src/middleware/index.ts +71 -0
- package/src/middleware/openapi.ts +305 -0
- package/src/middleware/requestLogging.ts +92 -0
- package/src/middleware/session.ts +238 -0
- package/src/middleware/validation.ts +603 -0
- package/src/services/aiService.ts +789 -0
- package/src/services/conversationStorage.ts +232 -0
- package/src/services/crossPlatformBuffer.ts +341 -0
- package/src/services/index.ts +47 -0
- package/src/services/networkService.ts +351 -0
- package/src/services/queueService.ts +446 -0
- package/src/services/settingsService.ts +549 -0
- package/src/services/systemMonitor.ts +936 -0
- package/src/services/updateService.ts +334 -0
- package/src/services/websocketEvents.ts +409 -0
- package/src/services/websocketServer.ts +394 -0
- package/src/settings/SettingsSchema.ts +664 -0
- package/src/testing/TestServer.ts +312 -0
- package/src/types/index.ts +154 -0
- package/src/utils/appPaths.ts +196 -0
- package/src/utils/fs-utils.ts +130 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/standardConfig.ts +178 -0
- package/src/utils/startupBanner.ts +287 -0
- package/src/utils/startupLogger.ts +268 -0
- package/ui/dist/index.d.mts +1221 -0
- package/ui/dist/index.d.ts +1221 -0
- package/ui/dist/index.js +73 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/index.mjs +73 -0
- package/ui/dist/index.mjs.map +1 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check Service
|
|
3
|
+
* Provides real-time system health monitoring without intervention
|
|
4
|
+
* Data is informational only - no automatic service stops based on metrics
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import os from "os";
|
|
8
|
+
import { exec } from "child_process";
|
|
9
|
+
import { promisify } from "util";
|
|
10
|
+
import { Request, Response, Router } from "express";
|
|
11
|
+
|
|
12
|
+
const execAsync = promisify(exec);
|
|
13
|
+
|
|
14
|
+
export interface SystemHealth {
|
|
15
|
+
status: "healthy" | "degraded" | "unhealthy";
|
|
16
|
+
timestamp: string;
|
|
17
|
+
uptime: number;
|
|
18
|
+
environment: string;
|
|
19
|
+
version: string;
|
|
20
|
+
pid: number;
|
|
21
|
+
platform: string;
|
|
22
|
+
nodeVersion: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SystemMetrics {
|
|
26
|
+
cpu: {
|
|
27
|
+
usage: number;
|
|
28
|
+
count: number;
|
|
29
|
+
model: string;
|
|
30
|
+
speed: number;
|
|
31
|
+
loadAverage: number[];
|
|
32
|
+
};
|
|
33
|
+
memory: {
|
|
34
|
+
total: number;
|
|
35
|
+
used: number;
|
|
36
|
+
free: number;
|
|
37
|
+
percentage: number;
|
|
38
|
+
};
|
|
39
|
+
disk: {
|
|
40
|
+
total: number;
|
|
41
|
+
used: number;
|
|
42
|
+
free: number;
|
|
43
|
+
percentage: number;
|
|
44
|
+
path: string;
|
|
45
|
+
};
|
|
46
|
+
network: {
|
|
47
|
+
interfaces: NetworkInterface[];
|
|
48
|
+
};
|
|
49
|
+
process: {
|
|
50
|
+
pid: number;
|
|
51
|
+
memory: NodeJS.MemoryUsage;
|
|
52
|
+
cpuUsage: NodeJS.CpuUsage;
|
|
53
|
+
uptime: number;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface NetworkInterface {
|
|
58
|
+
name: string;
|
|
59
|
+
address: string;
|
|
60
|
+
family: string;
|
|
61
|
+
internal: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface HealthCheckOptions {
|
|
65
|
+
includeCpu?: boolean;
|
|
66
|
+
includeMemory?: boolean;
|
|
67
|
+
includeDisk?: boolean;
|
|
68
|
+
includeNetwork?: boolean;
|
|
69
|
+
includeProcess?: boolean;
|
|
70
|
+
diskPath?: string;
|
|
71
|
+
customChecks?: CustomHealthCheck[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface CustomHealthCheck {
|
|
75
|
+
name: string;
|
|
76
|
+
check: () => Promise<HealthCheckResult>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface HealthCheckResult {
|
|
80
|
+
name: string;
|
|
81
|
+
status: "healthy" | "degraded" | "unhealthy";
|
|
82
|
+
message?: string;
|
|
83
|
+
data?: any;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface DependencyHealth {
|
|
87
|
+
name: string;
|
|
88
|
+
status: "connected" | "disconnected" | "error";
|
|
89
|
+
responseTime?: number;
|
|
90
|
+
error?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class HealthCheckService {
|
|
94
|
+
private static instance: HealthCheckService;
|
|
95
|
+
private cpuUsageHistory: number[] = [];
|
|
96
|
+
private memoryUsageHistory: number[] = [];
|
|
97
|
+
private lastCpuInfo: any;
|
|
98
|
+
private metricsInterval?: NodeJS.Timeout;
|
|
99
|
+
private historySize: number = 60; // Keep last 60 data points
|
|
100
|
+
|
|
101
|
+
private constructor() {
|
|
102
|
+
this.startMetricsCollection();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static getInstance(): HealthCheckService {
|
|
106
|
+
if (!HealthCheckService.instance) {
|
|
107
|
+
HealthCheckService.instance = new HealthCheckService();
|
|
108
|
+
}
|
|
109
|
+
return HealthCheckService.instance;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get basic system health status
|
|
114
|
+
*/
|
|
115
|
+
async getHealth(appVersion?: string): Promise<SystemHealth> {
|
|
116
|
+
// Health status is 'healthy' by default - system metrics are informational only
|
|
117
|
+
// Actual health is determined by custom checks (database, websocket, etc.)
|
|
118
|
+
const status: SystemHealth["status"] = "healthy";
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
status,
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
uptime: process.uptime(),
|
|
124
|
+
environment: process.env.NODE_ENV || "development",
|
|
125
|
+
version: appVersion || process.env.npm_package_version || "unknown",
|
|
126
|
+
pid: process.pid,
|
|
127
|
+
platform: process.platform,
|
|
128
|
+
nodeVersion: process.version,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get detailed system metrics
|
|
134
|
+
*/
|
|
135
|
+
async getMetrics(options: HealthCheckOptions = {}): Promise<SystemMetrics> {
|
|
136
|
+
const {
|
|
137
|
+
includeCpu = true,
|
|
138
|
+
includeMemory = true,
|
|
139
|
+
includeDisk = true,
|
|
140
|
+
includeNetwork = true,
|
|
141
|
+
includeProcess = true,
|
|
142
|
+
diskPath = process.cwd(),
|
|
143
|
+
} = options;
|
|
144
|
+
|
|
145
|
+
const metrics: SystemMetrics = {} as SystemMetrics;
|
|
146
|
+
|
|
147
|
+
if (includeCpu) {
|
|
148
|
+
metrics.cpu = await this.getCpuMetrics();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (includeMemory) {
|
|
152
|
+
metrics.memory = this.getMemoryMetrics();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (includeDisk) {
|
|
156
|
+
metrics.disk = await this.getDiskMetrics(diskPath);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (includeNetwork) {
|
|
160
|
+
metrics.network = this.getNetworkMetrics();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (includeProcess) {
|
|
164
|
+
metrics.process = this.getProcessMetrics();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return metrics;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Get CPU metrics with real usage calculation
|
|
172
|
+
*/
|
|
173
|
+
private async getCpuMetrics(): Promise<SystemMetrics["cpu"]> {
|
|
174
|
+
const cpus = os.cpus();
|
|
175
|
+
const cpuModel = cpus[0]?.model || "Unknown";
|
|
176
|
+
const cpuSpeed = cpus[0]?.speed || 0;
|
|
177
|
+
const cpuCount = cpus.length;
|
|
178
|
+
const loadAverage = os.loadavg();
|
|
179
|
+
|
|
180
|
+
// Calculate CPU usage percentage
|
|
181
|
+
const cpuUsage = await this.calculateCpuUsage();
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
usage: cpuUsage,
|
|
185
|
+
count: cpuCount,
|
|
186
|
+
model: cpuModel,
|
|
187
|
+
speed: cpuSpeed,
|
|
188
|
+
loadAverage,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Calculate real CPU usage percentage
|
|
194
|
+
*/
|
|
195
|
+
private async calculateCpuUsage(): Promise<number> {
|
|
196
|
+
const cpus = os.cpus();
|
|
197
|
+
|
|
198
|
+
// Calculate total and idle times
|
|
199
|
+
let totalIdle = 0;
|
|
200
|
+
let totalTick = 0;
|
|
201
|
+
|
|
202
|
+
cpus.forEach((cpu) => {
|
|
203
|
+
for (const type in cpu.times) {
|
|
204
|
+
totalTick += cpu.times[type as keyof typeof cpu.times];
|
|
205
|
+
}
|
|
206
|
+
totalIdle += cpu.times.idle;
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const idle = totalIdle / cpus.length;
|
|
210
|
+
const total = totalTick / cpus.length;
|
|
211
|
+
|
|
212
|
+
// If we have previous measurements, calculate the difference
|
|
213
|
+
if (this.lastCpuInfo) {
|
|
214
|
+
const idleDiff = idle - this.lastCpuInfo.idle;
|
|
215
|
+
const totalDiff = total - this.lastCpuInfo.total;
|
|
216
|
+
const usage = 100 - (100 * idleDiff) / totalDiff;
|
|
217
|
+
|
|
218
|
+
this.lastCpuInfo = { idle, total };
|
|
219
|
+
return Math.min(100, Math.max(0, usage));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// First measurement - store for next time
|
|
223
|
+
this.lastCpuInfo = { idle, total };
|
|
224
|
+
|
|
225
|
+
// Fallback: use load average as approximation
|
|
226
|
+
const loadAvg = os.loadavg()[0]; // 1-minute load average
|
|
227
|
+
const approximateUsage = (loadAvg / cpus.length) * 100;
|
|
228
|
+
return Math.min(100, Math.max(0, approximateUsage));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get memory metrics
|
|
233
|
+
*/
|
|
234
|
+
private getMemoryMetrics(): SystemMetrics["memory"] {
|
|
235
|
+
const totalMemory = os.totalmem();
|
|
236
|
+
const freeMemory = os.freemem();
|
|
237
|
+
const usedMemory = totalMemory - freeMemory;
|
|
238
|
+
const memoryPercentage = (usedMemory / totalMemory) * 100;
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
total: totalMemory,
|
|
242
|
+
used: usedMemory,
|
|
243
|
+
free: freeMemory,
|
|
244
|
+
percentage: parseFloat(memoryPercentage.toFixed(2)),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get disk metrics for specified path
|
|
250
|
+
*/
|
|
251
|
+
private async getDiskMetrics(
|
|
252
|
+
diskPath: string,
|
|
253
|
+
): Promise<SystemMetrics["disk"]> {
|
|
254
|
+
try {
|
|
255
|
+
// Platform-specific disk usage check
|
|
256
|
+
if (process.platform === "win32") {
|
|
257
|
+
// Windows: use wmic command
|
|
258
|
+
const { stdout } = await execAsync(
|
|
259
|
+
"wmic logicaldisk get size,freespace,caption",
|
|
260
|
+
);
|
|
261
|
+
const lines = stdout.split("\n").filter((line) => line.trim());
|
|
262
|
+
|
|
263
|
+
// Parse the output (this is simplified - may need adjustment)
|
|
264
|
+
const total = parseInt(lines[1]?.split(/\s+/)[2] || "0");
|
|
265
|
+
const free = parseInt(lines[1]?.split(/\s+/)[1] || "0");
|
|
266
|
+
const used = total - free;
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
total,
|
|
270
|
+
used,
|
|
271
|
+
free,
|
|
272
|
+
percentage:
|
|
273
|
+
total > 0 ? parseFloat(((used / total) * 100).toFixed(2)) : 0,
|
|
274
|
+
path: diskPath,
|
|
275
|
+
};
|
|
276
|
+
} else {
|
|
277
|
+
// Unix-like systems: use df command
|
|
278
|
+
const { stdout } = await execAsync(`df -k "${diskPath}" | tail -1`);
|
|
279
|
+
const parts = stdout.trim().split(/\s+/);
|
|
280
|
+
|
|
281
|
+
// df output: filesystem 1K-blocks used available use% mounted
|
|
282
|
+
const total = parseInt(parts[1] || "0") * 1024;
|
|
283
|
+
const used = parseInt(parts[2] || "0") * 1024;
|
|
284
|
+
const available = parseInt(parts[3] || "0") * 1024;
|
|
285
|
+
const percentage = parseInt(parts[4]?.replace("%", "") || "0");
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
total,
|
|
289
|
+
used,
|
|
290
|
+
free: available,
|
|
291
|
+
percentage,
|
|
292
|
+
path: diskPath,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
} catch (_error) {
|
|
296
|
+
console.error("Failed to get disk metrics:", _error);
|
|
297
|
+
// Return zeros if we can't get disk stats
|
|
298
|
+
return {
|
|
299
|
+
total: 0,
|
|
300
|
+
used: 0,
|
|
301
|
+
free: 0,
|
|
302
|
+
percentage: 0,
|
|
303
|
+
path: diskPath,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get network interface information
|
|
310
|
+
*/
|
|
311
|
+
private getNetworkMetrics(): SystemMetrics["network"] {
|
|
312
|
+
const networkInterfaces = os.networkInterfaces();
|
|
313
|
+
const interfaces: NetworkInterface[] = [];
|
|
314
|
+
|
|
315
|
+
for (const [name, nets] of Object.entries(networkInterfaces)) {
|
|
316
|
+
if (nets) {
|
|
317
|
+
for (const net of nets) {
|
|
318
|
+
interfaces.push({
|
|
319
|
+
name,
|
|
320
|
+
address: net.address,
|
|
321
|
+
family: net.family,
|
|
322
|
+
internal: net.internal,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return { interfaces };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get current process metrics
|
|
333
|
+
*/
|
|
334
|
+
private getProcessMetrics(): SystemMetrics["process"] {
|
|
335
|
+
return {
|
|
336
|
+
pid: process.pid,
|
|
337
|
+
memory: process.memoryUsage(),
|
|
338
|
+
cpuUsage: process.cpuUsage(),
|
|
339
|
+
uptime: process.uptime(),
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Check dependency health (database, Redis, external APIs, etc.)
|
|
345
|
+
*/
|
|
346
|
+
async checkDependencies(
|
|
347
|
+
dependencies: {
|
|
348
|
+
name: string;
|
|
349
|
+
check: () => Promise<boolean>;
|
|
350
|
+
}[],
|
|
351
|
+
): Promise<DependencyHealth[]> {
|
|
352
|
+
const results: DependencyHealth[] = [];
|
|
353
|
+
|
|
354
|
+
for (const dep of dependencies) {
|
|
355
|
+
const startTime = Date.now();
|
|
356
|
+
try {
|
|
357
|
+
const isHealthy = await dep.check();
|
|
358
|
+
results.push({
|
|
359
|
+
name: dep.name,
|
|
360
|
+
status: isHealthy ? "connected" : "disconnected",
|
|
361
|
+
responseTime: Date.now() - startTime,
|
|
362
|
+
});
|
|
363
|
+
} catch (_error) {
|
|
364
|
+
results.push({
|
|
365
|
+
name: dep.name,
|
|
366
|
+
status: "error",
|
|
367
|
+
responseTime: Date.now() - startTime,
|
|
368
|
+
error: _error instanceof Error ? _error.message : "Unknown error",
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return results;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Run custom health checks
|
|
378
|
+
*/
|
|
379
|
+
async runCustomChecks(
|
|
380
|
+
checks: CustomHealthCheck[],
|
|
381
|
+
): Promise<HealthCheckResult[]> {
|
|
382
|
+
const results: HealthCheckResult[] = [];
|
|
383
|
+
|
|
384
|
+
for (const check of checks) {
|
|
385
|
+
try {
|
|
386
|
+
const result = await check.check();
|
|
387
|
+
results.push(result);
|
|
388
|
+
} catch (_error) {
|
|
389
|
+
results.push({
|
|
390
|
+
name: check.name,
|
|
391
|
+
status: "unhealthy",
|
|
392
|
+
message: _error instanceof Error ? _error.message : "Check failed",
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return results;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Get metrics history for graphs
|
|
402
|
+
*/
|
|
403
|
+
getMetricsHistory(): {
|
|
404
|
+
cpu: number[];
|
|
405
|
+
memory: number[];
|
|
406
|
+
} {
|
|
407
|
+
return {
|
|
408
|
+
cpu: [...this.cpuUsageHistory],
|
|
409
|
+
memory: [...this.memoryUsageHistory],
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Start collecting metrics periodically for history
|
|
415
|
+
*/
|
|
416
|
+
private startMetricsCollection(): void {
|
|
417
|
+
// Collect metrics every 5 seconds
|
|
418
|
+
this.metricsInterval = setInterval(async () => {
|
|
419
|
+
try {
|
|
420
|
+
const metrics = await this.getMetrics();
|
|
421
|
+
|
|
422
|
+
// Add to history
|
|
423
|
+
this.cpuUsageHistory.push(metrics.cpu.usage);
|
|
424
|
+
this.memoryUsageHistory.push(metrics.memory.percentage);
|
|
425
|
+
|
|
426
|
+
// Keep only last N data points
|
|
427
|
+
if (this.cpuUsageHistory.length > this.historySize) {
|
|
428
|
+
this.cpuUsageHistory.shift();
|
|
429
|
+
}
|
|
430
|
+
if (this.memoryUsageHistory.length > this.historySize) {
|
|
431
|
+
this.memoryUsageHistory.shift();
|
|
432
|
+
}
|
|
433
|
+
} catch (_error) {
|
|
434
|
+
console.error("Failed to collect metrics:", _error);
|
|
435
|
+
}
|
|
436
|
+
}, 5000);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Stop metrics collection (for cleanup)
|
|
441
|
+
*/
|
|
442
|
+
stopMetricsCollection(): void {
|
|
443
|
+
if (this.metricsInterval) {
|
|
444
|
+
clearInterval(this.metricsInterval);
|
|
445
|
+
this.metricsInterval = undefined;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Create health check router for Express apps
|
|
452
|
+
*/
|
|
453
|
+
export function createHealthCheckRouter(options?: {
|
|
454
|
+
version?: string;
|
|
455
|
+
customChecks?: CustomHealthCheck[];
|
|
456
|
+
dependencies?: Array<{ name: string; check: () => Promise<boolean> }>;
|
|
457
|
+
}): Router {
|
|
458
|
+
const router = Router();
|
|
459
|
+
const healthService = HealthCheckService.getInstance();
|
|
460
|
+
|
|
461
|
+
// Basic health endpoint
|
|
462
|
+
router.get("/health", async (_req: Request, res: Response) => {
|
|
463
|
+
try {
|
|
464
|
+
const health = await healthService.getHealth(options?.version);
|
|
465
|
+
|
|
466
|
+
// Run custom checks if provided
|
|
467
|
+
if (options?.customChecks && options.customChecks.length > 0) {
|
|
468
|
+
const customResults = await Promise.all(
|
|
469
|
+
options.customChecks.map((check) => check.check()),
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
// Add custom check results to health object
|
|
473
|
+
(health as any).checks = customResults;
|
|
474
|
+
|
|
475
|
+
// Update overall status based ONLY on custom checks
|
|
476
|
+
const hasUnhealthy = customResults.some(
|
|
477
|
+
(r) => r.status === "unhealthy",
|
|
478
|
+
);
|
|
479
|
+
const hasDegraded = customResults.some((r) => r.status === "degraded");
|
|
480
|
+
|
|
481
|
+
if (hasUnhealthy) {
|
|
482
|
+
health.status = "unhealthy";
|
|
483
|
+
} else if (hasDegraded) {
|
|
484
|
+
health.status = "degraded";
|
|
485
|
+
}
|
|
486
|
+
// Otherwise keep default 'healthy' status
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const statusCode =
|
|
490
|
+
health.status === "healthy"
|
|
491
|
+
? 200
|
|
492
|
+
: health.status === "degraded"
|
|
493
|
+
? 200
|
|
494
|
+
: 503;
|
|
495
|
+
res.status(statusCode).json(health);
|
|
496
|
+
} catch (_error) {
|
|
497
|
+
res.status(503).json({
|
|
498
|
+
status: "unhealthy",
|
|
499
|
+
error: "Failed to get health status",
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// Detailed metrics endpoint
|
|
505
|
+
router.get("/metrics", async (_req: Request, res: Response) => {
|
|
506
|
+
try {
|
|
507
|
+
const metrics = await healthService.getMetrics();
|
|
508
|
+
res.json(metrics);
|
|
509
|
+
} catch (_error) {
|
|
510
|
+
res.status(500).json({
|
|
511
|
+
error: "Failed to get metrics",
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Metrics history for graphs
|
|
517
|
+
router.get("/metrics/history", (_req: Request, res: Response) => {
|
|
518
|
+
const history = healthService.getMetricsHistory();
|
|
519
|
+
res.json(history);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// Dependency health checks
|
|
523
|
+
if (options?.dependencies) {
|
|
524
|
+
router.get("/health/dependencies", async (_req: Request, res: Response) => {
|
|
525
|
+
try {
|
|
526
|
+
const results = await healthService.checkDependencies(
|
|
527
|
+
options.dependencies!,
|
|
528
|
+
);
|
|
529
|
+
const allHealthy = results.every((r) => r.status === "connected");
|
|
530
|
+
res.status(allHealthy ? 200 : 503).json(results);
|
|
531
|
+
} catch (_error) {
|
|
532
|
+
res.status(500).json({
|
|
533
|
+
error: "Failed to check dependencies",
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Custom health checks
|
|
540
|
+
if (options?.customChecks) {
|
|
541
|
+
router.get("/health/custom", async (_req: Request, res: Response) => {
|
|
542
|
+
try {
|
|
543
|
+
const results = await healthService.runCustomChecks(
|
|
544
|
+
options.customChecks!,
|
|
545
|
+
);
|
|
546
|
+
const allHealthy = results.every((r) => r.status === "healthy");
|
|
547
|
+
res.status(allHealthy ? 200 : 503).json(results);
|
|
548
|
+
} catch (_error) {
|
|
549
|
+
res.status(500).json({
|
|
550
|
+
error: "Failed to run custom checks",
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return router;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Export singleton instance getter
|
|
560
|
+
export function getHealthCheckService(): HealthCheckService {
|
|
561
|
+
return HealthCheckService.getInstance();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Export types
|
|
565
|
+
export type { HealthCheckService };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Framework Components
|
|
3
|
+
*
|
|
4
|
+
* These are generic, reusable components that could be extracted
|
|
5
|
+
* into a separate npm package for use in other applications.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Framework version
|
|
9
|
+
export const FRAMEWORK_VERSION = "4.4.0";
|
|
10
|
+
|
|
11
|
+
// Process Management
|
|
12
|
+
export { StandardServer, createStandardServer } from "./StandardServer.js";
|
|
13
|
+
export type { StandardServerConfig } from "./StandardServer.js";
|
|
14
|
+
export {
|
|
15
|
+
clearPort,
|
|
16
|
+
isPortAvailable,
|
|
17
|
+
getPortInfo,
|
|
18
|
+
getProcessOnPort,
|
|
19
|
+
findAvailablePort,
|
|
20
|
+
checkRequiredPorts,
|
|
21
|
+
formatPortStatus,
|
|
22
|
+
waitForPort,
|
|
23
|
+
getPortsInUse,
|
|
24
|
+
type ProcessInfo,
|
|
25
|
+
type PortStatus,
|
|
26
|
+
type PortClearResult,
|
|
27
|
+
type PortStatusResult,
|
|
28
|
+
} from "./portUtils.js";
|
|
29
|
+
|
|
30
|
+
// Logging - Consolidated logger implementation
|
|
31
|
+
export {
|
|
32
|
+
getLogger,
|
|
33
|
+
default as Logger,
|
|
34
|
+
createLogger as createLoggerBase,
|
|
35
|
+
} from "./logger.js";
|
|
36
|
+
|
|
37
|
+
import { createLogger as createLoggerImport } from "./logger.js";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create a logger instance with automatic file output
|
|
41
|
+
* @param name - The name/category for this logger
|
|
42
|
+
* @returns A logger instance that writes to console and files
|
|
43
|
+
*/
|
|
44
|
+
export function createLogger(name: string) {
|
|
45
|
+
// Use the createLogger function from logger
|
|
46
|
+
return createLoggerImport(name);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Export types for backward compatibility
|
|
50
|
+
export interface Logger {
|
|
51
|
+
info: (...args: any[]) => void;
|
|
52
|
+
error: (...args: any[]) => void;
|
|
53
|
+
warn: (...args: any[]) => void;
|
|
54
|
+
debug: (...args: any[]) => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
58
|
+
|
|
59
|
+
// Security
|
|
60
|
+
export {
|
|
61
|
+
getStorageService,
|
|
62
|
+
StorageService,
|
|
63
|
+
getSecureFileHandler,
|
|
64
|
+
SecureFileHandler,
|
|
65
|
+
} from "./storageService.js";
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Usage Example:
|
|
69
|
+
*
|
|
70
|
+
* import { StandardServer, createLogger } from '@/core';
|
|
71
|
+
*
|
|
72
|
+
* const logger = createLogger('MyApp');
|
|
73
|
+
* const server = new StandardServer({
|
|
74
|
+
* appName: 'MyApp',
|
|
75
|
+
* appVersion: '1.0.0',
|
|
76
|
+
* port: 8080
|
|
77
|
+
* });
|
|
78
|
+
* await server.initialize();
|
|
79
|
+
* await server.start();
|
|
80
|
+
*/
|