@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
@@ -3,14 +3,15 @@
3
3
  * Error handling middleware for Express
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.requestLogger = exports.notFoundHandler = exports.errorHandler = void 0;
6
+ exports.notFoundHandler = exports.errorHandler = void 0;
7
+ const logger_1 = require("./logger");
7
8
  /**
8
9
  * Global error handler middleware
9
10
  * Must be registered last in the middleware chain
10
11
  */
11
12
  const errorHandler = (err, req, res, _next) => {
12
13
  const status = err.status || err.statusCode || 500;
13
- console.error('[ERROR]', {
14
+ logger_1.AppLogger.error('Request error occurred', {
14
15
  status,
15
16
  method: req.method,
16
17
  path: req.path,
@@ -33,11 +34,3 @@ const notFoundHandler = (_req, res) => {
33
34
  });
34
35
  };
35
36
  exports.notFoundHandler = notFoundHandler;
36
- /**
37
- * Request logging middleware
38
- */
39
- const requestLogger = (req, _res, next) => {
40
- console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
41
- next();
42
- };
43
- exports.requestLogger = requestLogger;
@@ -3,11 +3,10 @@
3
3
  * Middleware exports
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.serveDashboard = exports.startServer = exports.buildDashboardUrl = exports.buildApiUrl = exports.createTimeoutMiddleware = exports.createDashboardCorsMiddleware = exports.createApiCorsMiddleware = exports.createHelmetMiddleware = exports.requestLogger = exports.notFoundHandler = exports.errorHandler = void 0;
6
+ exports.AppLogger = exports.httpLogger = exports.serveDashboard = exports.startServer = exports.buildDashboardUrl = exports.buildApiUrl = exports.createTimeoutMiddleware = exports.createDashboardCorsMiddleware = exports.createApiCorsMiddleware = exports.createHelmetMiddleware = exports.notFoundHandler = exports.errorHandler = void 0;
7
7
  var error_handler_1 = require("./error-handler");
8
8
  Object.defineProperty(exports, "errorHandler", { enumerable: true, get: function () { return error_handler_1.errorHandler; } });
9
9
  Object.defineProperty(exports, "notFoundHandler", { enumerable: true, get: function () { return error_handler_1.notFoundHandler; } });
10
- Object.defineProperty(exports, "requestLogger", { enumerable: true, get: function () { return error_handler_1.requestLogger; } });
11
10
  var security_1 = require("./security");
12
11
  Object.defineProperty(exports, "createHelmetMiddleware", { enumerable: true, get: function () { return security_1.createHelmetMiddleware; } });
13
12
  Object.defineProperty(exports, "createApiCorsMiddleware", { enumerable: true, get: function () { return security_1.createApiCorsMiddleware; } });
@@ -19,3 +18,6 @@ var server_startup_1 = require("./server-startup");
19
18
  Object.defineProperty(exports, "startServer", { enumerable: true, get: function () { return server_startup_1.startServer; } });
20
19
  var dashboard_startup_1 = require("./dashboard-startup");
21
20
  Object.defineProperty(exports, "serveDashboard", { enumerable: true, get: function () { return dashboard_startup_1.serveDashboard; } });
21
+ var logger_1 = require("./logger");
22
+ Object.defineProperty(exports, "httpLogger", { enumerable: true, get: function () { return logger_1.httpLogger; } });
23
+ Object.defineProperty(exports, "AppLogger", { enumerable: true, get: function () { return logger_1.AppLogger; } });
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * Logger configuration using Morgan
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AppLogger = exports.httpLogger = void 0;
10
+ const morgan_1 = __importDefault(require("morgan"));
11
+ /**
12
+ * HTTP request logger middleware using Morgan
13
+ */
14
+ exports.httpLogger = (0, morgan_1.default)('dev');
15
+ /**
16
+ * Application logger for non-HTTP events
17
+ */
18
+ class AppLogger {
19
+ static info(message, data) {
20
+ if (process.env.LOG_LEVEL == 'info' || process.env.LOG_LEVEL == 'debug') {
21
+ if (data) {
22
+ console.log(`${this.prefix} [INFO]`, message, JSON.stringify(data, null, 2));
23
+ }
24
+ else {
25
+ console.log(`${this.prefix} [INFO]`, message);
26
+ }
27
+ }
28
+ }
29
+ static error(message, error) {
30
+ if (error instanceof Error) {
31
+ console.error(`${this.prefix} [ERROR]`, message, {
32
+ message: error.message,
33
+ stack: error.stack,
34
+ });
35
+ }
36
+ else if (error) {
37
+ console.error(`${this.prefix} [ERROR]`, message, error);
38
+ }
39
+ else {
40
+ console.error(`${this.prefix} [ERROR]`, message);
41
+ }
42
+ }
43
+ static warn(message, data) {
44
+ if (data) {
45
+ console.warn(`${this.prefix} [WARN]`, message, JSON.stringify(data, null, 2));
46
+ }
47
+ else {
48
+ console.warn(`${this.prefix} [WARN]`, message);
49
+ }
50
+ }
51
+ static debug(message, data) {
52
+ if (process.env.LOG_LEVEL == 'debug') {
53
+ if (data) {
54
+ console.log(`${this.prefix} [DEBUG]`, message, JSON.stringify(data, null, 2));
55
+ }
56
+ else {
57
+ console.log(`${this.prefix} [DEBUG]`, message);
58
+ }
59
+ }
60
+ }
61
+ }
62
+ exports.AppLogger = AppLogger;
63
+ AppLogger.prefix = '[APP]';
@@ -14,6 +14,7 @@ exports.buildApiUrl = buildApiUrl;
14
14
  exports.buildDashboardUrl = buildDashboardUrl;
15
15
  const helmet_1 = __importDefault(require("helmet"));
16
16
  const cors_1 = __importDefault(require("cors"));
17
+ const constants_1 = require("../constants");
17
18
  /**
18
19
  * Create Helmet security middleware with Content Security Policy
19
20
  */
@@ -34,10 +35,10 @@ function createHelmetMiddleware(apiUrl) {
34
35
  */
35
36
  function createApiCorsMiddleware(dashboardUrl) {
36
37
  const corsOptions = {
37
- origin: process.env.CORS_ORIGIN || dashboardUrl,
38
+ origin: dashboardUrl,
38
39
  credentials: true,
39
- methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
40
- allowedHeaders: ['Content-Type', 'Authorization'],
40
+ methods: [...constants_1.CORS_API_METHODS],
41
+ allowedHeaders: [...constants_1.CORS_ALLOWED_HEADERS],
41
42
  };
42
43
  return (0, cors_1.default)(corsOptions);
43
44
  }
@@ -55,8 +56,8 @@ function createDashboardCorsMiddleware() {
55
56
  */
56
57
  function createTimeoutMiddleware() {
57
58
  return (req, res, next) => {
58
- req.setTimeout(30000);
59
- res.setTimeout(30000);
59
+ req.setTimeout(constants_1.REQUEST_TIMEOUT);
60
+ res.setTimeout(constants_1.RESPONSE_TIMEOUT);
60
61
  next();
61
62
  };
62
63
  }
@@ -64,15 +65,15 @@ function createTimeoutMiddleware() {
64
65
  * Build API URL based on config
65
66
  */
66
67
  function buildApiUrl(host, port) {
67
- const apiHost = host === '0.0.0.0' ? 'localhost' : host;
68
- return process.env.API_URL || `http://${apiHost}:${port}`;
68
+ const apiHost = host === constants_1.WILDCARD_ADDRESS ? constants_1.DEFAULT_LOCALHOST : host;
69
+ return `${constants_1.HTTP_PROTOCOL}${apiHost}:${port}`;
69
70
  }
70
71
  /**
71
72
  * Build dashboard URL based on config
72
73
  */
73
74
  function buildDashboardUrl(config) {
74
- const dashboardHost = config.dashboard.host === '0.0.0.0'
75
- ? 'localhost'
75
+ const dashboardHost = config.dashboard.host === constants_1.WILDCARD_ADDRESS
76
+ ? constants_1.DEFAULT_LOCALHOST
76
77
  : config.dashboard.host;
77
- return `http://${dashboardHost}:${config.dashboard.port}`;
78
+ return `${constants_1.HTTP_PROTOCOL}${dashboardHost}:${config.dashboard.port}`;
78
79
  }
@@ -9,23 +9,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.startServer = startServer;
10
10
  const express_1 = __importDefault(require("express"));
11
11
  const body_parser_1 = require("body-parser");
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");
16
+ const swagger_middleware_1 = require("./swagger-middleware");
15
17
  const package_routes_1 = __importDefault(require("../routes/package-routes"));
16
18
  const commit_routes_1 = __importDefault(require("../routes/commit-routes"));
17
19
  const health_routes_1 = __importDefault(require("../routes/health-routes"));
18
20
  const config_routes_1 = __importDefault(require("../routes/config-routes"));
19
- // Security constants
20
- const PORT_MIN = 1024;
21
- const PORT_MAX = 65535;
21
+ const constants_1 = require("../constants");
22
22
  /**
23
23
  * Validate port number
24
24
  */
25
25
  function validatePort(port) {
26
26
  const portNum = typeof port === 'string' ? parseInt(port, 10) : port;
27
- if (isNaN(portNum) || portNum < PORT_MIN || portNum > PORT_MAX) {
28
- throw new Error(`Port must be between ${PORT_MIN} and ${PORT_MAX}`);
27
+ if (isNaN(portNum) || portNum < constants_1.PORT_MIN || portNum > constants_1.PORT_MAX) {
28
+ throw new Error((0, constants_1.PORT_VALIDATION_ERROR_MESSAGE)(constants_1.PORT_MIN, constants_1.PORT_MAX));
29
29
  }
30
30
  return portNum;
31
31
  }
@@ -44,9 +44,11 @@ function createApp(rootPath) {
44
44
  app.use((0, security_1.createHelmetMiddleware)(apiUrl));
45
45
  app.use((0, security_1.createApiCorsMiddleware)(dashboardUrl));
46
46
  // Body parser
47
- app.use((0, body_parser_1.json)({ limit: '1mb' }));
48
- // Request logging
49
- app.use(error_handler_1.requestLogger);
47
+ app.use((0, body_parser_1.json)({ limit: constants_1.BODY_PARSER_LIMIT }));
48
+ // HTTP request logging with Morgan
49
+ app.use(logger_1.httpLogger);
50
+ // Setup Swagger documentation
51
+ (0, swagger_middleware_1.setupSwaggerDocs)(app);
50
52
  // Routes
51
53
  app.use('/api/packages', package_routes_1.default);
52
54
  app.use('/api/commits/', commit_routes_1.default);
@@ -66,46 +68,51 @@ function startServer(rootPath) {
66
68
  const port = config_loader_1.appConfig.server.port;
67
69
  const host = config_loader_1.appConfig.server.host;
68
70
  const validatedPort = validatePort(port);
71
+ logger_1.AppLogger.info(`Starting Monodog API server...`);
72
+ logger_1.AppLogger.info(`Analyzing monorepo at root: ${rootPath}`);
69
73
  const app = createApp(rootPath);
70
74
  const server = app.listen(validatedPort, host, () => {
71
- console.log(`Backend server running on http://${host}:${validatedPort}`);
72
- console.log('API endpoints available:');
73
- console.log(' - GET /api/health');
74
- console.log(' - GET /api/packages/refresh');
75
- console.log(' - GET /api/packages');
76
- console.log(' - GET /api/packages/:name');
77
- console.log(' - PUT /api/packages/update-config');
78
- console.log(' - GET /api/commits/:packagePath');
79
- console.log(' - GET /api/health/packages');
80
- console.log(' - PUT /api/config/files/:id');
81
- console.log(' - GET /api/config/files');
75
+ console.log((0, constants_1.SUCCESS_SERVER_START)(host, validatedPort));
76
+ logger_1.AppLogger.info('API endpoints available:', {
77
+ endpoints: [
78
+ 'GET /api/health',
79
+ 'GET /api/packages/refresh',
80
+ 'GET /api/packages',
81
+ 'GET /api/packages/:name',
82
+ 'PUT /api/packages/update-config',
83
+ 'GET /api/commits/:packagePath',
84
+ 'GET /api/health/packages',
85
+ 'PUT /api/config/files/:id',
86
+ 'GET /api/config/files',
87
+ ],
88
+ });
82
89
  });
83
90
  server.on('error', (err) => {
84
91
  if (err.code === 'EADDRINUSE') {
85
- console.error(`Error: Port ${validatedPort} is already in use. Please specify a different port.`);
92
+ logger_1.AppLogger.error((0, constants_1.ERROR_PORT_IN_USE)(validatedPort), err);
86
93
  process.exit(1);
87
94
  }
88
95
  else if (err.code === 'EACCES') {
89
- console.error(`Error: Permission denied to listen on port ${validatedPort}. Use a port above 1024.`);
96
+ logger_1.AppLogger.error((0, constants_1.ERROR_PERMISSION_DENIED)(validatedPort), err);
90
97
  process.exit(1);
91
98
  }
92
99
  else {
93
- console.error('Server failed to start:', err.message);
100
+ logger_1.AppLogger.error('Server failed to start:', err);
94
101
  process.exit(1);
95
102
  }
96
103
  });
97
104
  // Graceful shutdown
98
105
  process.on('SIGTERM', () => {
99
- console.log('SIGTERM signal received: closing HTTP server');
106
+ logger_1.AppLogger.info(constants_1.MESSAGE_GRACEFUL_SHUTDOWN);
100
107
  server.close(() => {
101
- console.log('HTTP server closed');
108
+ logger_1.AppLogger.info(constants_1.MESSAGE_SERVER_CLOSED);
102
109
  process.exit(0);
103
110
  });
104
111
  });
105
112
  }
106
113
  catch (error) {
107
114
  const err = error;
108
- console.error('Failed to start server:', err?.message || String(error));
115
+ logger_1.AppLogger.error('Failed to start server:', err);
109
116
  process.exit(1);
110
117
  }
111
118
  }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Swagger Documentation Middleware
4
+ * Sets up Swagger UI for API documentation
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.setupSwaggerDocs = setupSwaggerDocs;
11
+ const swagger_ui_express_1 = __importDefault(require("swagger-ui-express"));
12
+ const swagger_jsdoc_1 = __importDefault(require("swagger-jsdoc"));
13
+ const swagger_config_1 = require("../config/swagger-config");
14
+ /**
15
+ * Setup Swagger documentation endpoint
16
+ * @param app Express application instance
17
+ */
18
+ function setupSwaggerDocs(app) {
19
+ try {
20
+ const specs = (0, swagger_jsdoc_1.default)(swagger_config_1.swaggerOptions);
21
+ // Serve raw Swagger JSON FIRST (before the middleware catches all /api-docs paths)
22
+ app.get('/api-docs/swagger.json', (_req, res) => {
23
+ res.setHeader('Content-Type', 'application/json');
24
+ res.send(specs);
25
+ });
26
+ // Serve Swagger UI at /api-docs
27
+ app.use('/api-docs', swagger_ui_express_1.default.serve, swagger_ui_express_1.default.setup(specs, {
28
+ swaggerOptions: {
29
+ url: '/api-docs/swagger.json',
30
+ persistAuthorization: true,
31
+ displayOperationId: true,
32
+ filter: true,
33
+ showExtensions: true,
34
+ },
35
+ customCss: `
36
+ .swagger-ui .topbar {
37
+ background-color: #2c3e50;
38
+ }
39
+ .swagger-ui .info .title {
40
+ color: #2c3e50;
41
+ font-weight: bold;
42
+ }
43
+ .swagger-ui .btn-box .btn {
44
+ background-color: #2c3e50;
45
+ }
46
+ `,
47
+ customCssUrl: 'https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.15.5/swagger-ui.min.css',
48
+ }));
49
+ console.log('Swagger documentation available at /api-docs');
50
+ }
51
+ catch (error) {
52
+ console.error('Failed to setup Swagger documentation:', error);
53
+ }
54
+ }
@@ -8,7 +8,7 @@ const health_controller_1 = require("../controllers/health-controller");
8
8
  const healthRouter = express_1.default.Router();
9
9
  healthRouter
10
10
  .route('/refresh')
11
- .get(health_controller_1.refreshHealth);
11
+ .post(health_controller_1.refreshHealth);
12
12
  healthRouter
13
13
  .route('/packages')
14
14
  .get(health_controller_1.getPackagesHealth);
@@ -8,7 +8,7 @@ const package_controller_1 = require("../controllers/package-controller");
8
8
  const packageRouter = express_1.default.Router();
9
9
  packageRouter
10
10
  .route('/refresh')
11
- .get(package_controller_1.refreshPackages);
11
+ .post(package_controller_1.refreshPackages);
12
12
  packageRouter
13
13
  .route('/update-config')
14
14
  .put(package_controller_1.updatePackageConfig);
package/dist/serve.js CHANGED
@@ -11,9 +11,22 @@
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const index_1 = require("./index");
13
13
  const utilities_1 = require("./utils/utilities");
14
+ let logLevel = '';
15
+ let nodeEnv = 'production';
16
+ const args = process.argv;
17
+ if (args.includes('--dev')) {
18
+ nodeEnv = 'development';
19
+ }
20
+ // Priority: Check for debug first, then fall back to info
21
+ if (args.includes('--debug')) {
22
+ logLevel = 'debug';
23
+ }
24
+ else if (args.includes('--info')) {
25
+ logLevel = 'info';
26
+ }
27
+ process.env.LOG_LEVEL = logLevel;
28
+ process.env.NODE_ENV = nodeEnv;
14
29
  const rootPath = (0, utilities_1.findMonorepoRoot)();
15
- console.log(`Starting Monodog API server...`);
16
- console.log(`Analyzing monorepo at root: ${rootPath}`);
17
30
  // Start the Express server and dashboard
18
31
  (0, index_1.startServer)(rootPath);
19
32
  (0, index_1.serveDashboard)(rootPath);
@@ -4,6 +4,8 @@ exports.healthRefreshService = exports.getHealthSummaryService = void 0;
4
4
  const utilities_1 = require("../utils/utilities");
5
5
  const monorepo_scanner_1 = require("../utils/monorepo-scanner");
6
6
  const repositories_1 = require("../repositories");
7
+ // Track in-flight health refresh requests to prevent duplicates
8
+ let inFlightHealthRefresh = null;
7
9
  const getHealthSummaryService = async () => {
8
10
  const packageHealthData = await repositories_1.PackageHealthRepository.findAll();
9
11
  console.log('packageHealthData -->', packageHealthData.length);
@@ -42,73 +44,91 @@ const getHealthSummaryService = async () => {
42
44
  };
43
45
  exports.getHealthSummaryService = getHealthSummaryService;
44
46
  const healthRefreshService = async (rootDir) => {
45
- const packages = (0, utilities_1.scanMonorepo)(rootDir);
46
- console.log('packages -->', packages.length);
47
- const healthMetrics = await Promise.all(packages.map(async (pkg) => {
47
+ // If a health refresh is already in progress, return the in-flight promise
48
+ if (inFlightHealthRefresh) {
49
+ console.log('Health refresh already in progress, returning cached promise');
50
+ return inFlightHealthRefresh;
51
+ }
52
+ // Create and store the health refresh promise
53
+ inFlightHealthRefresh = (async () => {
48
54
  try {
49
- // Await each health check function since they return promises
50
- const buildStatus = await (0, monorepo_scanner_1.funCheckBuildStatus)(pkg);
51
- const testCoverage = 0; //await funCheckTestCoverage(pkg); // skip test coverage for now
52
- const lintStatus = await (0, monorepo_scanner_1.funCheckLintStatus)(pkg);
53
- const securityAudit = await (0, monorepo_scanner_1.funCheckSecurityAudit)(pkg);
54
- // Calculate overall health score
55
- const overallScore = (0, utilities_1.calculatePackageHealth)(buildStatus, testCoverage, lintStatus, securityAudit);
56
- const health = {
57
- buildStatus: buildStatus,
58
- testCoverage: testCoverage,
59
- lintStatus: lintStatus,
60
- securityAudit: securityAudit,
61
- overallScore: overallScore.overallScore,
62
- };
63
- const packageStatus = health.overallScore >= 80
64
- ? 'healthy'
65
- : health.overallScore >= 60 && health.overallScore < 80
66
- ? 'warning'
67
- : 'error';
68
- console.log(pkg.name, '-->', health, packageStatus);
69
- await repositories_1.PackageHealthRepository.upsert({
70
- packageName: pkg.name,
71
- packageOverallScore: overallScore.overallScore,
72
- packageBuildStatus: buildStatus,
73
- packageTestCoverage: testCoverage,
74
- packageLintStatus: lintStatus,
75
- packageSecurity: securityAudit,
76
- packageDependencies: '',
77
- });
78
- // update related package status as well
79
- await repositories_1.PackageRepository.updateStatus(pkg.name, packageStatus);
80
- return {
81
- packageName: pkg.name,
82
- health,
83
- isHealthy: health.overallScore >= 80,
84
- };
85
- }
86
- catch (error) {
87
- return {
88
- packageName: pkg.name,
89
- health: {
90
- "buildStatus": "",
91
- "testCoverage": 0,
92
- "lintStatus": "",
93
- "securityAudit": "",
94
- "overallScore": 0
55
+ const packages = (0, utilities_1.scanMonorepo)(rootDir);
56
+ console.log('packages -->', packages.length);
57
+ const healthMetrics = await Promise.all(packages.map(async (pkg) => {
58
+ try {
59
+ // Await each health check function since they return promises
60
+ const buildStatus = await (0, monorepo_scanner_1.funCheckBuildStatus)(pkg);
61
+ const testCoverage = 0; //await funCheckTestCoverage(pkg); // skip test coverage for now
62
+ const lintStatus = await (0, monorepo_scanner_1.funCheckLintStatus)(pkg);
63
+ const securityAudit = await (0, monorepo_scanner_1.funCheckSecurityAudit)(pkg);
64
+ // Calculate overall health score
65
+ const overallScore = (0, utilities_1.calculatePackageHealth)(buildStatus, testCoverage, lintStatus, securityAudit);
66
+ const health = {
67
+ buildStatus: buildStatus,
68
+ testCoverage: testCoverage,
69
+ lintStatus: lintStatus,
70
+ securityAudit: securityAudit,
71
+ overallScore: overallScore.overallScore,
72
+ };
73
+ const packageStatus = health.overallScore >= 80
74
+ ? 'healthy'
75
+ : health.overallScore >= 60 && health.overallScore < 80
76
+ ? 'warning'
77
+ : 'error';
78
+ console.log(pkg.name, '-->', health, packageStatus);
79
+ await repositories_1.PackageHealthRepository.upsert({
80
+ packageName: pkg.name,
81
+ packageOverallScore: overallScore.overallScore,
82
+ packageBuildStatus: buildStatus,
83
+ packageTestCoverage: testCoverage,
84
+ packageLintStatus: lintStatus,
85
+ packageSecurity: securityAudit,
86
+ packageDependencies: '',
87
+ });
88
+ // update related package status as well
89
+ await repositories_1.PackageRepository.updateStatus(pkg.name, packageStatus);
90
+ return {
91
+ packageName: pkg.name,
92
+ health,
93
+ isHealthy: health.overallScore >= 80,
94
+ };
95
+ }
96
+ catch (error) {
97
+ return {
98
+ packageName: pkg.name,
99
+ health: {
100
+ "buildStatus": "",
101
+ "testCoverage": 0,
102
+ "lintStatus": "",
103
+ "securityAudit": "",
104
+ "overallScore": 0
105
+ },
106
+ isHealthy: false,
107
+ error: 'Failed to fetch health metrics1',
108
+ };
109
+ }
110
+ }));
111
+ const result = {
112
+ packages: healthMetrics.filter(h => !h.error),
113
+ summary: {
114
+ total: packages.length,
115
+ healthy: healthMetrics.filter(h => h.isHealthy).length,
116
+ unhealthy: healthMetrics.filter(h => !h.isHealthy).length,
117
+ averageScore: healthMetrics.filter(h => h.health).length > 0
118
+ ? healthMetrics
119
+ .filter(h => h.health)
120
+ .reduce((sum, h) => sum + h.health.overallScore, 0) /
121
+ healthMetrics.filter(h => h.health).length
122
+ : 0,
95
123
  },
96
- isHealthy: false,
97
- error: 'Failed to fetch health metrics1',
98
124
  };
125
+ return result;
99
126
  }
100
- }));
101
- return {
102
- packages: healthMetrics.filter(h => !h.error),
103
- summary: {
104
- total: packages.length,
105
- healthy: healthMetrics.filter(h => h.isHealthy).length,
106
- unhealthy: healthMetrics.filter(h => !h.isHealthy).length,
107
- averageScore: healthMetrics
108
- .filter(h => h.health)
109
- .reduce((sum, h) => sum + h.health.overallScore, 0) /
110
- healthMetrics.filter(h => h.health).length,
111
- },
112
- };
127
+ finally {
128
+ // Clear the in-flight promise after completion
129
+ inFlightHealthRefresh = null;
130
+ }
131
+ })();
132
+ return inFlightHealthRefresh;
113
133
  };
114
134
  exports.healthRefreshService = healthRefreshService;
@@ -128,7 +128,29 @@ const refreshPackagesService = async (rootPath) => {
128
128
  for (const pkg of packages) {
129
129
  await storePackage(pkg);
130
130
  }
131
- return packages;
131
+ // Return transformed packages like getPackagesService
132
+ const dbPackages = await repositories_1.PackageRepository.findAll();
133
+ const transformedPackages = dbPackages.map((pkg) => {
134
+ const transformedPkg = { ...pkg };
135
+ transformedPkg.maintainers = pkg.maintainers
136
+ ? JSON.parse(pkg.maintainers)
137
+ : [];
138
+ transformedPkg.scripts = pkg.scripts ? JSON.parse(pkg.scripts) : {};
139
+ transformedPkg.repository = pkg.repository
140
+ ? JSON.parse(pkg.repository)
141
+ : {};
142
+ transformedPkg.dependencies = pkg.dependencies
143
+ ? JSON.parse(pkg.dependencies)
144
+ : [];
145
+ transformedPkg.devDependencies = pkg.devDependencies
146
+ ? JSON.parse(pkg.devDependencies)
147
+ : [];
148
+ transformedPkg.peerDependencies = pkg.peerDependencies
149
+ ? JSON.parse(pkg.peerDependencies)
150
+ : [];
151
+ return transformedPkg;
152
+ });
153
+ return transformedPackages;
132
154
  };
133
155
  exports.refreshPackagesService = refreshPackagesService;
134
156
  const getPackageDetailService = async (name) => {