@manojkmfsi/monodog 1.0.25 → 1.1.1
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/config/swagger-config.js +345 -0
- package/dist/config-loader.js +2 -2
- package/dist/constants/index.js +26 -0
- package/dist/constants/middleware.js +71 -0
- package/dist/constants/port.js +20 -0
- package/dist/constants/security.js +67 -0
- package/dist/middleware/dashboard-startup.js +15 -18
- package/dist/middleware/security.js +10 -9
- package/dist/middleware/server-startup.js +12 -11
- package/dist/middleware/swagger-middleware.js +54 -0
- package/dist/routes/health-routes.js +1 -1
- package/dist/routes/package-routes.js +1 -1
- package/dist/services/health-service.js +84 -64
- package/dist/services/package-service.js +23 -1
- package/monodog-config.example.json +2 -2
- package/monodog-config.json +5 -4
- package/monodog-dashboard/dist/assets/{index-746f6c13.js → index-45e19f29.js} +1 -1
- package/monodog-dashboard/dist/index.html +1 -1
- package/package.json +5 -2
- package/src/config/swagger-config.ts +344 -0
- package/src/config-loader.ts +2 -2
- package/src/constants/index.ts +13 -0
- package/src/constants/middleware.ts +83 -0
- package/src/constants/port.ts +20 -0
- package/src/constants/security.ts +78 -0
- package/src/middleware/dashboard-startup.ts +30 -18
- package/src/middleware/security.ts +18 -9
- package/src/middleware/server-startup.ts +22 -11
- package/src/middleware/swagger-middleware.ts +57 -0
- package/src/routes/health-routes.ts +1 -1
- package/src/routes/package-routes.ts +1 -1
- package/src/services/health-service.ts +103 -79
- package/src/services/package-service.ts +27 -1
- package/src/types/swagger-jsdoc.d.ts +15 -0
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -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
|
+
};
|
package/dist/config-loader.js
CHANGED
|
@@ -83,11 +83,11 @@ function createConfigFileIfMissing(rootPath) {
|
|
|
83
83
|
path: 'file:./monodog.db', // SQLite database file path, relative to prisma schema location
|
|
84
84
|
},
|
|
85
85
|
dashboard: {
|
|
86
|
-
host: '
|
|
86
|
+
host: 'localhost',
|
|
87
87
|
port: '3010',
|
|
88
88
|
},
|
|
89
89
|
server: {
|
|
90
|
-
host: '
|
|
90
|
+
host: 'localhost', // Default host for the API server
|
|
91
91
|
port: 8999, // Default port for the API server
|
|
92
92
|
},
|
|
93
93
|
};
|
|
@@ -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 = 'localhost';
|
|
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';
|
|
@@ -13,16 +13,14 @@ const logger_1 = require("./logger");
|
|
|
13
13
|
const config_loader_1 = require("../config-loader");
|
|
14
14
|
const error_handler_1 = require("./error-handler");
|
|
15
15
|
const security_1 = require("./security");
|
|
16
|
-
|
|
17
|
-
const PORT_MIN = 1024;
|
|
18
|
-
const PORT_MAX = 65535;
|
|
16
|
+
const constants_1 = require("../constants");
|
|
19
17
|
/**
|
|
20
18
|
* Validate port number
|
|
21
19
|
*/
|
|
22
20
|
function validatePort(port) {
|
|
23
21
|
const portNum = typeof port === 'string' ? parseInt(port, 10) : port;
|
|
24
|
-
if (isNaN(portNum) || portNum < PORT_MIN || portNum > PORT_MAX) {
|
|
25
|
-
throw new Error(
|
|
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));
|
|
26
24
|
}
|
|
27
25
|
return portNum;
|
|
28
26
|
}
|
|
@@ -42,27 +40,26 @@ function createDashboardApp() {
|
|
|
42
40
|
app.use((0, security_1.createDashboardCorsMiddleware)());
|
|
43
41
|
// Environment config endpoint
|
|
44
42
|
app.get('/env-config.js', (_req, res) => {
|
|
45
|
-
res.setHeader('Content-Type',
|
|
46
|
-
res.setHeader('Cache-Control',
|
|
43
|
+
res.setHeader('Content-Type', constants_1.CONTENT_TYPE_JAVASCRIPT);
|
|
44
|
+
res.setHeader('Cache-Control', constants_1.CACHE_CONTROL_NO_CACHE);
|
|
47
45
|
res.send(`window.ENV = { API_URL: "${apiUrl}" };`);
|
|
48
46
|
});
|
|
49
47
|
// Request logging
|
|
50
48
|
app.use(logger_1.httpLogger);
|
|
51
|
-
// app.use(requestLogger);
|
|
52
49
|
// SPA routing: serve index.html for non-static routes
|
|
53
50
|
app.use((_req, _res, next) => {
|
|
54
|
-
if (
|
|
51
|
+
if (constants_1.STATIC_FILE_PATTERN.test(_req.path)) {
|
|
55
52
|
next();
|
|
56
53
|
}
|
|
57
54
|
else {
|
|
58
|
-
_res.header('Cache-Control',
|
|
59
|
-
_res.header('Expires',
|
|
60
|
-
_res.header('Pragma',
|
|
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);
|
|
61
58
|
_res.sendFile('index.html', {
|
|
62
59
|
root: path_1.default.resolve(__dirname, '..', '..', 'monodog-dashboard', 'dist'),
|
|
63
60
|
}, (err) => {
|
|
64
61
|
if (err) {
|
|
65
|
-
logger_1.AppLogger.error(
|
|
62
|
+
logger_1.AppLogger.error(constants_1.ERROR_SERVING_INDEX_HTML, err);
|
|
66
63
|
_res.status(500).json({ error: 'Internal server error' });
|
|
67
64
|
}
|
|
68
65
|
});
|
|
@@ -90,16 +87,16 @@ function serveDashboard(rootPath) {
|
|
|
90
87
|
const validatedPort = validatePort(port);
|
|
91
88
|
const app = createDashboardApp();
|
|
92
89
|
const server = app.listen(validatedPort, host, () => {
|
|
93
|
-
console.log(
|
|
90
|
+
console.log((0, constants_1.SUCCESS_DASHBOARD_START)(host, validatedPort));
|
|
94
91
|
console.log('Press Ctrl+C to quit.');
|
|
95
92
|
});
|
|
96
93
|
server.on('error', (err) => {
|
|
97
94
|
if (err.code === 'EADDRINUSE') {
|
|
98
|
-
logger_1.AppLogger.error(
|
|
95
|
+
logger_1.AppLogger.error((0, constants_1.ERROR_PORT_IN_USE)(validatedPort), err);
|
|
99
96
|
process.exit(1);
|
|
100
97
|
}
|
|
101
98
|
else if (err.code === 'EACCES') {
|
|
102
|
-
logger_1.AppLogger.error(
|
|
99
|
+
logger_1.AppLogger.error((0, constants_1.ERROR_PERMISSION_DENIED)(validatedPort), err);
|
|
103
100
|
process.exit(1);
|
|
104
101
|
}
|
|
105
102
|
else {
|
|
@@ -109,9 +106,9 @@ function serveDashboard(rootPath) {
|
|
|
109
106
|
});
|
|
110
107
|
// Graceful shutdown
|
|
111
108
|
process.on('SIGTERM', () => {
|
|
112
|
-
logger_1.AppLogger.info(
|
|
109
|
+
logger_1.AppLogger.info(constants_1.MESSAGE_DASHBOARD_GRACEFUL_SHUTDOWN);
|
|
113
110
|
server.close(() => {
|
|
114
|
-
logger_1.AppLogger.info(
|
|
111
|
+
logger_1.AppLogger.info(constants_1.MESSAGE_DASHBOARD_CLOSED);
|
|
115
112
|
process.exit(0);
|
|
116
113
|
});
|
|
117
114
|
});
|