@manojkmfsi/monodog 1.0.24 → 1.1.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.
Files changed (48) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/config/swagger-config.js +345 -0
  4. package/dist/constants/index.js +26 -0
  5. package/dist/constants/middleware.js +71 -0
  6. package/dist/constants/port.js +20 -0
  7. package/dist/constants/security.js +67 -0
  8. package/dist/middleware/dashboard-startup.js +20 -21
  9. package/dist/middleware/error-handler.js +3 -10
  10. package/dist/middleware/index.js +4 -2
  11. package/dist/middleware/logger.js +63 -0
  12. package/dist/middleware/security.js +11 -10
  13. package/dist/middleware/server-startup.js +32 -25
  14. package/dist/middleware/swagger-middleware.js +54 -0
  15. package/dist/routes/health-routes.js +1 -1
  16. package/dist/routes/package-routes.js +1 -1
  17. package/dist/serve.js +15 -2
  18. package/dist/services/health-service.js +84 -64
  19. package/dist/services/package-service.js +23 -1
  20. package/monodog-dashboard/dist/assets/{index-746f6c13.js → index-45e19f29.js} +1 -1
  21. package/monodog-dashboard/dist/index.html +1 -1
  22. package/package.json +14 -4
  23. package/prisma/schema/commit.prisma +11 -0
  24. package/prisma/schema/dependency-info.prisma +12 -0
  25. package/prisma/schema/health-status.prisma +14 -0
  26. package/prisma/schema/package-health.prisma +15 -0
  27. package/prisma/schema/package.prisma +21 -0
  28. package/prisma/schema/schema.prisma +15 -0
  29. package/src/config/swagger-config.ts +344 -0
  30. package/src/constants/index.ts +13 -0
  31. package/src/constants/middleware.ts +83 -0
  32. package/src/constants/port.ts +20 -0
  33. package/src/constants/security.ts +78 -0
  34. package/src/middleware/dashboard-startup.ts +35 -24
  35. package/src/middleware/error-handler.ts +2 -15
  36. package/src/middleware/index.ts +3 -1
  37. package/src/middleware/logger.ts +58 -0
  38. package/src/middleware/security.ts +19 -10
  39. package/src/middleware/server-startup.ts +43 -30
  40. package/src/middleware/swagger-middleware.ts +57 -0
  41. package/src/routes/health-routes.ts +1 -1
  42. package/src/routes/package-routes.ts +1 -1
  43. package/src/serve.ts +19 -3
  44. package/src/services/health-service.ts +103 -79
  45. package/src/services/package-service.ts +27 -1
  46. package/src/types/swagger-jsdoc.d.ts +15 -0
  47. package/prisma/schema.prisma +0 -116
  48. /package/prisma/migrations/{20251219074511_create_unique_composite_key_for_commits → 20251219090102_composite_key_for_table_commits}/migration.sql +0 -0
@@ -1,4 +1,4 @@
1
1
 
