@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,453 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard Server Implementation
|
|
3
|
+
* A simplified, consistent server pattern for all SuperDangerous applications
|
|
4
|
+
* Combines the best of StartupOrchestrator with the simplicity apps need
|
|
5
|
+
*/
|
|
6
|
+
import express from "express";
|
|
7
|
+
import { createServer } from "http";
|
|
8
|
+
import cors from "cors";
|
|
9
|
+
import { createWebSocketServer } from "../services/websocketServer.js";
|
|
10
|
+
import { displayStartupBanner } from "../utils/startupBanner.js";
|
|
11
|
+
import { getProcessOnPort } from "./portUtils.js";
|
|
12
|
+
import { createLogger, getLogger } from "./index.js";
|
|
13
|
+
import { aiErrorHandler } from "../middleware/aiErrorHandler.js";
|
|
14
|
+
import { apiErrorHandler } from "./apiResponse.js";
|
|
15
|
+
import { createRequestLoggingMiddleware } from "../middleware/requestLogging.js";
|
|
16
|
+
import { getAppDataPath, getLogsPath, isDesktopApp, } from "../utils/appPaths.js";
|
|
17
|
+
let logger; // Will be initialized when needed
|
|
18
|
+
function ensureLogger() {
|
|
19
|
+
if (!logger) {
|
|
20
|
+
logger = createLogger("Server");
|
|
21
|
+
}
|
|
22
|
+
return logger;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Standard server implementation that all apps should use
|
|
26
|
+
* Handles startup, error handling, and banner display consistently
|
|
27
|
+
*/
|
|
28
|
+
export class StandardServer {
|
|
29
|
+
app;
|
|
30
|
+
httpServer;
|
|
31
|
+
config;
|
|
32
|
+
wsServer;
|
|
33
|
+
startTime;
|
|
34
|
+
isInitialized = false;
|
|
35
|
+
shuttingDown = false;
|
|
36
|
+
signalsBound = false;
|
|
37
|
+
connections = new Set();
|
|
38
|
+
constructor(config) {
|
|
39
|
+
const environment = process.env.NODE_ENV || "development";
|
|
40
|
+
// Default to localhost for development/test, 0.0.0.0 for production/containerized environments
|
|
41
|
+
const defaultHost = environment === "development" || environment === "test"
|
|
42
|
+
? "localhost"
|
|
43
|
+
: "0.0.0.0";
|
|
44
|
+
// Auto-enable desktop integration if running in Electron or explicitly enabled
|
|
45
|
+
const enableDesktopIntegration = config.enableDesktopIntegration ?? isDesktopApp();
|
|
46
|
+
this.config = {
|
|
47
|
+
port: 8080,
|
|
48
|
+
host: process.env.HOST || config.host || defaultHost,
|
|
49
|
+
environment,
|
|
50
|
+
enableWebSocket: true,
|
|
51
|
+
bodyLimit: "10mb",
|
|
52
|
+
requestTimeoutMs: 120_000,
|
|
53
|
+
headersTimeoutMs: 65_000,
|
|
54
|
+
keepAliveTimeoutMs: 60_000,
|
|
55
|
+
gracefulShutdownSignals: ["SIGTERM", "SIGINT"],
|
|
56
|
+
enableRequestLogging: true,
|
|
57
|
+
enableDesktopIntegration,
|
|
58
|
+
appId: config.appId ||
|
|
59
|
+
`com.company.${config.appName.toLowerCase().replace(/[^a-z0-9]/g, "-")}`,
|
|
60
|
+
exitOnStartupError: config.exitOnStartupError ?? process.env.NODE_ENV !== "test",
|
|
61
|
+
...config,
|
|
62
|
+
};
|
|
63
|
+
this.app = express();
|
|
64
|
+
this.httpServer = createServer(this.app);
|
|
65
|
+
this.httpServer.on("connection", (socket) => {
|
|
66
|
+
this.connections.add(socket);
|
|
67
|
+
socket.on("close", () => this.connections.delete(socket));
|
|
68
|
+
});
|
|
69
|
+
this.startTime = Date.now();
|
|
70
|
+
this.bindShutdownSignals();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the Express app instance for middleware setup
|
|
74
|
+
*/
|
|
75
|
+
getApp() {
|
|
76
|
+
return this.app;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the HTTP server instance
|
|
80
|
+
*/
|
|
81
|
+
getServer() {
|
|
82
|
+
return this.httpServer;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Initialize the server (setup middleware, routes, etc.)
|
|
86
|
+
*/
|
|
87
|
+
async initialize() {
|
|
88
|
+
if (this.isInitialized)
|
|
89
|
+
return;
|
|
90
|
+
this.isInitialized = true;
|
|
91
|
+
try {
|
|
92
|
+
// Setup desktop-specific paths, CORS, and logging if running as desktop app
|
|
93
|
+
if (this.config.enableDesktopIntegration) {
|
|
94
|
+
await this.setupDesktopIntegration();
|
|
95
|
+
}
|
|
96
|
+
// Initialize the logger first to ensure file output works
|
|
97
|
+
const logger = getLogger;
|
|
98
|
+
if (logger &&
|
|
99
|
+
typeof logger.isInitialized === "function" &&
|
|
100
|
+
!logger.isInitialized()) {
|
|
101
|
+
// Use proper logs directory for desktop apps
|
|
102
|
+
const logsDir = this.config.enableDesktopIntegration
|
|
103
|
+
? getLogsPath(this.config.appId, this.config.appName)
|
|
104
|
+
: "./data/logs";
|
|
105
|
+
await logger.initialize({
|
|
106
|
+
appName: this.config.appName,
|
|
107
|
+
logLevel: this.config.logging?.level || process.env.LOG_LEVEL || "info",
|
|
108
|
+
consoleOutput: true,
|
|
109
|
+
fileOutput: true,
|
|
110
|
+
logsDir,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// Setup default middleware
|
|
114
|
+
this.setupDefaultMiddleware();
|
|
115
|
+
// Initialize WebSocket if enabled (before onInitialize so it can be passed)
|
|
116
|
+
if (this.config.enableWebSocket) {
|
|
117
|
+
this.wsServer = await Promise.resolve(createWebSocketServer(this.httpServer));
|
|
118
|
+
}
|
|
119
|
+
// Call custom initialization if provided, passing the WebSocket server
|
|
120
|
+
if (this.config.onInitialize) {
|
|
121
|
+
const wantsWebSocket = this.config.onInitialize.length >= 2;
|
|
122
|
+
if (wantsWebSocket) {
|
|
123
|
+
await this.config.onInitialize(this.app, this.wsServer);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await this.config.onInitialize(this.app);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Setup error handlers (should be last)
|
|
130
|
+
this.setupErrorHandlers();
|
|
131
|
+
}
|
|
132
|
+
catch (_error) {
|
|
133
|
+
ensureLogger().error("Server initialization failed:", _error);
|
|
134
|
+
this.isInitialized = false;
|
|
135
|
+
throw _error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Setup desktop app integration (CORS, data paths, logging, etc.)
|
|
140
|
+
*/
|
|
141
|
+
async setupDesktopIntegration() {
|
|
142
|
+
ensureLogger().info("Setting up desktop app integration", {
|
|
143
|
+
appId: this.config.appId,
|
|
144
|
+
isDesktopApp: isDesktopApp(),
|
|
145
|
+
dataPath: this.config.desktopDataPath ||
|
|
146
|
+
getAppDataPath(this.config.appId, this.config.appName),
|
|
147
|
+
});
|
|
148
|
+
// Initialize logging for desktop apps
|
|
149
|
+
const logger = getLogger;
|
|
150
|
+
if (!logger.isInitialized()) {
|
|
151
|
+
const logsDir = getLogsPath(this.config.appId, this.config.appName);
|
|
152
|
+
await logger.initialize({
|
|
153
|
+
appName: this.config.appName,
|
|
154
|
+
logLevel: process.env.LOG_LEVEL || "info",
|
|
155
|
+
consoleOutput: true,
|
|
156
|
+
fileOutput: true,
|
|
157
|
+
logsDir,
|
|
158
|
+
});
|
|
159
|
+
ensureLogger().info("Logging initialized for desktop app", { logsDir });
|
|
160
|
+
}
|
|
161
|
+
// Setup CORS for desktop apps
|
|
162
|
+
const corsOrigins = [...(this.config.corsOrigins || [])];
|
|
163
|
+
// Add localhost origins based on webPort if specified
|
|
164
|
+
if (this.config.webPort) {
|
|
165
|
+
corsOrigins.push(`http://localhost:${this.config.webPort}`, `http://localhost:${this.config.webPort + 1}`);
|
|
166
|
+
}
|
|
167
|
+
// Add Electron origins when running in desktop mode
|
|
168
|
+
if (isDesktopApp()) {
|
|
169
|
+
// Electron file:// protocol sends null or file:// origin
|
|
170
|
+
corsOrigins.push("file://", "null");
|
|
171
|
+
}
|
|
172
|
+
this.app.use(cors({
|
|
173
|
+
origin: corsOrigins,
|
|
174
|
+
credentials: true,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Setup default middleware for all applications
|
|
179
|
+
*/
|
|
180
|
+
setupDefaultMiddleware() {
|
|
181
|
+
// Basic middleware that should be present in all apps
|
|
182
|
+
this.app.use(express.json({ limit: this.config.bodyLimit }));
|
|
183
|
+
this.app.use(express.urlencoded({ extended: true, limit: this.config.bodyLimit }));
|
|
184
|
+
// CORS setup for non-desktop apps (desktop setup happens in setupDesktopIntegration)
|
|
185
|
+
if (!this.config.enableDesktopIntegration) {
|
|
186
|
+
const corsOrigins = [...(this.config.corsOrigins || [])];
|
|
187
|
+
// Add localhost origins based on webPort if specified
|
|
188
|
+
if (this.config.webPort) {
|
|
189
|
+
corsOrigins.push(`http://localhost:${this.config.webPort}`, `http://localhost:${this.config.webPort + 1}`);
|
|
190
|
+
}
|
|
191
|
+
if (corsOrigins.length > 0) {
|
|
192
|
+
this.app.use(cors({
|
|
193
|
+
origin: corsOrigins,
|
|
194
|
+
credentials: true,
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
this.app.use(cors());
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Request logging (can be disabled)
|
|
202
|
+
if (this.config.enableRequestLogging) {
|
|
203
|
+
this.app.use(createRequestLoggingMiddleware({
|
|
204
|
+
logger: ensureLogger(),
|
|
205
|
+
...this.config.requestLogging,
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
// Trust proxy to respect X-Forwarded-* headers in containerized/proxy envs
|
|
209
|
+
const trustProxy = this.config.trustProxy ??
|
|
210
|
+
(this.config.environment !== "development" ? true : false);
|
|
211
|
+
if (typeof this.app.set === "function") {
|
|
212
|
+
this.app.set("trust proxy", trustProxy);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Setup error handlers (should be last in middleware chain)
|
|
217
|
+
*/
|
|
218
|
+
setupErrorHandlers() {
|
|
219
|
+
// AI error handler for AI service errors
|
|
220
|
+
this.app.use(aiErrorHandler);
|
|
221
|
+
// Standardized API error handler
|
|
222
|
+
this.app.use(apiErrorHandler);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Start the server and listen on the configured port
|
|
226
|
+
*/
|
|
227
|
+
async start() {
|
|
228
|
+
if (!this.isInitialized) {
|
|
229
|
+
throw new Error("Server not initialized. Call initialize() first.");
|
|
230
|
+
}
|
|
231
|
+
const port = this.config.port;
|
|
232
|
+
const host = this.config.host;
|
|
233
|
+
const exitOnError = this.config.exitOnStartupError !== false;
|
|
234
|
+
// Check if API port is available (skip for port 0 which means "pick any available")
|
|
235
|
+
if (port !== 0) {
|
|
236
|
+
const processOnPort = await getProcessOnPort(port);
|
|
237
|
+
if (processOnPort) {
|
|
238
|
+
const message = `Port ${port} is already in use`;
|
|
239
|
+
if (exitOnError) {
|
|
240
|
+
ensureLogger().error(message);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
ensureLogger().warn(`${message} (PID ${processOnPort.pid} - ${processOnPort.command})`);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return new Promise((resolve, reject) => {
|
|
250
|
+
const fail = (error) => {
|
|
251
|
+
ensureLogger().error("Server error:", error);
|
|
252
|
+
if (exitOnError) {
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
reject(error);
|
|
256
|
+
};
|
|
257
|
+
// Handle server errors
|
|
258
|
+
this.httpServer.on("error", (error) => {
|
|
259
|
+
if (error.code === "EADDRINUSE") {
|
|
260
|
+
const message = `Port ${port} is already in use`;
|
|
261
|
+
ensureLogger().error(message);
|
|
262
|
+
if (exitOnError) {
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
reject(new Error(message));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
else if (error.code === "EACCES") {
|
|
269
|
+
const message = `Port ${port} requires elevated privileges`;
|
|
270
|
+
ensureLogger().error(message);
|
|
271
|
+
if (exitOnError) {
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
274
|
+
reject(new Error(message));
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
fail(error instanceof Error ? error : new Error(String(error)));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
// Start listening
|
|
283
|
+
// Apply safer timeouts for production workloads
|
|
284
|
+
this.httpServer.requestTimeout = this.config.requestTimeoutMs;
|
|
285
|
+
this.httpServer.headersTimeout = this.config.headersTimeoutMs;
|
|
286
|
+
this.httpServer.keepAliveTimeout = this.config.keepAliveTimeoutMs;
|
|
287
|
+
try {
|
|
288
|
+
this.httpServer.listen(port, host, async () => {
|
|
289
|
+
// Display banner only after successful binding
|
|
290
|
+
// Note: In production, webPort is typically not used because the API server
|
|
291
|
+
// serves the UI assets directly from the main port. However, if webPort
|
|
292
|
+
// is explicitly configured, respect it.
|
|
293
|
+
// Only display banner if not suppressed
|
|
294
|
+
if (process.env.SUPPRESS_STARTUP_BANNER !== "true") {
|
|
295
|
+
displayStartupBanner({
|
|
296
|
+
appName: this.config.appName,
|
|
297
|
+
appVersion: this.config.appVersion,
|
|
298
|
+
description: this.config.description,
|
|
299
|
+
port: this.config.port,
|
|
300
|
+
webPort: this.config.webPort, // Pass the actual configured webPort
|
|
301
|
+
environment: this.config.environment,
|
|
302
|
+
startTime: this.startTime,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// Call custom start handler if provided
|
|
306
|
+
if (this.config.onStart) {
|
|
307
|
+
try {
|
|
308
|
+
await this.config.onStart();
|
|
309
|
+
}
|
|
310
|
+
catch (_error) {
|
|
311
|
+
const error = _error instanceof Error ? _error : new Error(String(_error));
|
|
312
|
+
ensureLogger().error("Custom start handler failed:", error);
|
|
313
|
+
if (exitOnError) {
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
reject(error);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (this.config.webPort) {
|
|
321
|
+
ensureLogger().info(`Web UI Port: ${this.config.webPort}`);
|
|
322
|
+
}
|
|
323
|
+
// Bind graceful shutdown signals once per instance
|
|
324
|
+
this.bindShutdownSignals();
|
|
325
|
+
resolve();
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
330
|
+
ensureLogger().error("Failed to start server:", error);
|
|
331
|
+
if (exitOnError) {
|
|
332
|
+
process.exit(1);
|
|
333
|
+
}
|
|
334
|
+
reject(error);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get the data path for desktop apps (platform-specific)
|
|
340
|
+
*/
|
|
341
|
+
getDataPath() {
|
|
342
|
+
if (this.config.enableDesktopIntegration) {
|
|
343
|
+
return (this.config.desktopDataPath ||
|
|
344
|
+
getAppDataPath(this.config.appId, this.config.appName));
|
|
345
|
+
}
|
|
346
|
+
return "./data";
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Check if running as desktop app
|
|
350
|
+
*/
|
|
351
|
+
isDesktopApp() {
|
|
352
|
+
return this.config.enableDesktopIntegration || false;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Attach signal listeners for graceful shutdown
|
|
356
|
+
*/
|
|
357
|
+
bindShutdownSignals() {
|
|
358
|
+
if (this.signalsBound)
|
|
359
|
+
return;
|
|
360
|
+
if (!this.config.gracefulShutdownSignals?.length)
|
|
361
|
+
return;
|
|
362
|
+
const signals = this.config.gracefulShutdownSignals;
|
|
363
|
+
if (process.setMaxListeners) {
|
|
364
|
+
const current = process.getMaxListeners ? process.getMaxListeners() : 10;
|
|
365
|
+
process.setMaxListeners(Math.max(current, signals.length + 20));
|
|
366
|
+
}
|
|
367
|
+
signals.forEach((signal) => {
|
|
368
|
+
process.on(signal, async () => {
|
|
369
|
+
ensureLogger().info(`Received ${signal}, shutting down gracefully...`);
|
|
370
|
+
try {
|
|
371
|
+
await this.stop();
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
ensureLogger().error("Graceful shutdown failed", error);
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
this.signalsBound = true;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Stop the server gracefully
|
|
384
|
+
*/
|
|
385
|
+
async stop() {
|
|
386
|
+
if (this.shuttingDown)
|
|
387
|
+
return Promise.resolve();
|
|
388
|
+
this.shuttingDown = true;
|
|
389
|
+
return new Promise((resolve, reject) => {
|
|
390
|
+
const timeout = setTimeout(() => {
|
|
391
|
+
ensureLogger().warn("Force closing server after timeout");
|
|
392
|
+
this.forceCloseConnections();
|
|
393
|
+
resolve();
|
|
394
|
+
}, 10_000);
|
|
395
|
+
const close = () => {
|
|
396
|
+
clearTimeout(timeout);
|
|
397
|
+
ensureLogger().info("Server stopped gracefully");
|
|
398
|
+
resolve();
|
|
399
|
+
};
|
|
400
|
+
try {
|
|
401
|
+
if (this.wsServer?.shutdown) {
|
|
402
|
+
this.wsServer.shutdown();
|
|
403
|
+
}
|
|
404
|
+
if (this.wsServer?.close) {
|
|
405
|
+
this.wsServer.close();
|
|
406
|
+
}
|
|
407
|
+
this.httpServer.close((err) => {
|
|
408
|
+
if (err) {
|
|
409
|
+
ensureLogger().error("Error while stopping server", err);
|
|
410
|
+
reject(err);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
this.forceCloseConnections();
|
|
414
|
+
close();
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
clearTimeout(timeout);
|
|
419
|
+
reject(error);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
forceCloseConnections() {
|
|
424
|
+
// Prefer native closeAllConnections if available
|
|
425
|
+
if (typeof this.httpServer.closeAllConnections === "function") {
|
|
426
|
+
try {
|
|
427
|
+
this.httpServer.closeAllConnections();
|
|
428
|
+
}
|
|
429
|
+
catch (err) {
|
|
430
|
+
ensureLogger().warn("closeAllConnections failed", err);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
this.connections.forEach((socket) => {
|
|
434
|
+
try {
|
|
435
|
+
socket.destroy();
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
// ignore
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
this.connections.clear();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Convenience function to create and start a standard server
|
|
446
|
+
*/
|
|
447
|
+
export async function createStandardServer(config) {
|
|
448
|
+
const server = new StandardServer(config);
|
|
449
|
+
await server.initialize();
|
|
450
|
+
await server.start();
|
|
451
|
+
return server;
|
|
452
|
+
}
|
|
453
|
+
//# sourceMappingURL=StandardServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StandardServer.js","sourceRoot":"","sources":["../../src/core/StandardServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized API Response Utilities
|
|
3
|
+
* Provides consistent response format across all applications
|
|
4
|
+
*/
|
|
5
|
+
import { Response } from "express";
|
|
6
|
+
export interface ApiResponse<T = any> {
|
|
7
|
+
success: boolean;
|
|
8
|
+
data?: T;
|
|
9
|
+
error?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
timestamp?: string;
|
|
12
|
+
metadata?: Record<string, any>;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiErrorResponse extends ApiResponse {
|
|
15
|
+
success: false;
|
|
16
|
+
error: string;
|
|
17
|
+
code?: string;
|
|
18
|
+
details?: any;
|
|
19
|
+
stack?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ApiSuccessResponse<T = any> extends ApiResponse<T> {
|
|
22
|
+
success: true;
|
|
23
|
+
data: T;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Send a successful response
|
|
27
|
+
*/
|
|
28
|
+
export declare function sendSuccess<T = any>(res: Response, data: T, message?: string, statusCode?: number): Response<ApiSuccessResponse<T>>;
|
|
29
|
+
/**
|
|
30
|
+
* Send an error response
|
|
31
|
+
*/
|
|
32
|
+
export declare function sendError(res: Response, error: string | Error, statusCode?: number, details?: any): Response<ApiErrorResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Send a validation error response
|
|
35
|
+
*/
|
|
36
|
+
export declare function sendValidationError(res: Response, errors: any, message?: string): Response<ApiErrorResponse>;
|
|
37
|
+
/**
|
|
38
|
+
* Send a not found response
|
|
39
|
+
*/
|
|
40
|
+
export declare function sendNotFound(res: Response, resource?: string): Response<ApiErrorResponse>;
|
|
41
|
+
/**
|
|
42
|
+
* Send an unauthorized response
|
|
43
|
+
*/
|
|
44
|
+
export declare function sendUnauthorized(res: Response, message?: string): Response<ApiErrorResponse>;
|
|
45
|
+
/**
|
|
46
|
+
* Send a forbidden response
|
|
47
|
+
*/
|
|
48
|
+
export declare function sendForbidden(res: Response, message?: string): Response<ApiErrorResponse>;
|
|
49
|
+
/**
|
|
50
|
+
* Send a bad request response
|
|
51
|
+
*/
|
|
52
|
+
export declare function sendBadRequest(res: Response, message?: string): Response<ApiErrorResponse>;
|
|
53
|
+
/**
|
|
54
|
+
* Send a created response
|
|
55
|
+
*/
|
|
56
|
+
export declare function sendCreated<T = any>(res: Response, data: T, message?: string): Response<ApiSuccessResponse<T>>;
|
|
57
|
+
/**
|
|
58
|
+
* Send a no content response
|
|
59
|
+
*/
|
|
60
|
+
export declare function sendNoContent(res: Response): Response;
|
|
61
|
+
/**
|
|
62
|
+
* Wrap async route handlers to catch errors
|
|
63
|
+
*/
|
|
64
|
+
export declare function asyncHandler(fn: (req: any, res: any, next: any) => any): (req: any, res: any, next: any) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Standard error handler middleware
|
|
67
|
+
*/
|
|
68
|
+
export declare function apiErrorHandler(err: any, _req: any, res: any, next: any): any;
|
|
69
|
+
//# sourceMappingURL=apiResponse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiResponse.d.ts","sourceRoot":"","sources":["../../src/core/apiResponse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAMnC,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,GAAG,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;IACjE,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;CACT;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,EACjC,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,CAAC,EACP,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,SAAM,GACf,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CASjC;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,MAAM,GAAG,KAAK,EACrB,UAAU,SAAM,EAChB,OAAO,CAAC,EAAE,GAAG,GACZ,QAAQ,CAAC,gBAAgB,CAAC,CAoB5B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,QAAQ,EACb,MAAM,EAAE,GAAG,EACX,OAAO,SAAsB,GAC5B,QAAQ,CAAC,gBAAgB,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,QAAQ,EACb,QAAQ,SAAa,GACpB,QAAQ,CAAC,gBAAgB,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,QAAQ,EACb,OAAO,SAAiB,GACvB,QAAQ,CAAC,gBAAgB,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,QAAQ,EACb,OAAO,SAAc,GACpB,QAAQ,CAAC,gBAAgB,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,QAAQ,EACb,OAAO,SAAgB,GACtB,QAAQ,CAAC,gBAAgB,CAAC,CAE5B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,GAAG,EACjC,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,CAAC,EACP,OAAO,SAAkC,GACxC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAEjC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,QAAQ,CAErD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,GAAG,IAC7D,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,UAGtC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,OAsCvE"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized API Response Utilities
|
|
3
|
+
* Provides consistent response format across all applications
|
|
4
|
+
*/
|
|
5
|
+
import { ZodError } from "zod";
|
|
6
|
+
import { createLogger } from "../core/logger.js";
|
|
7
|
+
const logger = createLogger("api-error");
|
|
8
|
+
/**
|
|
9
|
+
* Send a successful response
|
|
10
|
+
*/
|
|
11
|
+
export function sendSuccess(res, data, message, statusCode = 200) {
|
|
12
|
+
const requestId = res.locals?.requestId;
|
|
13
|
+
return res.status(statusCode).json({
|
|
14
|
+
success: true,
|
|
15
|
+
data,
|
|
16
|
+
message,
|
|
17
|
+
timestamp: new Date().toISOString(),
|
|
18
|
+
metadata: requestId ? { requestId } : undefined,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Send an error response
|
|
23
|
+
*/
|
|
24
|
+
export function sendError(res, error, statusCode = 500, details) {
|
|
25
|
+
const requestId = res.locals?.requestId;
|
|
26
|
+
const errorMessage = typeof error === "string" ? error : error.message;
|
|
27
|
+
const response = {
|
|
28
|
+
success: false,
|
|
29
|
+
error: errorMessage,
|
|
30
|
+
timestamp: new Date().toISOString(),
|
|
31
|
+
metadata: requestId ? { requestId } : undefined,
|
|
32
|
+
};
|
|
33
|
+
if (details) {
|
|
34
|
+
response.details = details;
|
|
35
|
+
}
|
|
36
|
+
// Include stack trace in development
|
|
37
|
+
if (process.env.NODE_ENV === "development" && error instanceof Error) {
|
|
38
|
+
response.stack = error.stack;
|
|
39
|
+
}
|
|
40
|
+
return res.status(statusCode).json(response);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Send a validation error response
|
|
44
|
+
*/
|
|
45
|
+
export function sendValidationError(res, errors, message = "Validation failed") {
|
|
46
|
+
return sendError(res, message, 400, errors);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Send a not found response
|
|
50
|
+
*/
|
|
51
|
+
export function sendNotFound(res, resource = "Resource") {
|
|
52
|
+
return sendError(res, `${resource} not found`, 404);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Send an unauthorized response
|
|
56
|
+
*/
|
|
57
|
+
export function sendUnauthorized(res, message = "Unauthorized") {
|
|
58
|
+
return sendError(res, message, 401);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Send a forbidden response
|
|
62
|
+
*/
|
|
63
|
+
export function sendForbidden(res, message = "Forbidden") {
|
|
64
|
+
return sendError(res, message, 403);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Send a bad request response
|
|
68
|
+
*/
|
|
69
|
+
export function sendBadRequest(res, message = "Bad request") {
|
|
70
|
+
return sendError(res, message, 400);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Send a created response
|
|
74
|
+
*/
|
|
75
|
+
export function sendCreated(res, data, message = "Resource created successfully") {
|
|
76
|
+
return sendSuccess(res, data, message, 201);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Send a no content response
|
|
80
|
+
*/
|
|
81
|
+
export function sendNoContent(res) {
|
|
82
|
+
return res.status(204).send();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Wrap async route handlers to catch errors
|
|
86
|
+
*/
|
|
87
|
+
export function asyncHandler(fn) {
|
|
88
|
+
return (req, res, next) => {
|
|
89
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Standard error handler middleware
|
|
94
|
+
*/
|
|
95
|
+
export function apiErrorHandler(err, _req, res, next) {
|
|
96
|
+
// If response was already sent, delegate to default Express error handler
|
|
97
|
+
if (res.headersSent) {
|
|
98
|
+
return next(err);
|
|
99
|
+
}
|
|
100
|
+
// Log the error using the framework's enhanced logger
|
|
101
|
+
logger.error("API Error:", {
|
|
102
|
+
error: err.message,
|
|
103
|
+
stack: err.stack,
|
|
104
|
+
name: err.name,
|
|
105
|
+
statusCode: err.statusCode || err.status || 500,
|
|
106
|
+
});
|
|
107
|
+
// Handle different error types
|
|
108
|
+
if (err instanceof ZodError || err?.name === "ZodError") {
|
|
109
|
+
const issues = err instanceof ZodError ? err.issues : err?.issues;
|
|
110
|
+
return sendValidationError(res, issues || err.message);
|
|
111
|
+
}
|
|
112
|
+
if (err.name === "ValidationError") {
|
|
113
|
+
return sendValidationError(res, err.errors || err.message);
|
|
114
|
+
}
|
|
115
|
+
if (err.name === "UnauthorizedError") {
|
|
116
|
+
return sendUnauthorized(res, err.message);
|
|
117
|
+
}
|
|
118
|
+
if (err.name === "CastError" || err.name === "TypeError") {
|
|
119
|
+
return sendBadRequest(res, "Invalid request parameters");
|
|
120
|
+
}
|
|
121
|
+
if (err.statusCode || err.status) {
|
|
122
|
+
return sendError(res, err.message, err.statusCode || err.status);
|
|
123
|
+
}
|
|
124
|
+
// Default to internal server error
|
|
125
|
+
return sendError(res, err.message || "Internal server error");
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=apiResponse.js.map
|