@qwickapps/server 1.0.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 +45 -0
- package/README.md +321 -0
- package/dist/core/control-panel.d.ts +21 -0
- package/dist/core/control-panel.d.ts.map +1 -0
- package/dist/core/control-panel.js +416 -0
- package/dist/core/control-panel.js.map +1 -0
- package/dist/core/gateway.d.ts +133 -0
- package/dist/core/gateway.d.ts.map +1 -0
- package/dist/core/gateway.js +270 -0
- package/dist/core/gateway.js.map +1 -0
- package/dist/core/health-manager.d.ts +52 -0
- package/dist/core/health-manager.d.ts.map +1 -0
- package/dist/core/health-manager.js +192 -0
- package/dist/core/health-manager.js.map +1 -0
- package/dist/core/index.d.ts +10 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +8 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logging.d.ts +83 -0
- package/dist/core/logging.d.ts.map +1 -0
- package/dist/core/logging.js +191 -0
- package/dist/core/logging.js.map +1 -0
- package/dist/core/types.d.ts +195 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/config-plugin.d.ts +15 -0
- package/dist/plugins/config-plugin.d.ts.map +1 -0
- package/dist/plugins/config-plugin.js +96 -0
- package/dist/plugins/config-plugin.js.map +1 -0
- package/dist/plugins/diagnostics-plugin.d.ts +29 -0
- package/dist/plugins/diagnostics-plugin.d.ts.map +1 -0
- package/dist/plugins/diagnostics-plugin.js +142 -0
- package/dist/plugins/diagnostics-plugin.js.map +1 -0
- package/dist/plugins/health-plugin.d.ts +17 -0
- package/dist/plugins/health-plugin.d.ts.map +1 -0
- package/dist/plugins/health-plugin.js +25 -0
- package/dist/plugins/health-plugin.js.map +1 -0
- package/dist/plugins/index.d.ts +14 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +10 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/logs-plugin.d.ts +22 -0
- package/dist/plugins/logs-plugin.d.ts.map +1 -0
- package/dist/plugins/logs-plugin.js +242 -0
- package/dist/plugins/logs-plugin.js.map +1 -0
- package/dist-ui/assets/index-Bk7ypbI4.js +465 -0
- package/dist-ui/assets/index-Bk7ypbI4.js.map +1 -0
- package/dist-ui/assets/index-CiizQQnb.css +1 -0
- package/dist-ui/index.html +13 -0
- package/package.json +98 -0
- package/src/core/control-panel.ts +493 -0
- package/src/core/gateway.ts +421 -0
- package/src/core/health-manager.ts +227 -0
- package/src/core/index.ts +25 -0
- package/src/core/logging.ts +234 -0
- package/src/core/types.ts +218 -0
- package/src/index.ts +55 -0
- package/src/plugins/config-plugin.ts +117 -0
- package/src/plugins/diagnostics-plugin.ts +178 -0
- package/src/plugins/health-plugin.ts +35 -0
- package/src/plugins/index.ts +17 -0
- package/src/plugins/logs-plugin.ts +314 -0
- package/ui/index.html +12 -0
- package/ui/src/App.tsx +65 -0
- package/ui/src/api/controlPanelApi.ts +148 -0
- package/ui/src/config/AppConfig.ts +18 -0
- package/ui/src/index.css +29 -0
- package/ui/src/index.tsx +11 -0
- package/ui/src/pages/ConfigPage.tsx +199 -0
- package/ui/src/pages/DashboardPage.tsx +264 -0
- package/ui/src/pages/DiagnosticsPage.tsx +315 -0
- package/ui/src/pages/HealthPage.tsx +204 -0
- package/ui/src/pages/LogsPage.tsx +267 -0
- package/ui/src/pages/NotFoundPage.tsx +41 -0
- package/ui/tsconfig.json +19 -0
- package/ui/vite.config.ts +21 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Server for @qwickapps/server
|
|
3
|
+
*
|
|
4
|
+
* Provides a production-ready gateway pattern that:
|
|
5
|
+
* 1. Serves the control panel UI (always responsive)
|
|
6
|
+
* 2. Proxies API requests to an internal service
|
|
7
|
+
* 3. Provides health and diagnostics endpoints
|
|
8
|
+
*
|
|
9
|
+
* Architecture:
|
|
10
|
+
* Internet → Gateway (GATEWAY_PORT, public) → Service (SERVICE_PORT, internal)
|
|
11
|
+
*
|
|
12
|
+
* The gateway is always responsive even if the internal service is down,
|
|
13
|
+
* allowing diagnostics and error visibility.
|
|
14
|
+
*
|
|
15
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
16
|
+
*/
|
|
17
|
+
import { createControlPanel } from './control-panel.js';
|
|
18
|
+
import { initializeLogging, getControlPanelLogger } from './logging.js';
|
|
19
|
+
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
20
|
+
import { randomBytes } from 'crypto';
|
|
21
|
+
import express from 'express';
|
|
22
|
+
import { existsSync } from 'fs';
|
|
23
|
+
import { resolve } from 'path';
|
|
24
|
+
/**
|
|
25
|
+
* Basic auth middleware for gateway protection (control panel only)
|
|
26
|
+
* - Skips localhost requests
|
|
27
|
+
* - Skips API routes (/api/v1/*) - they have their own service auth
|
|
28
|
+
* - Skips health endpoints - these should be public
|
|
29
|
+
* - Requires valid credentials for non-localhost control panel access
|
|
30
|
+
*/
|
|
31
|
+
function createBasicAuthMiddleware(username, password, apiPaths) {
|
|
32
|
+
const expectedAuth = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
|
33
|
+
return (req, res, next) => {
|
|
34
|
+
const path = req.path;
|
|
35
|
+
// Skip auth for API routes - they use their own authentication
|
|
36
|
+
for (const apiPath of apiPaths) {
|
|
37
|
+
if (path.startsWith(apiPath)) {
|
|
38
|
+
return next();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Skip auth for health endpoints - these should be publicly accessible
|
|
42
|
+
if (path === '/health' || path === '/api/health') {
|
|
43
|
+
return next();
|
|
44
|
+
}
|
|
45
|
+
// Allow localhost without auth
|
|
46
|
+
const remoteAddress = req.ip || req.socket?.remoteAddress || '';
|
|
47
|
+
const host = req.hostname || req.headers.host || '';
|
|
48
|
+
const isLocalhost = host === 'localhost' ||
|
|
49
|
+
host === '127.0.0.1' ||
|
|
50
|
+
host.startsWith('localhost:') ||
|
|
51
|
+
host.startsWith('127.0.0.1:') ||
|
|
52
|
+
remoteAddress === '127.0.0.1' ||
|
|
53
|
+
remoteAddress === '::1' ||
|
|
54
|
+
remoteAddress === '::ffff:127.0.0.1';
|
|
55
|
+
if (isLocalhost) {
|
|
56
|
+
return next();
|
|
57
|
+
}
|
|
58
|
+
// Check for valid basic auth
|
|
59
|
+
const authHeader = req.headers.authorization;
|
|
60
|
+
if (authHeader === expectedAuth) {
|
|
61
|
+
return next();
|
|
62
|
+
}
|
|
63
|
+
// Request authentication
|
|
64
|
+
res.setHeader('WWW-Authenticate', 'Basic realm="Control Panel"');
|
|
65
|
+
res.status(401).json({
|
|
66
|
+
error: 'Unauthorized',
|
|
67
|
+
message: 'Authentication required.',
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create a gateway that proxies to an internal service
|
|
73
|
+
*
|
|
74
|
+
* @param config - Gateway configuration
|
|
75
|
+
* @param serviceFactory - Factory function to create the internal service
|
|
76
|
+
* @returns Gateway instance
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* import { createGateway } from '@qwickapps/server';
|
|
81
|
+
*
|
|
82
|
+
* const gateway = createGateway(
|
|
83
|
+
* {
|
|
84
|
+
* productName: 'My Service',
|
|
85
|
+
* gatewayPort: 3101,
|
|
86
|
+
* servicePort: 3100,
|
|
87
|
+
* },
|
|
88
|
+
* async (port) => {
|
|
89
|
+
* const app = createMyApp();
|
|
90
|
+
* const server = app.listen(port);
|
|
91
|
+
* return {
|
|
92
|
+
* app,
|
|
93
|
+
* server,
|
|
94
|
+
* shutdown: async () => { server.close(); },
|
|
95
|
+
* };
|
|
96
|
+
* }
|
|
97
|
+
* );
|
|
98
|
+
*
|
|
99
|
+
* await gateway.start();
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export function createGateway(config, serviceFactory) {
|
|
103
|
+
// Initialize logging subsystem first
|
|
104
|
+
const loggingSubsystem = initializeLogging({
|
|
105
|
+
namespace: config.productName,
|
|
106
|
+
...config.logging,
|
|
107
|
+
});
|
|
108
|
+
// Use provided logger or get one from the logging subsystem
|
|
109
|
+
const logger = config.logger || getControlPanelLogger('Gateway');
|
|
110
|
+
const gatewayPort = config.gatewayPort || parseInt(process.env.GATEWAY_PORT || process.env.PORT || '3101', 10);
|
|
111
|
+
const servicePort = config.servicePort || parseInt(process.env.SERVICE_PORT || '3100', 10);
|
|
112
|
+
const nodeEnv = process.env.NODE_ENV || 'development';
|
|
113
|
+
// Auth configuration
|
|
114
|
+
const authMode = config.authMode || 'auto';
|
|
115
|
+
const basicAuthUser = config.basicAuthUser || process.env.BASIC_AUTH_USER || 'admin';
|
|
116
|
+
const providedPassword = config.basicAuthPassword || process.env.BASIC_AUTH_PASSWORD;
|
|
117
|
+
const basicAuthPassword = providedPassword || (authMode === 'auto' ? randomBytes(16).toString('base64url') : '');
|
|
118
|
+
const isPasswordAutoGenerated = !providedPassword && authMode === 'auto';
|
|
119
|
+
// API paths to proxy
|
|
120
|
+
const proxyPaths = config.proxyPaths || ['/api/v1'];
|
|
121
|
+
let service = null;
|
|
122
|
+
// Create control panel
|
|
123
|
+
const controlPanel = createControlPanel({
|
|
124
|
+
config: {
|
|
125
|
+
productName: config.productName,
|
|
126
|
+
port: gatewayPort,
|
|
127
|
+
version: config.version || process.env.npm_package_version || '1.0.0',
|
|
128
|
+
branding: config.branding,
|
|
129
|
+
cors: config.corsOrigins ? { origins: config.corsOrigins } : undefined,
|
|
130
|
+
// Skip body parsing for proxied paths
|
|
131
|
+
skipBodyParserPaths: [...proxyPaths, '/health'],
|
|
132
|
+
// Disable built-in dashboard if custom UI is provided
|
|
133
|
+
disableDashboard: !!config.customUiPath,
|
|
134
|
+
links: config.links,
|
|
135
|
+
},
|
|
136
|
+
plugins: config.plugins || [],
|
|
137
|
+
logger,
|
|
138
|
+
});
|
|
139
|
+
// Add basic auth middleware if enabled
|
|
140
|
+
if (authMode === 'basic' || authMode === 'auto') {
|
|
141
|
+
controlPanel.app.use(createBasicAuthMiddleware(basicAuthUser, basicAuthPassword, proxyPaths));
|
|
142
|
+
}
|
|
143
|
+
// Setup proxy middleware for API paths
|
|
144
|
+
const setupProxyMiddleware = () => {
|
|
145
|
+
const target = `http://localhost:${servicePort}`;
|
|
146
|
+
// Proxy each API path
|
|
147
|
+
for (const apiPath of proxyPaths) {
|
|
148
|
+
const proxyOptions = {
|
|
149
|
+
target,
|
|
150
|
+
changeOrigin: false,
|
|
151
|
+
pathFilter: `${apiPath}/**`,
|
|
152
|
+
on: {
|
|
153
|
+
error: (err, _req, res) => {
|
|
154
|
+
logger.error('Proxy error', { error: err.message, path: apiPath });
|
|
155
|
+
if (res && 'writeHead' in res && !res.headersSent) {
|
|
156
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
157
|
+
res.end(JSON.stringify({
|
|
158
|
+
error: 'Service Unavailable',
|
|
159
|
+
message: 'The service is currently unavailable. Please try again later.',
|
|
160
|
+
details: nodeEnv === 'development' ? err.message : undefined,
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
controlPanel.app.use(createProxyMiddleware(proxyOptions));
|
|
167
|
+
}
|
|
168
|
+
// Proxy /health endpoint to internal service
|
|
169
|
+
const healthProxyOptions = {
|
|
170
|
+
target,
|
|
171
|
+
changeOrigin: false,
|
|
172
|
+
pathFilter: '/health',
|
|
173
|
+
on: {
|
|
174
|
+
error: (_err, _req, res) => {
|
|
175
|
+
if (res && 'writeHead' in res && !res.headersSent) {
|
|
176
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
177
|
+
res.end(JSON.stringify({
|
|
178
|
+
status: 'unhealthy',
|
|
179
|
+
error: 'Service unavailable',
|
|
180
|
+
gateway: 'healthy',
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
controlPanel.app.use(createProxyMiddleware(healthProxyOptions));
|
|
187
|
+
};
|
|
188
|
+
// Serve custom React UI if provided
|
|
189
|
+
const setupCustomUI = () => {
|
|
190
|
+
if (config.customUiPath && existsSync(config.customUiPath)) {
|
|
191
|
+
logger.info(`Serving custom UI from ${config.customUiPath}`);
|
|
192
|
+
controlPanel.app.use(express.static(config.customUiPath));
|
|
193
|
+
// SPA fallback
|
|
194
|
+
controlPanel.app.get('*', (req, res, next) => {
|
|
195
|
+
if (req.path.startsWith('/api/') || req.path === '/api') {
|
|
196
|
+
return next();
|
|
197
|
+
}
|
|
198
|
+
res.sendFile(resolve(config.customUiPath, 'index.html'));
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const start = async () => {
|
|
203
|
+
logger.info('Starting gateway...');
|
|
204
|
+
// 1. Start internal service
|
|
205
|
+
logger.info(`Starting internal service on port ${servicePort}...`);
|
|
206
|
+
service = await serviceFactory(servicePort);
|
|
207
|
+
logger.info(`Internal service started on port ${servicePort}`);
|
|
208
|
+
// 2. Setup proxy middleware (after service is started)
|
|
209
|
+
setupProxyMiddleware();
|
|
210
|
+
// 3. Setup custom UI (after proxy middleware)
|
|
211
|
+
setupCustomUI();
|
|
212
|
+
// 4. Start control panel gateway
|
|
213
|
+
await controlPanel.start();
|
|
214
|
+
// Log startup info
|
|
215
|
+
logger.info('');
|
|
216
|
+
logger.info('========================================');
|
|
217
|
+
logger.info(` ${config.productName} Gateway`);
|
|
218
|
+
logger.info('========================================');
|
|
219
|
+
logger.info('');
|
|
220
|
+
logger.info(` Gateway Port: ${gatewayPort} (public)`);
|
|
221
|
+
logger.info(` Service Port: ${servicePort} (internal)`);
|
|
222
|
+
logger.info('');
|
|
223
|
+
if (authMode === 'basic' || authMode === 'auto') {
|
|
224
|
+
logger.info(' Control Panel Auth: HTTP Basic Auth');
|
|
225
|
+
logger.info(' ----------------------------------------');
|
|
226
|
+
logger.info(` Username: ${basicAuthUser}`);
|
|
227
|
+
if (isPasswordAutoGenerated) {
|
|
228
|
+
logger.info(` Password: ${basicAuthPassword}`);
|
|
229
|
+
logger.info(' (auto-generated, set BASIC_AUTH_PASSWORD to use a fixed password)');
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
logger.info(' Password: ********** (from environment)');
|
|
233
|
+
}
|
|
234
|
+
logger.info(' ----------------------------------------');
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
logger.info(' Control Panel Auth: None (not recommended)');
|
|
238
|
+
}
|
|
239
|
+
logger.info('');
|
|
240
|
+
logger.info(' Endpoints:');
|
|
241
|
+
logger.info(` GET / - Control Panel UI`);
|
|
242
|
+
logger.info(` GET /api/health - Gateway health`);
|
|
243
|
+
logger.info(` GET /health - Service health (proxied)`);
|
|
244
|
+
for (const apiPath of proxyPaths) {
|
|
245
|
+
logger.info(` * ${apiPath}/* - Service API (proxied)`);
|
|
246
|
+
}
|
|
247
|
+
logger.info('========================================');
|
|
248
|
+
logger.info('');
|
|
249
|
+
};
|
|
250
|
+
const stop = async () => {
|
|
251
|
+
logger.info('Shutting down gateway...');
|
|
252
|
+
// Stop control panel
|
|
253
|
+
await controlPanel.stop();
|
|
254
|
+
// Stop internal service
|
|
255
|
+
if (service) {
|
|
256
|
+
await service.shutdown();
|
|
257
|
+
service.server.close();
|
|
258
|
+
}
|
|
259
|
+
logger.info('Gateway shutdown complete');
|
|
260
|
+
};
|
|
261
|
+
return {
|
|
262
|
+
controlPanel,
|
|
263
|
+
service,
|
|
264
|
+
start,
|
|
265
|
+
stop,
|
|
266
|
+
gatewayPort,
|
|
267
|
+
servicePort,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../src/core/gateway.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages health checks for various services and provides aggregated status
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
7
|
+
*/
|
|
8
|
+
import type { HealthCheck, HealthCheckResult, HealthStatus, Logger } from './types.js';
|
|
9
|
+
export declare class HealthManager {
|
|
10
|
+
private checks;
|
|
11
|
+
private results;
|
|
12
|
+
private intervals;
|
|
13
|
+
private logger;
|
|
14
|
+
constructor(logger: Logger);
|
|
15
|
+
/**
|
|
16
|
+
* Register a health check
|
|
17
|
+
*/
|
|
18
|
+
register(check: HealthCheck): void;
|
|
19
|
+
/**
|
|
20
|
+
* Run a health check
|
|
21
|
+
*/
|
|
22
|
+
private runCheck;
|
|
23
|
+
/**
|
|
24
|
+
* Run HTTP health check
|
|
25
|
+
*/
|
|
26
|
+
private runHttpCheck;
|
|
27
|
+
/**
|
|
28
|
+
* Run TCP health check (simplified - just tries to connect)
|
|
29
|
+
*/
|
|
30
|
+
private runTcpCheck;
|
|
31
|
+
/**
|
|
32
|
+
* Get all health check results
|
|
33
|
+
*/
|
|
34
|
+
getResults(): Record<string, HealthCheckResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Get specific health check result
|
|
37
|
+
*/
|
|
38
|
+
getResult(name: string): HealthCheckResult | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Get aggregated status
|
|
41
|
+
*/
|
|
42
|
+
getAggregatedStatus(): HealthStatus;
|
|
43
|
+
/**
|
|
44
|
+
* Force run all checks
|
|
45
|
+
*/
|
|
46
|
+
checkAll(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Shutdown - clear all intervals
|
|
49
|
+
*/
|
|
50
|
+
shutdown(): void;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=health-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-manager.d.ts","sourceRoot":"","sources":["../../src/core/health-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEvF,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,SAAS,CAA0D;IAC3E,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAI1B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAyBlC;;OAEG;YACW,QAAQ;IA2DtB;;OAEG;YACW,YAAY;IAmC1B;;OAEG;YACW,WAAW;IAuBzB;;OAEG;IACH,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAI/C;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAItD;;OAEG;IACH,mBAAmB,IAAI,YAAY;IAiBnC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/B;;OAEG;IACH,QAAQ,IAAI,IAAI;CAOjB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Check Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages health checks for various services and provides aggregated status
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
7
|
+
*/
|
|
8
|
+
export class HealthManager {
|
|
9
|
+
constructor(logger) {
|
|
10
|
+
this.checks = new Map();
|
|
11
|
+
this.results = new Map();
|
|
12
|
+
this.intervals = new Map();
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Register a health check
|
|
17
|
+
*/
|
|
18
|
+
register(check) {
|
|
19
|
+
this.checks.set(check.name, check);
|
|
20
|
+
// Initialize result
|
|
21
|
+
this.results.set(check.name, {
|
|
22
|
+
status: 'unknown',
|
|
23
|
+
lastChecked: new Date(),
|
|
24
|
+
});
|
|
25
|
+
// Start periodic check
|
|
26
|
+
const interval = check.interval || 30000; // Default 30 seconds
|
|
27
|
+
this.runCheck(check.name);
|
|
28
|
+
const timer = setInterval(() => {
|
|
29
|
+
this.runCheck(check.name);
|
|
30
|
+
}, interval);
|
|
31
|
+
this.intervals.set(check.name, timer);
|
|
32
|
+
this.logger.info(`[HealthManager] Registered health check: ${check.name}`, {
|
|
33
|
+
type: check.type,
|
|
34
|
+
interval,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run a health check
|
|
39
|
+
*/
|
|
40
|
+
async runCheck(name) {
|
|
41
|
+
const check = this.checks.get(name);
|
|
42
|
+
if (!check)
|
|
43
|
+
return;
|
|
44
|
+
const startTime = Date.now();
|
|
45
|
+
const timeout = check.timeout || 5000;
|
|
46
|
+
try {
|
|
47
|
+
let result;
|
|
48
|
+
switch (check.type) {
|
|
49
|
+
case 'http':
|
|
50
|
+
result = await this.runHttpCheck(check, timeout);
|
|
51
|
+
break;
|
|
52
|
+
case 'tcp':
|
|
53
|
+
result = await this.runTcpCheck(check, timeout);
|
|
54
|
+
break;
|
|
55
|
+
case 'custom':
|
|
56
|
+
if (check.check) {
|
|
57
|
+
result = await Promise.race([
|
|
58
|
+
check.check(),
|
|
59
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout)),
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
result = { healthy: false, details: { error: 'No check function provided' } };
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
result = { healthy: false, details: { error: 'Unknown check type' } };
|
|
68
|
+
}
|
|
69
|
+
const latency = result.latency || Date.now() - startTime;
|
|
70
|
+
this.results.set(name, {
|
|
71
|
+
status: result.healthy ? 'healthy' : 'unhealthy',
|
|
72
|
+
latency,
|
|
73
|
+
lastChecked: new Date(),
|
|
74
|
+
details: result.details,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
const latency = Date.now() - startTime;
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
this.results.set(name, {
|
|
81
|
+
status: 'unhealthy',
|
|
82
|
+
latency,
|
|
83
|
+
message,
|
|
84
|
+
lastChecked: new Date(),
|
|
85
|
+
});
|
|
86
|
+
this.logger.warn(`[HealthManager] Health check failed: ${name}`, {
|
|
87
|
+
error: message,
|
|
88
|
+
latency,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Run HTTP health check
|
|
94
|
+
*/
|
|
95
|
+
async runHttpCheck(check, timeout) {
|
|
96
|
+
if (!check.url) {
|
|
97
|
+
return { healthy: false, details: { error: 'No URL provided' } };
|
|
98
|
+
}
|
|
99
|
+
const controller = new AbortController();
|
|
100
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
101
|
+
try {
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
const response = await fetch(check.url, {
|
|
104
|
+
method: 'GET',
|
|
105
|
+
signal: controller.signal,
|
|
106
|
+
});
|
|
107
|
+
const latency = Date.now() - startTime;
|
|
108
|
+
clearTimeout(timeoutId);
|
|
109
|
+
return {
|
|
110
|
+
healthy: response.ok,
|
|
111
|
+
latency,
|
|
112
|
+
details: {
|
|
113
|
+
status: response.status,
|
|
114
|
+
statusText: response.statusText,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
clearTimeout(timeoutId);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Run TCP health check (simplified - just tries to connect)
|
|
125
|
+
*/
|
|
126
|
+
async runTcpCheck(check, timeout) {
|
|
127
|
+
if (!check.host || !check.port) {
|
|
128
|
+
return { healthy: false, details: { error: 'Host and port required for TCP check' } };
|
|
129
|
+
}
|
|
130
|
+
// Use HTTP check as a proxy for TCP (simplified for browser compatibility)
|
|
131
|
+
// In a real Node.js environment, you'd use net.createConnection
|
|
132
|
+
const url = `http://${check.host}:${check.port}`;
|
|
133
|
+
try {
|
|
134
|
+
return await this.runHttpCheck({ ...check, url }, timeout);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// TCP check failed
|
|
138
|
+
return {
|
|
139
|
+
healthy: false,
|
|
140
|
+
details: { error: `Cannot connect to ${check.host}:${check.port}` },
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get all health check results
|
|
146
|
+
*/
|
|
147
|
+
getResults() {
|
|
148
|
+
return Object.fromEntries(this.results);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get specific health check result
|
|
152
|
+
*/
|
|
153
|
+
getResult(name) {
|
|
154
|
+
return this.results.get(name);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get aggregated status
|
|
158
|
+
*/
|
|
159
|
+
getAggregatedStatus() {
|
|
160
|
+
const results = Array.from(this.results.values());
|
|
161
|
+
if (results.length === 0)
|
|
162
|
+
return 'unknown';
|
|
163
|
+
const unhealthyCount = results.filter((r) => r.status === 'unhealthy').length;
|
|
164
|
+
const degradedCount = results.filter((r) => r.status === 'degraded').length;
|
|
165
|
+
if (unhealthyCount > 0)
|
|
166
|
+
return 'unhealthy';
|
|
167
|
+
if (degradedCount > 0)
|
|
168
|
+
return 'degraded';
|
|
169
|
+
const hasUnknown = results.some((r) => r.status === 'unknown');
|
|
170
|
+
if (hasUnknown)
|
|
171
|
+
return 'unknown';
|
|
172
|
+
return 'healthy';
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Force run all checks
|
|
176
|
+
*/
|
|
177
|
+
async checkAll() {
|
|
178
|
+
const promises = Array.from(this.checks.keys()).map((name) => this.runCheck(name));
|
|
179
|
+
await Promise.all(promises);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Shutdown - clear all intervals
|
|
183
|
+
*/
|
|
184
|
+
shutdown() {
|
|
185
|
+
for (const timer of this.intervals.values()) {
|
|
186
|
+
clearInterval(timer);
|
|
187
|
+
}
|
|
188
|
+
this.intervals.clear();
|
|
189
|
+
this.logger.info('[HealthManager] Shutdown complete');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=health-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-manager.js","sourceRoot":"","sources":["../../src/core/health-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,OAAO,aAAa;IAMxB,YAAY,MAAc;QALlB,WAAM,GAA6B,IAAI,GAAG,EAAE,CAAC;QAC7C,YAAO,GAAmC,IAAI,GAAG,EAAE,CAAC;QACpD,cAAS,GAAgD,IAAI,GAAG,EAAE,CAAC;QAIzE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,KAAkB;QACzB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAEnC,oBAAoB;QACpB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;YAC3B,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,IAAI,IAAI,EAAE;SACxB,CAAC,CAAC;QAEH,uBAAuB;QACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,CAAC,qBAAqB;QAC/D,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE1B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,EAAE,QAAQ,CAAC,CAAC;QAEb,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAEtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,KAAK,CAAC,IAAI,EAAE,EAAE;YACzE,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,QAAQ,CAAC,IAAY;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC;QAEtC,IAAI,CAAC;YACH,IAAI,MAAiF,CAAC;YAEtF,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,MAAM;oBACT,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;oBACjD,MAAM;gBACR,KAAK,KAAK;oBACR,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;oBAChD,MAAM;gBACR,KAAK,QAAQ;oBACX,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;wBAChB,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;4BAC1B,KAAK,CAAC,KAAK,EAAE;4BACb,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CACxD;yBACF,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,MAAM,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,EAAE,CAAC;oBAChF,CAAC;oBACD,MAAM;gBACR;oBACE,MAAM,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,CAAC;YAC1E,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAEzD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE;gBACrB,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;gBAChD,OAAO;gBACP,WAAW,EAAE,IAAI,IAAI,EAAE;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YACvC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEvE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE;gBACrB,MAAM,EAAE,WAAW;gBACnB,OAAO;gBACP,OAAO;gBACP,WAAW,EAAE,IAAI,IAAI,EAAE;aACxB,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,IAAI,EAAE,EAAE;gBAC/D,KAAK,EAAE,OAAO;gBACd,OAAO;aACR,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,YAAY,CACxB,KAAkB,EAClB,OAAe;QAEf,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC;QACnE,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;QAEhE,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE;gBACtC,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAEvC,YAAY,CAAC,SAAS,CAAC,CAAC;YAExB,OAAO;gBACL,OAAO,EAAE,QAAQ,CAAC,EAAE;gBACpB,OAAO;gBACP,OAAO,EAAE;oBACP,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;iBAChC;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,WAAW,CACvB,KAAkB,EAClB,OAAe;QAEf,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAC/B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,sCAAsC,EAAE,EAAE,CAAC;QACxF,CAAC;QAED,2EAA2E;QAC3E,gEAAgE;QAChE,MAAM,GAAG,GAAG,UAAU,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAEjD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;YACnB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,EAAE,KAAK,EAAE,qBAAqB,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE;aACpE,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAElD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAE3C,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;QAC9E,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;QAE5E,IAAI,cAAc,GAAG,CAAC;YAAE,OAAO,WAAW,CAAC;QAC3C,IAAI,aAAa,GAAG,CAAC;YAAE,OAAO,UAAU,CAAC;QAEzC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC/D,IAAI,UAAU;YAAE,OAAO,SAAS,CAAC;QAEjC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ;QACZ,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACnF,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IACxD,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core exports for @qwickapps/server
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
5
|
+
*/
|
|
6
|
+
export { createControlPanel } from './control-panel.js';
|
|
7
|
+
export type { CreateControlPanelOptions } from './control-panel.js';
|
|
8
|
+
export { HealthManager } from './health-manager.js';
|
|
9
|
+
export type { ControlPanelConfig, ControlPanelPlugin, ControlPanelInstance, PluginContext, HealthCheck, HealthCheckType, HealthStatus, HealthCheckResult, LogSource, ConfigDisplayOptions, Logger, DiagnosticsReport, } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,WAAW,EACX,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,oBAAoB,EACpB,MAAM,EACN,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Panel Logging Subsystem
|
|
3
|
+
*
|
|
4
|
+
* Provides centralized logging for the control panel and all plugins.
|
|
5
|
+
* Configures @qwickapps/logging to write to files that the LogsPage can display.
|
|
6
|
+
*
|
|
7
|
+
* Environment Variables:
|
|
8
|
+
* LOG_LEVEL - Minimum log level (debug, info, warn, error). Default: debug in dev, info in prod
|
|
9
|
+
* LOG_DIR - Directory for log files. Default: ./logs
|
|
10
|
+
* LOG_FILE - Enable file logging. Default: true
|
|
11
|
+
* LOG_FILE_PATH - Path to log file. Default: ./logs/app.log (used by pino if available)
|
|
12
|
+
* LOG_CONSOLE - Enable console output. Default: true
|
|
13
|
+
*
|
|
14
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
15
|
+
*/
|
|
16
|
+
import { LogLevel } from '@qwickapps/logging';
|
|
17
|
+
import type { Logger } from './types.js';
|
|
18
|
+
export interface LoggingConfig {
|
|
19
|
+
/** Product namespace for log entries */
|
|
20
|
+
namespace?: string;
|
|
21
|
+
/** Minimum log level */
|
|
22
|
+
level?: LogLevel;
|
|
23
|
+
/** Directory for log files */
|
|
24
|
+
logDir?: string;
|
|
25
|
+
/** Enable file logging */
|
|
26
|
+
fileLogging?: boolean;
|
|
27
|
+
/** Enable console output */
|
|
28
|
+
consoleOutput?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Logging subsystem instance
|
|
32
|
+
*/
|
|
33
|
+
declare class LoggingSubsystem {
|
|
34
|
+
private config;
|
|
35
|
+
private rootLogger;
|
|
36
|
+
private fileTransport;
|
|
37
|
+
private initialized;
|
|
38
|
+
constructor();
|
|
39
|
+
/**
|
|
40
|
+
* Initialize the logging subsystem with configuration
|
|
41
|
+
*/
|
|
42
|
+
initialize(config?: LoggingConfig): void;
|
|
43
|
+
/**
|
|
44
|
+
* Get a logger for a specific component/plugin
|
|
45
|
+
*/
|
|
46
|
+
getLogger(namespace: string): Logger;
|
|
47
|
+
/**
|
|
48
|
+
* Get the root logger
|
|
49
|
+
*/
|
|
50
|
+
getRootLogger(): Logger;
|
|
51
|
+
/**
|
|
52
|
+
* Check if file logging is enabled and working
|
|
53
|
+
*/
|
|
54
|
+
isFileLoggingEnabled(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Get the log directory path
|
|
57
|
+
*/
|
|
58
|
+
getLogDir(): string;
|
|
59
|
+
/**
|
|
60
|
+
* Get the default log file paths
|
|
61
|
+
*/
|
|
62
|
+
getLogPaths(): {
|
|
63
|
+
appLog: string;
|
|
64
|
+
errorLog: string;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get or create the logging subsystem
|
|
69
|
+
*/
|
|
70
|
+
export declare function getLoggingSubsystem(): LoggingSubsystem;
|
|
71
|
+
/**
|
|
72
|
+
* Initialize the logging subsystem with configuration
|
|
73
|
+
*/
|
|
74
|
+
export declare function initializeLogging(config?: LoggingConfig): LoggingSubsystem;
|
|
75
|
+
/**
|
|
76
|
+
* Get a logger for a specific namespace
|
|
77
|
+
*/
|
|
78
|
+
export declare function getControlPanelLogger(namespace: string): Logger;
|
|
79
|
+
/**
|
|
80
|
+
* Export for convenience
|
|
81
|
+
*/
|
|
82
|
+
export { LoggingSubsystem };
|
|
83
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/core/logging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAoC,QAAQ,EAAgB,MAAM,oBAAoB,CAAC;AAC9F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAyDD;;GAEG;AACH,cAAM,gBAAgB;IACpB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,WAAW,CAAS;;IAO5B;;OAEG;IACH,UAAU,CAAC,MAAM,GAAE,aAAkB,GAAG,IAAI;IAwC5C;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAoBpC;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAI/B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,WAAW,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;CAMpD;AAKD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAKtD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,GAAE,aAAkB,GAAG,gBAAgB,CAI9E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;GAEG;AACH,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|