@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,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Upload Middleware
|
|
3
|
+
* Simple file upload handling for Express
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Request, Response, NextFunction } from "express";
|
|
7
|
+
import multer from "multer";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { getStorageService } from "../core/storageService.js";
|
|
10
|
+
import { createLogger } from "../core/index.js";
|
|
11
|
+
|
|
12
|
+
let logger: any; // Will be initialized when needed
|
|
13
|
+
|
|
14
|
+
function ensureLogger() {
|
|
15
|
+
if (!logger) {
|
|
16
|
+
logger = createLogger("FileUpload");
|
|
17
|
+
}
|
|
18
|
+
return logger;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface FileUploadConfig {
|
|
22
|
+
destination?: string;
|
|
23
|
+
maxSize?: number;
|
|
24
|
+
allowedTypes?: string[];
|
|
25
|
+
fieldName?: string;
|
|
26
|
+
multiple?: boolean;
|
|
27
|
+
maxCount?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Create file upload middleware
|
|
32
|
+
*/
|
|
33
|
+
export function createFileUpload(config: FileUploadConfig = {}) {
|
|
34
|
+
const {
|
|
35
|
+
destination = "uploads",
|
|
36
|
+
maxSize = 10 * 1024 * 1024, // 10MB default
|
|
37
|
+
allowedTypes = [],
|
|
38
|
+
fieldName = "file",
|
|
39
|
+
multiple = false,
|
|
40
|
+
maxCount = 10,
|
|
41
|
+
} = config;
|
|
42
|
+
|
|
43
|
+
// Configure multer storage
|
|
44
|
+
const storage = multer.memoryStorage();
|
|
45
|
+
|
|
46
|
+
// Configure multer
|
|
47
|
+
const upload = multer({
|
|
48
|
+
storage,
|
|
49
|
+
limits: {
|
|
50
|
+
fileSize: maxSize,
|
|
51
|
+
files: maxCount,
|
|
52
|
+
},
|
|
53
|
+
fileFilter: (_req, file, cb) => {
|
|
54
|
+
// Check file type if restrictions are set
|
|
55
|
+
if (allowedTypes.length > 0) {
|
|
56
|
+
const ext = path.extname(file.originalname).toLowerCase();
|
|
57
|
+
if (!allowedTypes.includes(ext)) {
|
|
58
|
+
return cb(new Error(`File type ${ext} not allowed`));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
cb(null, true);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Return appropriate middleware
|
|
66
|
+
const multerMiddleware = multiple
|
|
67
|
+
? upload.array(fieldName, maxCount)
|
|
68
|
+
: upload.single(fieldName);
|
|
69
|
+
|
|
70
|
+
return async (
|
|
71
|
+
req: Request,
|
|
72
|
+
res: Response,
|
|
73
|
+
next: NextFunction,
|
|
74
|
+
): Promise<void> => {
|
|
75
|
+
multerMiddleware(req, res, async (err) => {
|
|
76
|
+
if (err) {
|
|
77
|
+
ensureLogger().error("Upload error:", err);
|
|
78
|
+
|
|
79
|
+
if (err instanceof multer.MulterError) {
|
|
80
|
+
if (err.code === "LIMIT_FILE_SIZE") {
|
|
81
|
+
res.status(400).json({
|
|
82
|
+
success: false,
|
|
83
|
+
error: "File too large",
|
|
84
|
+
message: `File size exceeds maximum of ${maxSize} bytes`,
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (err.code === "LIMIT_FILE_COUNT") {
|
|
89
|
+
res.status(400).json({
|
|
90
|
+
success: false,
|
|
91
|
+
error: "Too many files",
|
|
92
|
+
message: `Maximum ${maxCount} files allowed`,
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
res.status(400).json({
|
|
99
|
+
success: false,
|
|
100
|
+
error: "Upload failed",
|
|
101
|
+
message: err.message,
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Process uploaded files via StorageService to keep a single path for uploads
|
|
107
|
+
try {
|
|
108
|
+
const storage = getStorageService();
|
|
109
|
+
|
|
110
|
+
if (multiple && req.files && Array.isArray(req.files)) {
|
|
111
|
+
// Multiple files
|
|
112
|
+
const uploadedFiles = [];
|
|
113
|
+
|
|
114
|
+
for (const file of req.files) {
|
|
115
|
+
const uploaded = await storage.saveUserUpload(
|
|
116
|
+
file.buffer,
|
|
117
|
+
file.originalname,
|
|
118
|
+
{
|
|
119
|
+
allowedTypes,
|
|
120
|
+
maxSize,
|
|
121
|
+
destination,
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
uploadedFiles.push({
|
|
125
|
+
...uploaded,
|
|
126
|
+
mimetype: file.mimetype,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
req.uploadedFiles = uploadedFiles;
|
|
131
|
+
ensureLogger().info(`Uploaded ${uploadedFiles.length} files`);
|
|
132
|
+
} else if (req.file) {
|
|
133
|
+
// Single file
|
|
134
|
+
const uploaded = await storage.saveUserUpload(
|
|
135
|
+
req.file.buffer,
|
|
136
|
+
req.file.originalname,
|
|
137
|
+
{
|
|
138
|
+
allowedTypes,
|
|
139
|
+
maxSize,
|
|
140
|
+
destination,
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
req.uploadedFile = {
|
|
145
|
+
...uploaded,
|
|
146
|
+
mimetype: req.file.mimetype,
|
|
147
|
+
};
|
|
148
|
+
ensureLogger().info(`Uploaded file: ${uploaded.filename}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
next();
|
|
152
|
+
} catch (_error: any) {
|
|
153
|
+
ensureLogger().error("File processing error:", _error);
|
|
154
|
+
res.status(500).json({
|
|
155
|
+
success: false,
|
|
156
|
+
error: "File processing failed",
|
|
157
|
+
message: _error.message,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Parse form data middleware (for mixed file/data uploads)
|
|
166
|
+
*/
|
|
167
|
+
export function parseFormData(fields: string[] = []) {
|
|
168
|
+
const upload = multer();
|
|
169
|
+
return upload.fields(fields.map((field) => ({ name: field })));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Download file helper
|
|
174
|
+
*/
|
|
175
|
+
export function sendFile(filePath: string, filename?: string) {
|
|
176
|
+
return (_req: Request, res: Response) => {
|
|
177
|
+
const resolvedPath = path.resolve(filePath);
|
|
178
|
+
const downloadName = filename || path.basename(filePath);
|
|
179
|
+
|
|
180
|
+
res.download(resolvedPath, downloadName, (err) => {
|
|
181
|
+
if (err) {
|
|
182
|
+
ensureLogger().error("Download error:", err);
|
|
183
|
+
if (!res.headersSent) {
|
|
184
|
+
res.status(404).json({
|
|
185
|
+
success: false,
|
|
186
|
+
error: "File not found",
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Express middleware to clean old temp files periodically
|
|
196
|
+
*/
|
|
197
|
+
export function createTempCleaner(
|
|
198
|
+
tempDir: string = "./temp",
|
|
199
|
+
maxAge: number = 24 * 60 * 60 * 1000, // 24 hours
|
|
200
|
+
interval: number = 60 * 60 * 1000, // 1 hour
|
|
201
|
+
) {
|
|
202
|
+
const storage = getStorageService();
|
|
203
|
+
|
|
204
|
+
// Start periodic cleaning
|
|
205
|
+
setInterval(async () => {
|
|
206
|
+
try {
|
|
207
|
+
const deleted = await storage.cleanTempFiles(maxAge, tempDir);
|
|
208
|
+
if (deleted > 0) {
|
|
209
|
+
ensureLogger().info(`Cleaned ${deleted} old temporary files`);
|
|
210
|
+
}
|
|
211
|
+
} catch (_error: any) {
|
|
212
|
+
ensureLogger().error("Temp file cleanup error:", _error);
|
|
213
|
+
}
|
|
214
|
+
}, interval);
|
|
215
|
+
|
|
216
|
+
// Return middleware that does nothing (just starts the cleaner)
|
|
217
|
+
return (_req: Request, _res: Response, next: NextFunction) => next();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Extend Express Request type
|
|
221
|
+
declare global {
|
|
222
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
223
|
+
namespace Express {
|
|
224
|
+
interface Request {
|
|
225
|
+
uploadedFile?: {
|
|
226
|
+
originalName: string;
|
|
227
|
+
filename: string;
|
|
228
|
+
path: string;
|
|
229
|
+
size: number;
|
|
230
|
+
mimetype?: string;
|
|
231
|
+
extension: string;
|
|
232
|
+
hash?: string;
|
|
233
|
+
};
|
|
234
|
+
uploadedFiles?: Array<{
|
|
235
|
+
originalName: string;
|
|
236
|
+
filename: string;
|
|
237
|
+
path: string;
|
|
238
|
+
size: number;
|
|
239
|
+
mimetype?: string;
|
|
240
|
+
extension: string;
|
|
241
|
+
hash?: string;
|
|
242
|
+
}>;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export default {
|
|
248
|
+
createFileUpload,
|
|
249
|
+
parseFormData,
|
|
250
|
+
sendFile,
|
|
251
|
+
createTempCleaner,
|
|
252
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized Health Check Middleware
|
|
3
|
+
* Provides consistent health monitoring across all applications
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Request, Response, Router } from "express";
|
|
7
|
+
import os from "os";
|
|
8
|
+
|
|
9
|
+
export interface HealthCheckOptions {
|
|
10
|
+
includeDetails?: boolean;
|
|
11
|
+
checkComponents?: () => Promise<ComponentHealth>;
|
|
12
|
+
version?: string;
|
|
13
|
+
serviceName?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ComponentHealth {
|
|
17
|
+
[key: string]: {
|
|
18
|
+
status: "healthy" | "degraded" | "unhealthy";
|
|
19
|
+
message?: string;
|
|
20
|
+
latency?: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface HealthResponse {
|
|
25
|
+
status: "healthy" | "degraded" | "unhealthy";
|
|
26
|
+
timestamp: string;
|
|
27
|
+
version: string;
|
|
28
|
+
uptime: number;
|
|
29
|
+
service?: string;
|
|
30
|
+
components?: ComponentHealth;
|
|
31
|
+
resources?: {
|
|
32
|
+
memory: {
|
|
33
|
+
used: number;
|
|
34
|
+
total: number;
|
|
35
|
+
percentage: number;
|
|
36
|
+
};
|
|
37
|
+
cpu: {
|
|
38
|
+
usage: number;
|
|
39
|
+
cores: number;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get system resource usage
|
|
46
|
+
*/
|
|
47
|
+
function getSystemResources() {
|
|
48
|
+
const totalMem = os.totalmem();
|
|
49
|
+
const freeMem = os.freemem();
|
|
50
|
+
const usedMem = totalMem - freeMem;
|
|
51
|
+
|
|
52
|
+
// Simplified CPU usage calculation
|
|
53
|
+
const cpus = os.cpus();
|
|
54
|
+
let totalIdle = 0;
|
|
55
|
+
let totalTick = 0;
|
|
56
|
+
|
|
57
|
+
cpus.forEach((cpu) => {
|
|
58
|
+
for (const type in cpu.times) {
|
|
59
|
+
totalTick += cpu.times[type as keyof typeof cpu.times];
|
|
60
|
+
}
|
|
61
|
+
totalIdle += cpu.times.idle;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const idle = totalIdle / cpus.length;
|
|
65
|
+
const total = totalTick / cpus.length;
|
|
66
|
+
const usage = Math.round(100 - (100 * idle) / total);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
memory: {
|
|
70
|
+
used: usedMem,
|
|
71
|
+
total: totalMem,
|
|
72
|
+
percentage: Math.round((usedMem / totalMem) * 100),
|
|
73
|
+
},
|
|
74
|
+
cpu: {
|
|
75
|
+
usage,
|
|
76
|
+
cores: cpus.length,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Determine overall health status based on components
|
|
83
|
+
*/
|
|
84
|
+
function determineOverallHealth(
|
|
85
|
+
components?: ComponentHealth,
|
|
86
|
+
): "healthy" | "degraded" | "unhealthy" {
|
|
87
|
+
if (!components) return "healthy";
|
|
88
|
+
|
|
89
|
+
const statuses = Object.values(components).map((c) => c.status);
|
|
90
|
+
|
|
91
|
+
if (statuses.some((s) => s === "unhealthy")) {
|
|
92
|
+
return "unhealthy";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (statuses.some((s) => s === "degraded")) {
|
|
96
|
+
return "degraded";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return "healthy";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create standardized health check endpoint
|
|
104
|
+
* @param {HealthCheckOptions} options - Health check configuration
|
|
105
|
+
* @returns {Router} Express router with health endpoint
|
|
106
|
+
*/
|
|
107
|
+
export function createHealthCheck(options: HealthCheckOptions = {}): Router {
|
|
108
|
+
const router = Router();
|
|
109
|
+
const {
|
|
110
|
+
includeDetails = true,
|
|
111
|
+
checkComponents,
|
|
112
|
+
version = process.env.npm_package_version || "1.0.0",
|
|
113
|
+
serviceName,
|
|
114
|
+
} = options;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* GET /health
|
|
118
|
+
* Standard health check endpoint
|
|
119
|
+
*/
|
|
120
|
+
router.get("/health", async (_req: Request, res: Response) => {
|
|
121
|
+
try {
|
|
122
|
+
// Check component health if provided
|
|
123
|
+
const components = checkComponents ? await checkComponents() : undefined;
|
|
124
|
+
|
|
125
|
+
// Build health response
|
|
126
|
+
const health: HealthResponse = {
|
|
127
|
+
status: determineOverallHealth(components),
|
|
128
|
+
timestamp: new Date().toISOString(),
|
|
129
|
+
version,
|
|
130
|
+
uptime: process.uptime(),
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
if (serviceName) {
|
|
134
|
+
health.service = serviceName;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (includeDetails) {
|
|
138
|
+
health.resources = getSystemResources();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (components) {
|
|
142
|
+
health.components = components;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Set appropriate status code
|
|
146
|
+
const statusCode =
|
|
147
|
+
health.status === "healthy"
|
|
148
|
+
? 200
|
|
149
|
+
: health.status === "degraded"
|
|
150
|
+
? 200
|
|
151
|
+
: 503;
|
|
152
|
+
|
|
153
|
+
res.status(statusCode).json(health);
|
|
154
|
+
} catch (_error: any) {
|
|
155
|
+
res.status(503).json({
|
|
156
|
+
status: "unhealthy",
|
|
157
|
+
timestamp: new Date().toISOString(),
|
|
158
|
+
version,
|
|
159
|
+
error: _error.message,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* GET /health/ready
|
|
166
|
+
* Readiness check (for k8s)
|
|
167
|
+
*/
|
|
168
|
+
router.get("/health/ready", async (_req: Request, res: Response) => {
|
|
169
|
+
try {
|
|
170
|
+
const components = checkComponents ? await checkComponents() : undefined;
|
|
171
|
+
const status = determineOverallHealth(components);
|
|
172
|
+
|
|
173
|
+
if (status === "healthy") {
|
|
174
|
+
res.status(200).json({ ready: true });
|
|
175
|
+
} else {
|
|
176
|
+
res.status(503).json({ ready: false, status });
|
|
177
|
+
}
|
|
178
|
+
} catch (_error) {
|
|
179
|
+
res.status(503).json({ ready: false });
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* GET /health/live
|
|
185
|
+
* Liveness check (for k8s)
|
|
186
|
+
*/
|
|
187
|
+
router.get("/health/live", (_req: Request, res: Response) => {
|
|
188
|
+
res.status(200).json({ alive: true });
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
return router;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Simple health check middleware for basic use
|
|
196
|
+
*/
|
|
197
|
+
export function healthCheck(_req: Request, res: Response) {
|
|
198
|
+
const health: HealthResponse = {
|
|
199
|
+
status: "healthy",
|
|
200
|
+
timestamp: new Date().toISOString(),
|
|
201
|
+
version: process.env.npm_package_version || "1.0.0",
|
|
202
|
+
uptime: process.uptime(),
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
res.json(health);
|
|
206
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware Module Exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
schemas,
|
|
7
|
+
validate,
|
|
8
|
+
validateParams,
|
|
9
|
+
validateQuery,
|
|
10
|
+
validateAsync,
|
|
11
|
+
validateRequest,
|
|
12
|
+
validateIf,
|
|
13
|
+
compose,
|
|
14
|
+
z,
|
|
15
|
+
zod,
|
|
16
|
+
} from "./validation.js";
|
|
17
|
+
|
|
18
|
+
export { aiErrorHandler } from "./aiErrorHandler.js";
|
|
19
|
+
export {
|
|
20
|
+
errorHandler,
|
|
21
|
+
notFoundHandler,
|
|
22
|
+
asyncHandler,
|
|
23
|
+
AppError,
|
|
24
|
+
} from "./errorHandler.js";
|
|
25
|
+
export {
|
|
26
|
+
createFileUpload,
|
|
27
|
+
parseFormData,
|
|
28
|
+
sendFile,
|
|
29
|
+
createTempCleaner,
|
|
30
|
+
} from "./fileUpload.js";
|
|
31
|
+
export type { FileUploadConfig } from "./fileUpload.js";
|
|
32
|
+
export { createHealthCheck, healthCheck } from "./health.js";
|
|
33
|
+
export type {
|
|
34
|
+
HealthCheckOptions,
|
|
35
|
+
ComponentHealth,
|
|
36
|
+
HealthResponse,
|
|
37
|
+
} from "./health.js";
|
|
38
|
+
export {
|
|
39
|
+
setupOpenAPIDocumentation,
|
|
40
|
+
generateOpenAPISpec,
|
|
41
|
+
ApiOperation,
|
|
42
|
+
} from "./openapi.js";
|
|
43
|
+
export type { OpenAPIConfig } from "./openapi.js";
|
|
44
|
+
|
|
45
|
+
// Auth middleware exports
|
|
46
|
+
export {
|
|
47
|
+
createAuthMiddleware,
|
|
48
|
+
createLoginHandler,
|
|
49
|
+
createLogoutHandler,
|
|
50
|
+
createAuthCheckHandler,
|
|
51
|
+
SimpleAuthService,
|
|
52
|
+
} from "./auth.js";
|
|
53
|
+
export type { AuthConfig } from "./auth.js";
|
|
54
|
+
|
|
55
|
+
// Session middleware exports
|
|
56
|
+
export { configureSession } from "./session.js";
|
|
57
|
+
export type { SessionConfig as SessionMiddlewareConfig } from "./session.js";
|
|
58
|
+
|
|
59
|
+
// CORS middleware exports
|
|
60
|
+
export {
|
|
61
|
+
createDynamicCors,
|
|
62
|
+
createProductionCors,
|
|
63
|
+
createDevCors,
|
|
64
|
+
} from "./cors.js";
|
|
65
|
+
export type { DynamicCorsOptions } from "./cors.js";
|
|
66
|
+
|
|
67
|
+
// Request logging / context
|
|
68
|
+
export {
|
|
69
|
+
createRequestLoggingMiddleware,
|
|
70
|
+
type RequestLoggingOptions,
|
|
71
|
+
} from "./requestLogging.js";
|