2
- > @manojkmfsi/monodog@1.0.24 build /home/runner/work/monodog/monodog/packages/monoapp
2
+ > @manojkmfsi/monodog@1.1.0 build /home/runner/work/monodog/monodog/packages/monoapp
3
3
  > rm -rf dist && tsc
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @manojkmfsi/monoapp
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added Swagger doc, updated req type for resfresh
8
+
9
+ ## 1.0.25
10
+
11
+ ### Patch Changes
12
+
13
+ - Added morgan and split prisma schema
14
+
3
15
  ## 1.0.24
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,345 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.swaggerOptions = exports.swaggerDefinition = void 0;
4
+ /**
5
+ * Swagger API Documentation Configuration
6
+ * Defines OpenAPI specification for MonoDog API
7
+ */
8
+ const config_loader_1 = require("../config-loader");
9
+ exports.swaggerDefinition = {
10
+ openapi: '3.0.0',
11
+ info: {
12
+ title: 'MonoDog API',
13
+ version: '1.0.0',
14
+ description: 'Monorepo Analytics and Health Dashboard API',
15
+ contact: {
16
+ name: 'MonoDog Team',
17
+ url: 'https://github.com/mindfiredigital/monodog',
18
+ },
19
+ license: {
20
+ name: 'MIT',
21
+ url: 'https://opensource.org/licenses/MIT',
22
+ },
23
+ },
24
+ servers: [
25
+ {
26
+ url: `http://${config_loader_1.appConfig.server.host}:${config_loader_1.appConfig.server.port}/api`,
27
+ description: 'Development server',
28
+ },
29
+ ],
30
+ paths: {
31
+ '/packages': {
32
+ get: {
33
+ tags: ['Packages'],
34
+ summary: 'Get all packages',
35
+ operationId: 'getPackages',
36
+ responses: {
37
+ '200': {
38
+ description: 'List of packages',
39
+ content: {
40
+ 'application/json': {
41
+ schema: { type: 'array', items: { $ref: '#/components/schemas/Package' } },
42
+ },
43
+ },
44
+ },
45
+ '500': { description: 'Internal server error' },
46
+ },
47
+ },
48
+ },
49
+ '/packages/{name}': {
50
+ get: {
51
+ tags: ['Packages'],
52
+ summary: 'Get package by name',
53
+ operationId: 'getPackageByName',
54
+ parameters: [{ name: 'name', in: 'path', required: true, schema: { type: 'string' } }],
55
+ responses: {
56
+ '200': {
57
+ description: 'Package details',
58
+ content: {
59
+ 'application/json': {
60
+ schema: { $ref: '#/components/schemas/Package' },
61
+ },
62
+ },
63
+ },
64
+ '404': { description: 'Package not found' },
65
+ },
66
+ },
67
+ },
68
+ '/packages/refresh': {
69
+ post: {
70
+ tags: ['Packages'],
71
+ summary: 'Refresh packages',
72
+ operationId: 'refreshPackages',
73
+ responses: {
74
+ '200': { description: 'Packages refreshed successfully' },
75
+ },
76
+ },
77
+ },
78
+ '/packages/update-config': {
79
+ put: {
80
+ tags: ['Packages'],
81
+ summary: 'Update package configuration',
82
+ operationId: 'updatePackageConfig',
83
+ requestBody: {
84
+ required: true,
85
+ content: {
86
+ 'application/json': {
87
+ schema: { $ref: '#/components/schemas/Package' },
88
+ },
89
+ },
90
+ },
91
+ responses: {
92
+ '200': { description: 'Package configuration updated successfully' },
93
+ '400': { description: 'Invalid request' },
94
+ '404': { description: 'Package not found' },
95
+ },
96
+ },
97
+ },
98
+ '/health/packages': {
99
+ get: {
100
+ tags: ['Health'],
101
+ summary: 'Get packages health status',
102
+ operationId: 'getPackagesHealth',
103
+ responses: {
104
+ '200': {
105
+ description: 'Health status of all packages',
106
+ content: {
107
+ 'application/json': {
108
+ schema: { type: 'array', items: { $ref: '#/components/schemas/PackageHealth' } },
109
+ },
110
+ },
111
+ },
112
+ },
113
+ },
114
+ },
115
+ '/health/refresh': {
116
+ post: {
117
+ tags: ['Health'],
118
+ summary: 'Refresh health status',
119
+ operationId: 'refreshHealth',
120
+ responses: {
121
+ '200': { description: 'Health status refreshed successfully' },
122
+ },
123
+ },
124
+ },
125
+ '/commits/{packagePath}': {
126
+ get: {
127
+ tags: ['Commits'],
128
+ summary: 'Get commits for a package',
129
+ operationId: 'getCommits',
130
+ parameters: [{ name: 'packagePath', in: 'path', required: true, schema: { type: 'string' } }],
131
+ responses: {
132
+ '200': {
133
+ description: 'List of commits',
134
+ content: {
135
+ 'application/json': {
136
+ schema: { type: 'array', items: { $ref: '#/components/schemas/Commit' } },
137
+ },
138
+ },
139
+ },
140
+ },
141
+ },
142
+ },
143
+ '/config/files': {
144
+ get: {
145
+ tags: ['Configuration'],
146
+ summary: 'Get configuration files',
147
+ operationId: 'getConfigFiles',
148
+ responses: {
149
+ '200': {
150
+ description: 'List of configuration files',
151
+ content: {
152
+ 'application/json': {
153
+ schema: { type: 'array', items: { $ref: '#/components/schemas/ConfigFile' } },
154
+ },
155
+ },
156
+ },
157
+ },
158
+ },
159
+ },
160
+ '/config/files/{id}': {
161
+ put: {
162
+ tags: ['Configuration'],
163
+ summary: 'Update configuration file',
164
+ operationId: 'updateConfigFile',
165
+ parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }],
166
+ requestBody: {
167
+ required: true,
168
+ content: {
169
+ 'application/json': {
170
+ schema: { $ref: '#/components/schemas/ConfigFile' },
171
+ },
172
+ },
173
+ },
174
+ responses: {
175
+ '200': { description: 'Configuration file updated successfully' },
176
+ '400': { description: 'Invalid request' },
177
+ '404': { description: 'Configuration file not found' },
178
+ },
179
+ },
180
+ },
181
+ },
182
+ tags: [
183
+ {
184
+ name: 'Packages',
185
+ description: 'Package management and analysis endpoints',
186
+ },
187
+ {
188
+ name: 'Health',
189
+ description: 'Health monitoring and status endpoints',
190
+ },
191
+ {
192
+ name: 'Commits',
193
+ description: 'Git commit history and analysis endpoints',
194
+ },
195
+ {
196
+ name: 'Configuration',
197
+ description: 'Configuration file management endpoints',
198
+ },
199
+ ],
200
+ components: {
201
+ schemas: {
202
+ Package: {
203
+ type: 'object',
204
+ properties: {
205
+ name: {
206
+ type: 'string',
207
+ description: 'Package name',
208
+ },
209
+ path: {
210
+ type: 'string',
211
+ description: 'Package path in monorepo',
212
+ },
213
+ version: {
214
+ type: 'string',
215
+ description: 'Package version',
216
+ },
217
+ size: {
218
+ type: 'number',
219
+ description: 'Package size in bytes',
220
+ },
221
+ dependencies: {
222
+ type: 'array',
223
+ items: {
224
+ type: 'string',
225
+ },
226
+ description: 'List of package dependencies',
227
+ },
228
+ },
229
+ },
230
+ PackageHealth: {
231
+ type: 'object',
232
+ properties: {
233
+ packageName: {
234
+ type: 'string',
235
+ description: 'Name of the package',
236
+ },
237
+ healthScore: {
238
+ type: 'number',
239
+ description: 'Health score (0-100)',
240
+ minimum: 0,
241
+ maximum: 100,
242
+ },
243
+ lintStatus: {
244
+ type: 'string',
245
+ enum: ['pass', 'warning', 'fail'],
246
+ description: 'Linting status',
247
+ },
248
+ buildStatus: {
249
+ type: 'string',
250
+ enum: ['success', 'failed', 'pending'],
251
+ description: 'Build status',
252
+ },
253
+ securityStatus: {
254
+ type: 'string',
255
+ enum: ['secure', 'warning', 'vulnerable'],
256
+ description: 'Security status',
257
+ },
258
+ testCoverage: {
259
+ type: 'number',
260
+ description: 'Test coverage percentage',
261
+ },
262
+ },
263
+ },
264
+ Commit: {
265
+ type: 'object',
266
+ properties: {
267
+ hash: {
268
+ type: 'string',
269
+ description: 'Commit hash',
270
+ },
271
+ author: {
272
+ type: 'string',
273
+ description: 'Commit author',
274
+ },
275
+ message: {
276
+ type: 'string',
277
+ description: 'Commit message',
278
+ },
279
+ date: {
280
+ type: 'string',
281
+ format: 'date-time',
282
+ description: 'Commit date',
283
+ },
284
+ filesChanged: {
285
+ type: 'number',
286
+ description: 'Number of files changed',
287
+ },
288
+ },
289
+ },
290
+ ConfigFile: {
291
+ type: 'object',
292
+ properties: {
293
+ id: {
294
+ type: 'string',
295
+ description: 'Configuration file ID',
296
+ },
297
+ name: {
298
+ type: 'string',
299
+ description: 'Configuration file name',
300
+ },
301
+ path: {
302
+ type: 'string',
303
+ description: 'Configuration file path',
304
+ },
305
+ content: {
306
+ type: 'string',
307
+ description: 'Configuration file content',
308
+ },
309
+ },
310
+ },
311
+ Error: {
312
+ type: 'object',
313
+ properties: {
314
+ error: {
315
+ type: 'string',
316
+ description: 'Error message',
317
+ },
318
+ message: {
319
+ type: 'string',
320
+ description: 'Detailed error message',
321
+ },
322
+ code: {
323
+ type: 'string',
324
+ description: 'Error code',
325
+ },
326
+ },
327
+ },
328
+ },
329
+ responses: {
330
+ UnauthorizedError: {
331
+ description: 'Unauthorized access',
332
+ },
333
+ NotFoundError: {
334
+ description: 'Resource not found',
335
+ },
336
+ InternalServerError: {
337
+ description: 'Internal server error',
338
+ },
339
+ },
340
+ },
341
+ };
342
+ exports.swaggerOptions = {
343
+ definition: exports.swaggerDefinition,
344
+ apis: [], // Using only definition, no JSDoc file scanning
345
+ };
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /**
3
+ * Constants Index
4
+ * Centralized export of all application constants
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ // Port constants
22
+ __exportStar(require("./port"), exports);
23
+ // Security constants
24
+ __exportStar(require("./security"), exports);
25
+ // Middleware constants
26
+ __exportStar(require("./middleware"), exports);
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Middleware Constants
4
+ * Defines constants used across middleware modules
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MESSAGE_SHUTDOWN_INSTRUCTION = exports.ERROR_SERVING_INDEX_HTML = exports.CONTENT_TYPE_JAVASCRIPT = exports.MESSAGE_DASHBOARD_CLOSED = exports.MESSAGE_DASHBOARD_GRACEFUL_SHUTDOWN = exports.MESSAGE_SERVER_CLOSED = exports.MESSAGE_GRACEFUL_SHUTDOWN = exports.SUCCESS_DASHBOARD_START = exports.SUCCESS_SERVER_START = exports.ERROR_INTERNAL_SERVER = exports.ERROR_PERMISSION_DENIED = exports.ERROR_PORT_IN_USE = exports.HTTP_STATUS_BAD_REQUEST = exports.HTTP_STATUS_NOT_FOUND = exports.HTTP_STATUS_INTERNAL_SERVER_ERROR = void 0;
8
+ /**
9
+ * HTTP status code for internal server error
10
+ */
11
+ exports.HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;
12
+ /**
13
+ * HTTP status code for not found
14
+ */
15
+ exports.HTTP_STATUS_NOT_FOUND = 404;
16
+ /**
17
+ * HTTP status code for bad request
18
+ */
19
+ exports.HTTP_STATUS_BAD_REQUEST = 400;
20
+ /**
21
+ * Error message for port already in use
22
+ */
23
+ const ERROR_PORT_IN_USE = (port) => `Port ${port} is already in use. Please specify a different port.`;
24
+ exports.ERROR_PORT_IN_USE = ERROR_PORT_IN_USE;
25
+ /**
26
+ * Error message for permission denied
27
+ */
28
+ const ERROR_PERMISSION_DENIED = (port) => `Permission denied to listen on port ${port}. Use a port above 1024.`;
29
+ exports.ERROR_PERMISSION_DENIED = ERROR_PERMISSION_DENIED;
30
+ /**
31
+ * Error message for internal server error
32
+ */
33
+ exports.ERROR_INTERNAL_SERVER = 'Internal server error';
34
+ /**
35
+ * Success message for server start
36
+ */
37
+ const SUCCESS_SERVER_START = (host, port) => `Backend server listening on http://${host}:${port}`;
38
+ exports.SUCCESS_SERVER_START = SUCCESS_SERVER_START;
39
+ /**
40
+ * Success message for dashboard start
41
+ */
42
+ const SUCCESS_DASHBOARD_START = (host, port) => `Dashboard listening on http://${host}:${port}`;
43
+ exports.SUCCESS_DASHBOARD_START = SUCCESS_DASHBOARD_START;
44
+ /**
45
+ * Message for graceful shutdown
46
+ */
47
+ exports.MESSAGE_GRACEFUL_SHUTDOWN = 'SIGTERM signal received: closing HTTP server';
48
+ /**
49
+ * Message for server closed
50
+ */
51
+ exports.MESSAGE_SERVER_CLOSED = 'HTTP server closed';
52
+ /**
53
+ * Message for dashboard graceful shutdown
54
+ */
55
+ exports.MESSAGE_DASHBOARD_GRACEFUL_SHUTDOWN = 'SIGTERM signal received: closing dashboard server';
56
+ /**
57
+ * Message for dashboard closed
58
+ */
59
+ exports.MESSAGE_DASHBOARD_CLOSED = 'Dashboard server closed';
60
+ /**
61
+ * Content-Type header for JavaScript
62
+ */
63
+ exports.CONTENT_TYPE_JAVASCRIPT = 'application/javascript';
64
+ /**
65
+ * Error serving index.html message
66
+ */
67
+ exports.ERROR_SERVING_INDEX_HTML = 'Error serving index.html:';
68
+ /**
69
+ * Shutdown instruction message
70
+ */
71
+ exports.MESSAGE_SHUTDOWN_INSTRUCTION = 'Press Ctrl+C to quit.';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * Port Constants
4
+ * Defines valid port range and port-related configuration
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PORT_VALIDATION_ERROR_MESSAGE = exports.PORT_MAX = exports.PORT_MIN = void 0;
8
+ /**
9
+ * Minimum valid port number (above system reserved ports)
10
+ */
11
+ exports.PORT_MIN = 1024;
12
+ /**
13
+ * Maximum valid port number
14
+ */
15
+ exports.PORT_MAX = 65535;
16
+ /**
17
+ * Port validation error message
18
+ */
19
+ const PORT_VALIDATION_ERROR_MESSAGE = (min, max) => `Port must be between ${min} and ${max}`;
20
+ exports.PORT_VALIDATION_ERROR_MESSAGE = PORT_VALIDATION_ERROR_MESSAGE;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ /**
3
+ * Security Constants
4
+ * Defines security-related configuration and constants
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PRAGMA_HEADER = exports.EXPIRES_HEADER = exports.STATIC_FILE_PATTERN = exports.CSP_DIRECTIVES = exports.HTTP_PROTOCOL = exports.WILDCARD_ADDRESS = exports.DEFAULT_LOCALHOST = exports.CACHE_CONTROL_STATIC = exports.CACHE_CONTROL_NO_CACHE = exports.BODY_PARSER_LIMIT = exports.CORS_ALLOWED_HEADERS = exports.CORS_API_METHODS = exports.RESPONSE_TIMEOUT = exports.REQUEST_TIMEOUT = void 0;
8
+ /**
9
+ * Request timeout duration in milliseconds (30 seconds)
10
+ */
11
+ exports.REQUEST_TIMEOUT = 30000;
12
+ /**
13
+ * Response timeout duration in milliseconds (30 seconds)
14
+ */
15
+ exports.RESPONSE_TIMEOUT = 30000;
16
+ /**
17
+ * CORS methods allowed for API
18
+ */
19
+ exports.CORS_API_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'];
20
+ /**
21
+ * CORS headers allowed
22
+ */
23
+ exports.CORS_ALLOWED_HEADERS = ['Content-Type', 'Authorization'];
24
+ /**
25
+ * Body parser JSON size limit
26
+ */
27
+ exports.BODY_PARSER_LIMIT = '1mb';
28
+ /**
29
+ * Cache control header for no-cache responses
30
+ */
31
+ exports.CACHE_CONTROL_NO_CACHE = 'private, no-cache, no-store, must-revalidate';
32
+ /**
33
+ * Cache control header for static assets
34
+ */
35
+ exports.CACHE_CONTROL_STATIC = '1d';
36
+ /**
37
+ * Default localhost hostname
38
+ */
39
+ exports.DEFAULT_LOCALHOST = 'localhost';
40
+ /**
41
+ * Wildcard address for listening on all interfaces
42
+ */
43
+ exports.WILDCARD_ADDRESS = '0.0.0.0';
44
+ /**
45
+ * HTTP protocol prefix
46
+ */
47
+ exports.HTTP_PROTOCOL = 'http://';
48
+ /**
49
+ * CSP directives for Helmet
50
+ */
51
+ exports.CSP_DIRECTIVES = {
52
+ defaultSrc: ["'self'"],
53
+ scriptSrc: ["'self'"],
54
+ imgSrc: ["'self'", 'data:', 'https:'],
55
+ };
56
+ /**
57
+ * Static file extensions pattern
58
+ */
59
+ exports.STATIC_FILE_PATTERN = /(.ico|.js|.css|.jpg|.png|.map|.woff|.woff2|.ttf)$/i;
60
+ /**
61
+ * Expires header for no-cache responses
62
+ */
63
+ exports.EXPIRES_HEADER = '-1';
64
+ /**
65
+ * Pragma header for no-cache responses
66
+ */
67
+ exports.PRAGMA_HEADER = 'no-cache';
@@ -9,19 +9,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.serveDashboard = serveDashboard;
10
10
  const express_1 = __importDefault(require("express"));
11
11
  const path_1 = __importDefault(require("path"));
12
+ const logger_1 = require("./logger");
12
13
  const config_loader_1 = require("../config-loader");
13
14
  const error_handler_1 = require("./error-handler");
14
15
  const security_1 = require("./security");
15
- // Security constants
16
- const PORT_MIN = 1024;
17
- const PORT_MAX = 65535;
16
+ const constants_1 = require("../constants");
18
17
  /**
19
18
  * Validate port number
20
19
  */
21
20
  function validatePort(port) {
22
21
  const portNum = typeof port === 'string' ? parseInt(port, 10) : port;
23
- if (isNaN(portNum) || portNum < PORT_MIN || portNum > PORT_MAX) {
24
- throw new Error(`Port must be between ${PORT_MIN} and ${PORT_MAX}`);
22
+ if (isNaN(portNum) || portNum < constants_1.PORT_MIN || portNum > constants_1.PORT_MAX) {
23
+ throw new Error((0, constants_1.PORT_VALIDATION_ERROR_MESSAGE)(constants_1.PORT_MIN, constants_1.PORT_MAX));
25
24
  }
26
25
  return portNum;
27
26
  }
@@ -41,26 +40,26 @@ function createDashboardApp() {
41
40
  app.use((0, security_1.createDashboardCorsMiddleware)());
42
41
  // Environment config endpoint
43
42
  app.get('/env-config.js', (_req, res) => {
44
- res.setHeader('Content-Type', 'application/javascript');
45
- res.setHeader('Cache-Control', 'private, no-cache, no-store, must-revalidate');
43
+ res.setHeader('Content-Type', constants_1.CONTENT_TYPE_JAVASCRIPT);
44
+ res.setHeader('Cache-Control', constants_1.CACHE_CONTROL_NO_CACHE);
46
45
  res.send(`window.ENV = { API_URL: "${apiUrl}" };`);
47
46
  });
48
47
  // Request logging
49
- app.use(error_handler_1.requestLogger);
48
+ app.use(logger_1.httpLogger);
50
49
  // SPA routing: serve index.html for non-static routes
51
50
  app.use((_req, _res, next) => {
52
- if (/(.ico|.js|.css|.jpg|.png|.map|.woff|.woff2|.ttf)$/i.test(_req.path)) {
51
+ if (constants_1.STATIC_FILE_PATTERN.test(_req.path)) {
53
52
  next();
54
53
  }
55
54
  else {
56
- _res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
57
- _res.header('Expires', '-1');
58
- _res.header('Pragma', 'no-cache');
55
+ _res.header('Cache-Control', constants_1.CACHE_CONTROL_NO_CACHE);
56
+ _res.header('Expires', constants_1.EXPIRES_HEADER);
57
+ _res.header('Pragma', constants_1.PRAGMA_HEADER);
59
58
  _res.sendFile('index.html', {
60
59
  root: path_1.default.resolve(__dirname, '..', '..', 'monodog-dashboard', 'dist'),
61
60
  }, (err) => {
62
61
  if (err) {
63
- console.error('Error serving index.html:', err?.message);
62
+ logger_1.AppLogger.error(constants_1.ERROR_SERVING_INDEX_HTML, err);
64
63
  _res.status(500).json({ error: 'Internal server error' });
65
64
  }
66
65
  });
@@ -68,7 +67,7 @@ function createDashboardApp() {
68
67
  });
69
68
  // Static files
70
69
  const staticPath = path_1.default.join(__dirname, '..', '..', 'monodog-dashboard', 'dist');
71
- console.log('Serving static files from:', staticPath);
70
+ logger_1.AppLogger.debug('Serving static files from:', { path: staticPath });
72
71
  app.use(express_1.default.static(staticPath, {
73
72
  maxAge: '1d',
74
73
  etag: false,
@@ -88,35 +87,35 @@ function serveDashboard(rootPath) {
88
87
  const validatedPort = validatePort(port);
89
88
  const app = createDashboardApp();
90
89
  const server = app.listen(validatedPort, host, () => {
91
- console.log(`Dashboard listening on http://${host}:${validatedPort}`);
90
+ console.log((0, constants_1.SUCCESS_DASHBOARD_START)(host, validatedPort));
92
91
  console.log('Press Ctrl+C to quit.');
93
92
  });
94
93
  server.on('error', (err) => {
95
94
  if (err.code === 'EADDRINUSE') {
96
- console.error(`Error: Port ${validatedPort} is already in use.`);
95
+ logger_1.AppLogger.error((0, constants_1.ERROR_PORT_IN_USE)(validatedPort), err);
97
96
  process.exit(1);
98
97
  }
99
98
  else if (err.code === 'EACCES') {
100
- console.error(`Error: Permission denied to listen on port ${validatedPort}.`);
99
+ logger_1.AppLogger.error((0, constants_1.ERROR_PERMISSION_DENIED)(validatedPort), err);
101
100
  process.exit(1);
102
101
  }
103
102
  else {
104
- console.error('Server failed to start:', err.message);
103
+ logger_1.AppLogger.error('Server failed to start:', err);
105
104
  process.exit(1);
106
105
  }
107
106
  });
108
107
  // Graceful shutdown
109
108
  process.on('SIGTERM', () => {
110
- console.log('SIGTERM signal received: closing dashboard server');
109
+ logger_1.AppLogger.info(constants_1.MESSAGE_DASHBOARD_GRACEFUL_SHUTDOWN);
111
110
  server.close(() => {
112
- console.log('Dashboard server closed');
111
+ logger_1.AppLogger.info(constants_1.MESSAGE_DASHBOARD_CLOSED);
113
112
  process.exit(0);
114
113
  });
115
114
  });
116
115
  }
117
116
  catch (error) {
118
117
  const err = error;
119
- console.error('Failed to start dashboard:', err?.message || String(error));
118
+ logger_1.AppLogger.error('Failed to start dashboard:', err);
120
119
  process.exit(1);
121
120
  }
122
121
  }