@manojkmfsi/monodog 1.0.24 → 1.0.25

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @manojkmfsi/monodog@1.0.24 build /home/runner/work/monodog/monodog/packages/monoapp
2
+ > @manojkmfsi/monodog@1.0.25 build /home/runner/work/monodog/monodog/packages/monoapp
3
3
  > rm -rf dist && tsc
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @manojkmfsi/monoapp
2
2
 
3
+ ## 1.0.25
4
+
5
+ ### Patch Changes
6
+
7
+ - Added morgan and split prisma schema
8
+
3
9
  ## 1.0.24
4
10
 
5
11
  ### Patch Changes
@@ -9,6 +9,7 @@ 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");
@@ -46,7 +47,8 @@ function createDashboardApp() {
46
47
  res.send(`window.ENV = { API_URL: "${apiUrl}" };`);
47
48
  });
48
49
  // Request logging
49
- app.use(error_handler_1.requestLogger);
50
+ app.use(logger_1.httpLogger);
51
+ // app.use(requestLogger);
50
52
  // SPA routing: serve index.html for non-static routes
51
53
  app.use((_req, _res, next) => {
52
54
  if (/(.ico|.js|.css|.jpg|.png|.map|.woff|.woff2|.ttf)$/i.test(_req.path)) {
@@ -60,7 +62,7 @@ function createDashboardApp() {
60
62
  root: path_1.default.resolve(__dirname, '..', '..', 'monodog-dashboard', 'dist'),
61
63
  }, (err) => {
62
64
  if (err) {
63
- console.error('Error serving index.html:', err?.message);
65
+ logger_1.AppLogger.error('Error serving index.html:', err);
64
66
  _res.status(500).json({ error: 'Internal server error' });
65
67
  }
66
68
  });
@@ -68,7 +70,7 @@ function createDashboardApp() {
68
70
  });
69
71
  // Static files
70
72
  const staticPath = path_1.default.join(__dirname, '..', '..', 'monodog-dashboard', 'dist');
71
- console.log('Serving static files from:', staticPath);
73
+ logger_1.AppLogger.debug('Serving static files from:', { path: staticPath });
72
74
  app.use(express_1.default.static(staticPath, {
73
75
  maxAge: '1d',
74
76
  etag: false,
@@ -93,30 +95,30 @@ function serveDashboard(rootPath) {
93
95
  });
94
96
  server.on('error', (err) => {
95
97
  if (err.code === 'EADDRINUSE') {
96
- console.error(`Error: Port ${validatedPort} is already in use.`);
98
+ logger_1.AppLogger.error(`Port ${validatedPort} is already in use.`, err);
97
99
  process.exit(1);
98
100
  }
99
101
  else if (err.code === 'EACCES') {
100
- console.error(`Error: Permission denied to listen on port ${validatedPort}.`);
102
+ logger_1.AppLogger.error(`Permission denied to listen on port ${validatedPort}.`, err);
101
103
  process.exit(1);
102
104
  }
103
105
  else {
104
- console.error('Server failed to start:', err.message);
106
+ logger_1.AppLogger.error('Server failed to start:', err);
105
107
  process.exit(1);
106
108
  }
107
109
  });
108
110
  // Graceful shutdown
109
111
  process.on('SIGTERM', () => {
110
- console.log('SIGTERM signal received: closing dashboard server');
112
+ logger_1.AppLogger.info('SIGTERM signal received: closing dashboard server');
111
113
  server.close(() => {
112
- console.log('Dashboard server closed');
114
+ logger_1.AppLogger.info('Dashboard server closed');
113
115
  process.exit(0);
114
116
  });
115
117
  });
116
118
  }
117
119
  catch (error) {
118
120
  const err = error;
119
- console.error('Failed to start dashboard:', err?.message || String(error));
121
+ logger_1.AppLogger.error('Failed to start dashboard:', err);
120
122
  process.exit(1);
121
123
  }
122
124
  }
@@ -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]';
@@ -34,7 +34,7 @@ function createHelmetMiddleware(apiUrl) {
34
34
  */
35
35
  function createApiCorsMiddleware(dashboardUrl) {
36
36
  const corsOptions = {
37
- origin: process.env.CORS_ORIGIN || dashboardUrl,
37
+ origin: dashboardUrl,
38
38
  credentials: true,
39
39
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
40
40
  allowedHeaders: ['Content-Type', 'Authorization'],
@@ -65,7 +65,7 @@ function createTimeoutMiddleware() {
65
65
  */
66
66
  function buildApiUrl(host, port) {
67
67
  const apiHost = host === '0.0.0.0' ? 'localhost' : host;
68
- return process.env.API_URL || `http://${apiHost}:${port}`;
68
+ return `http://${apiHost}:${port}`;
69
69
  }
70
70
  /**
71
71
  * Build dashboard URL based on config
@@ -9,6 +9,7 @@ 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");
@@ -45,8 +46,8 @@ function createApp(rootPath) {
45
46
  app.use((0, security_1.createApiCorsMiddleware)(dashboardUrl));
46
47
  // Body parser
47
48
  app.use((0, body_parser_1.json)({ limit: '1mb' }));
48
- // Request logging
49
- app.use(error_handler_1.requestLogger);
49
+ // HTTP request logging with Morgan
50
+ app.use(logger_1.httpLogger);
50
51
  // Routes
51
52
  app.use('/api/packages', package_routes_1.default);
52
53
  app.use('/api/commits/', commit_routes_1.default);
@@ -66,46 +67,51 @@ function startServer(rootPath) {
66
67
  const port = config_loader_1.appConfig.server.port;
67
68
  const host = config_loader_1.appConfig.server.host;
68
69
  const validatedPort = validatePort(port);
70
+ logger_1.AppLogger.info(`Starting Monodog API server...`);
71
+ logger_1.AppLogger.info(`Analyzing monorepo at root: ${rootPath}`);
69
72
  const app = createApp(rootPath);
70
73
  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');
74
+ console.log(`Backend server listening on http://${host}:${validatedPort}`);
75
+ logger_1.AppLogger.info('API endpoints available:', {
76
+ endpoints: [
77
+ 'GET /api/health',
78
+ 'GET /api/packages/refresh',
79
+ 'GET /api/packages',
80
+ 'GET /api/packages/:name',
81
+ 'PUT /api/packages/update-config',
82
+ 'GET /api/commits/:packagePath',
83
+ 'GET /api/health/packages',
84
+ 'PUT /api/config/files/:id',
85
+ 'GET /api/config/files',
86
+ ],
87
+ });
82
88
  });
83
89
  server.on('error', (err) => {
84
90
  if (err.code === 'EADDRINUSE') {
85
- console.error(`Error: Port ${validatedPort} is already in use. Please specify a different port.`);
91
+ logger_1.AppLogger.error(`Port ${validatedPort} is already in use. Please specify a different port.`, err);
86
92
  process.exit(1);
87
93
  }
88
94
  else if (err.code === 'EACCES') {
89
- console.error(`Error: Permission denied to listen on port ${validatedPort}. Use a port above 1024.`);
95
+ logger_1.AppLogger.error(`Permission denied to listen on port ${validatedPort}. Use a port above 1024.`, err);
90
96
  process.exit(1);
91
97
  }
92
98
  else {
93
- console.error('Server failed to start:', err.message);
99
+ logger_1.AppLogger.error('Server failed to start:', err);
94
100
  process.exit(1);
95
101
  }
96
102
  });
97
103
  // Graceful shutdown
98
104
  process.on('SIGTERM', () => {
99
- console.log('SIGTERM signal received: closing HTTP server');
105
+ logger_1.AppLogger.info('SIGTERM signal received: closing HTTP server');
100
106
  server.close(() => {
101
- console.log('HTTP server closed');
107
+ logger_1.AppLogger.info('HTTP server closed');
102
108
  process.exit(0);
103
109
  });
104
110
  });
105
111
  }
106
112
  catch (error) {
107
113
  const err = error;
108
- console.error('Failed to start server:', err?.message || String(error));
114
+ logger_1.AppLogger.error('Failed to start server:', err);
109
115
  process.exit(1);
110
116
  }
111
117
  }
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manojkmfsi/monodog",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "description": "App for monodog monorepo",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -22,25 +22,32 @@
22
22
  "@types/express": "^4.17.25",
23
23
  "@types/jest": "^29.5.14",
24
24
  "@types/js-yaml": "^4.0.9",
25
+ "@types/morgan": "^1.9.10",
25
26
  "@types/node": "^20.19.27",
26
27
  "cross-env": "^10.1.0",
27
28
  "jest": "^29.7.0",
28
29
  "jest-environment-jsdom": "^30.2.0",
30
+ "morgan": "^1.10.1",
29
31
  "ts-jest": "^29.4.6",
30
32
  "ts-node": "^10.9.2",
31
33
  "tsx": "^4.21.0",
32
34
  "typescript": "^5.9.3"
33
35
  },
36
+ "prisma": {
37
+ "schema": "./prisma/schema"
38
+ },
34
39
  "scripts": {
35
- "dev": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') tsx watch src/serve.js",
40
+ "dev": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') tsx watch src/serve.ts --dev --debug",
36
41
  "serve": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') tsx dist/serve.js",
37
42
  "build": "rm -rf dist && tsc",
38
- "test:coverage": "jest --coverage",
43
+ "test:coverage": "jest --coverage --silent",
39
44
  "prestart": "npm run build",
40
45
  "clean": "rm -rf dist node_modules/.cache",
41
46
  "lint": "eslint .",
42
47
  "lint:fix": "eslint . --fix",
43
48
  "db:url": "node dist/get-db-url.js",
49
+ "schema:format": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') prisma format",
50
+ "schema:validate": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') prisma validate",
44
51
  "generate": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') prisma generate",
45
52
  "migrate": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') prisma migrate dev",
46
53
  "migrate:reset": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') prisma migrate reset --force"
@@ -0,0 +1,11 @@
1
+ model Commit {
2
+ hash String
3
+ message String
4
+ author String
5
+ date DateTime?
6
+ type String
7
+ packageName String
8
+ package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
9
+
10
+ @@unique([hash, packageName])
11
+ }
@@ -0,0 +1,12 @@
1
+ model DependencyInfo {
2
+ name String
3
+ packageName String
4
+ version String
5
+ type String @default("")
6
+ status String @default("")
7
+ latest String?
8
+ outdated Boolean @default(false)
9
+ package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
10
+
11
+ @@unique([name, packageName]) // Composite unique constraint
12
+ }
@@ -0,0 +1,14 @@
1
+ model HealthStatus {
2
+ id Int @id @default(autoincrement())
3
+ packageName String @unique
4
+ overallScore Float // Overall health score (0-100)
5
+ buildStatus String // e.g., "passing", "failing", "unknown"
6
+ testCoverage Float // Test coverage percentage (0-100)
7
+ lintStatus String // e.g., "passing", "warning", "failing"
8
+ security String // e.g., "secure", "vulnerabilities", "unknown"
9
+ dependencies String // e.g., "up-to-date", "outdated", "vulnerable"
10
+ createdAt DateTime @default(now())
11
+ updatedAt DateTime @updatedAt
12
+
13
+ @@map("health_status")
14
+ }
@@ -0,0 +1,15 @@
1
+ model PackageHealth {
2
+ id Int @id @default(autoincrement())
3
+ packageName String @unique
4
+ packageOverallScore Float
5
+ packageBuildStatus String
6
+ packageTestCoverage Float?
7
+ packageLintStatus String
8
+ packageSecurity String // Changed from securityAudit to packageSecurity
9
+ packageDependencies String // Changed from dependencies to packageDependencies
10
+ createdAt DateTime @default(now())
11
+ updatedAt DateTime @updatedAt
12
+ package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
13
+
14
+ @@map("package_health")
15
+ }
@@ -0,0 +1,21 @@
1
+ model Package {
2
+ // Primary Key and Identity Field (using the package name as the unique ID): Example: '@monodog/dashboard'
3
+ name String @id @unique
4
+ version String
5
+ type String // e.g., 'app', 'package'
6
+ createdAt DateTime @default(now())
7
+ lastUpdated DateTime @default(now())
8
+ dependencies String?
9
+ maintainers String
10
+ path String // The relative path in the file system, e.g., 'packages/monoapp'
11
+ description String
12
+ license String
13
+ repository String?
14
+ scripts String?
15
+ status String @default("")
16
+ devDependencies String?
17
+ peerDependencies String?
18
+ dependenciesInfo DependencyInfo[]
19
+ commits Commit[]
20
+ packageHealth PackageHealth?
21
+ }
@@ -0,0 +1,15 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5
+ // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6
+
7
+ generator client {
8
+ provider = "prisma-client-js"
9
+ previewFeatures = ["prismaSchemaFolder"]
10
+ }
11
+
12
+ datasource db {
13
+ provider = "sqlite"
14
+ url = env("DATABASE_URL")
15
+ }
@@ -5,11 +5,11 @@
5
5
  import express from 'express';
6
6
  import path from 'path';
7
7
  import type { Express } from 'express';
8
+ import { httpLogger, AppLogger } from './logger';
8
9
 
9
10
  import { appConfig } from '../config-loader';
10
11
  import {
11
12
  errorHandler,
12
- requestLogger,
13
13
  } from './error-handler';
14
14
  import {
15
15
  createHelmetMiddleware,
@@ -64,7 +64,8 @@ function createDashboardApp(): Express {
64
64
  });
65
65
 
66
66
  // Request logging
67
- app.use(requestLogger);
67
+ app.use(httpLogger);
68
+ // app.use(requestLogger);
68
69
 
69
70
  // SPA routing: serve index.html for non-static routes
70
71
  app.use((_req, _res, next) => {
@@ -81,7 +82,7 @@ function createDashboardApp(): Express {
81
82
  root: path.resolve(__dirname, '..', '..', 'monodog-dashboard', 'dist'),
82
83
  }, (err: Error | null) => {
83
84
  if (err) {
84
- console.error('Error serving index.html:', (err as Error & { message?: string })?.message);
85
+ AppLogger.error('Error serving index.html:', err);
85
86
  _res.status(500).json({ error: 'Internal server error' });
86
87
  }
87
88
  });
@@ -90,7 +91,7 @@ function createDashboardApp(): Express {
90
91
 
91
92
  // Static files
92
93
  const staticPath = path.join(__dirname, '..', '..', 'monodog-dashboard', 'dist');
93
- console.log('Serving static files from:', staticPath);
94
+ AppLogger.debug('Serving static files from:', { path: staticPath });
94
95
  app.use(express.static(staticPath, {
95
96
  maxAge: '1d',
96
97
  etag: false,
@@ -121,30 +122,28 @@ export function serveDashboard(rootPath: string): void {
121
122
 
122
123
  server.on('error', (err: NodeJS.ErrnoException) => {
123
124
  if (err.code === 'EADDRINUSE') {
124
- console.error(`Error: Port ${validatedPort} is already in use.`);
125
+ AppLogger.error(`Port ${validatedPort} is already in use.`, err);
125
126
  process.exit(1);
126
127
  } else if (err.code === 'EACCES') {
127
- console.error(
128
- `Error: Permission denied to listen on port ${validatedPort}.`
129
- );
128
+ AppLogger.error(`Permission denied to listen on port ${validatedPort}.`, err);
130
129
  process.exit(1);
131
130
  } else {
132
- console.error('Server failed to start:', err.message);
131
+ AppLogger.error('Server failed to start:', err);
133
132
  process.exit(1);
134
133
  }
135
134
  });
136
135
 
137
136
  // Graceful shutdown
138
137
  process.on('SIGTERM', () => {
139
- console.log('SIGTERM signal received: closing dashboard server');
138
+ AppLogger.info('SIGTERM signal received: closing dashboard server');
140
139
  server.close(() => {
141
- console.log('Dashboard server closed');
140
+ AppLogger.info('Dashboard server closed');
142
141
  process.exit(0);
143
142
  });
144
143
  });
145
144
  } catch (error: unknown) {
146
145
  const err = error as Error & { message?: string };
147
- console.error('Failed to start dashboard:', err?.message || String(error));
146
+ AppLogger.error('Failed to start dashboard:', err);
148
147
  process.exit(1);
149
148
  }
150
149
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { Request, Response, NextFunction, ErrorRequestHandler } from 'express';
6
+ import { AppLogger } from './logger';
6
7
 
7
8
  /**
8
9
  * Custom error interface extending Error
@@ -24,7 +25,7 @@ export const errorHandler: ErrorRequestHandler = (
24
25
  ): void => {
25
26
  const status = err.status || err.statusCode || 500;
26
27
 
27
- console.error('[ERROR]', {
28
+ AppLogger.error('Request error occurred', {
28
29
  status,
29
30
  method: req.method,
30
31
  path: req.path,
@@ -47,17 +48,3 @@ export const notFoundHandler = (_req: Request, res: Response): void => {
47
48
  timestamp: Date.now(),
48
49
  });
49
50
  };
50
-
51
- /**
52
- * Request logging middleware
53
- */
54
- export const requestLogger = (
55
- req: Request,
56
- _res: Response,
57
- next: NextFunction
58
- ): void => {
59
- console.log(
60
- `[${new Date().toISOString()}] ${req.method} ${req.path}`
61
- );
62
- next();
63
- };
@@ -2,7 +2,7 @@
2
2
  * Middleware exports
3
3
  */
4
4
 
5
- export { errorHandler, notFoundHandler, requestLogger } from './error-handler';
5
+ export { errorHandler, notFoundHandler } from './error-handler';
6
6
  export type { CustomError } from './error-handler';
7
7
 
8
8
  export {
@@ -16,3 +16,5 @@ export {
16
16
 
17
17
  export { startServer } from './server-startup';
18
18
  export { serveDashboard } from './dashboard-startup';
19
+
20
+ export { httpLogger, AppLogger } from './logger';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Logger configuration using Morgan
3
+ */
4
+
5
+ import morgan from 'morgan';
6
+
7
+ /**
8
+ * HTTP request logger middleware using Morgan
9
+ */
10
+ export const httpLogger = morgan('dev');
11
+
12
+ /**
13
+ * Application logger for non-HTTP events
14
+ */
15
+ export class AppLogger {
16
+ private static readonly prefix = '[APP]';
17
+
18
+ static info(message: string, data?: Record<string, unknown>): void {
19
+ if (process.env.LOG_LEVEL == 'info' || process.env.LOG_LEVEL == 'debug') {
20
+ if (data) {
21
+ console.log(`${this.prefix} [INFO]`, message, JSON.stringify(data, null, 2));
22
+ } else {
23
+ console.log(`${this.prefix} [INFO]`, message);
24
+ }
25
+ }
26
+ }
27
+
28
+ static error(message: string, error?: Error | Record<string, unknown>): void {
29
+ if (error instanceof Error) {
30
+ console.error(`${this.prefix} [ERROR]`, message, {
31
+ message: error.message,
32
+ stack: error.stack,
33
+ });
34
+ } else if (error) {
35
+ console.error(`${this.prefix} [ERROR]`, message, error);
36
+ } else {
37
+ console.error(`${this.prefix} [ERROR]`, message);
38
+ }
39
+ }
40
+
41
+ static warn(message: string, data?: Record<string, unknown>): void {
42
+ if (data) {
43
+ console.warn(`${this.prefix} [WARN]`, message, JSON.stringify(data, null, 2));
44
+ } else {
45
+ console.warn(`${this.prefix} [WARN]`, message);
46
+ }
47
+ }
48
+
49
+ static debug(message: string, data?: Record<string, unknown>): void {
50
+ if (process.env.LOG_LEVEL == 'debug') {
51
+ if (data) {
52
+ console.log(`${this.prefix} [DEBUG]`, message, JSON.stringify(data, null, 2));
53
+ } else {
54
+ console.log(`${this.prefix} [DEBUG]`, message);
55
+ }
56
+ }
57
+ }
58
+ }
@@ -28,7 +28,7 @@ export function createHelmetMiddleware(apiUrl: string) {
28
28
  */
29
29
  export function createApiCorsMiddleware(dashboardUrl: string) {
30
30
  const corsOptions: CorsOptions = {
31
- origin: process.env.CORS_ORIGIN || dashboardUrl,
31
+ origin: dashboardUrl,
32
32
  credentials: true,
33
33
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
34
34
  allowedHeaders: ['Content-Type', 'Authorization'],
@@ -67,15 +67,15 @@ export function buildApiUrl(
67
67
  port: number
68
68
  ): string {
69
69
  const apiHost = host === '0.0.0.0' ? 'localhost' : host;
70
- return process.env.API_URL || `http://${apiHost}:${port}`;
70
+ return `http://${apiHost}:${port}`;
71
71
  }
72
72
 
73
73
  /**
74
74
  * Build dashboard URL based on config
75
75
  */
76
76
  export function buildDashboardUrl(config: MonodogConfig): string {
77
- const dashboardHost = config.dashboard.host === '0.0.0.0'
78
- ? 'localhost'
77
+ const dashboardHost = config.dashboard.host === '0.0.0.0'
78
+ ? 'localhost'
79
79
  : config.dashboard.host;
80
80
  return `http://${dashboardHost}:${config.dashboard.port}`;
81
81
  }
@@ -5,12 +5,12 @@
5
5
  import express from 'express';
6
6
  import { json } from 'body-parser';
7
7
  import type { Express } from 'express';
8
+ import { httpLogger, AppLogger } from './logger';
8
9
 
9
10
  import { appConfig } from '../config-loader';
10
11
  import {
11
12
  errorHandler,
12
13
  notFoundHandler,
13
- requestLogger,
14
14
  } from './error-handler';
15
15
  import {
16
16
  createHelmetMiddleware,
@@ -64,8 +64,8 @@ function createApp(rootPath: string): Express {
64
64
  // Body parser
65
65
  app.use(json({ limit: '1mb' }));
66
66
 
67
- // Request logging
68
- app.use(requestLogger);
67
+ // HTTP request logging with Morgan
68
+ app.use(httpLogger);
69
69
 
70
70
  // Routes
71
71
  app.use('/api/packages', packageRouter);
@@ -91,50 +91,52 @@ export function startServer(rootPath: string): void {
91
91
  const host = appConfig.server.host;
92
92
  const validatedPort = validatePort(port);
93
93
 
94
+ AppLogger.info(`Starting Monodog API server...`);
95
+ AppLogger.info(`Analyzing monorepo at root: ${rootPath}`);
96
+
94
97
  const app = createApp(rootPath);
95
98
 
96
99
  const server = app.listen(validatedPort, host, () => {
97
- console.log(`Backend server running on http://${host}:${validatedPort}`);
98
- console.log('API endpoints available:');
99
- console.log(' - GET /api/health');
100
- console.log(' - GET /api/packages/refresh');
101
- console.log(' - GET /api/packages');
102
- console.log(' - GET /api/packages/:name');
103
- console.log(' - PUT /api/packages/update-config');
104
- console.log(' - GET /api/commits/:packagePath');
105
- console.log(' - GET /api/health/packages');
106
- console.log(' - PUT /api/config/files/:id');
107
- console.log(' - GET /api/config/files');
100
+ console.log(`Backend server listening on http://${host}:${validatedPort}`);
101
+ AppLogger.info('API endpoints available:', {
102
+ endpoints: [
103
+ 'GET /api/health',
104
+ 'GET /api/packages/refresh',
105
+ 'GET /api/packages',
106
+ 'GET /api/packages/:name',
107
+ 'PUT /api/packages/update-config',
108
+ 'GET /api/commits/:packagePath',
109
+ 'GET /api/health/packages',
110
+ 'PUT /api/config/files/:id',
111
+ 'GET /api/config/files',
112
+ ],
113
+ });
108
114
  });
109
115
 
110
116
  server.on('error', (err: NodeJS.ErrnoException) => {
111
117
  if (err.code === 'EADDRINUSE') {
112
- console.error(
113
- `Error: Port ${validatedPort} is already in use. Please specify a different port.`
114
- );
118
+ AppLogger.error(`Port ${validatedPort} is already in use. Please specify a different port.`, err);
115
119
  process.exit(1);
116
120
  } else if (err.code === 'EACCES') {
117
- console.error(
118
- `Error: Permission denied to listen on port ${validatedPort}. Use a port above 1024.`
119
- );
121
+ AppLogger.error(`Permission denied to listen on port ${validatedPort}. Use a port above 1024.`, err);
120
122
  process.exit(1);
121
123
  } else {
122
- console.error('Server failed to start:', err.message);
124
+ AppLogger.error('Server failed to start:', err);
123
125
  process.exit(1);
124
126
  }
125
127
  });
126
128
 
127
129
  // Graceful shutdown
128
130
  process.on('SIGTERM', () => {
129
- console.log('SIGTERM signal received: closing HTTP server');
131
+ AppLogger.info('SIGTERM signal received: closing HTTP server');
130
132
  server.close(() => {
131
- console.log('HTTP server closed');
133
+ AppLogger.info('HTTP server closed');
132
134
  process.exit(0);
133
135
  });
134
136
  });
135
137
  } catch (error: unknown) {
136
138
  const err = error as Error & { message?: string };
137
- console.error('Failed to start server:', err?.message || String(error));
139
+ AppLogger.error('Failed to start server:', err);
138
140
  process.exit(1);
139
141
  }
140
142
  }
package/src/serve.ts CHANGED
@@ -12,10 +12,26 @@
12
12
  import { startServer, serveDashboard } from './index';
13
13
  import { findMonorepoRoot } from './utils/utilities';
14
14
 
15
- const rootPath = findMonorepoRoot();
15
+ let logLevel = '';
16
+ let nodeEnv = 'production';
17
+
18
+ const args = process.argv;
19
+
20
+ if (args.includes('--dev')) {
21
+ nodeEnv = 'development';
22
+ }
16
23
 
17
- console.log(`Starting Monodog API server...`);
18
- console.log(`Analyzing monorepo at root: ${rootPath}`);
24
+ // Priority: Check for debug first, then fall back to info
25
+ if (args.includes('--debug')) {
26
+ logLevel = 'debug';
27
+ } else if (args.includes('--info')) {
28
+ logLevel = 'info';
29
+ }
30
+
31
+ process.env.LOG_LEVEL = logLevel;
32
+ process.env.NODE_ENV = nodeEnv
33
+
34
+ const rootPath = findMonorepoRoot();
19
35
 
20
36
  // Start the Express server and dashboard
21
37
 
@@ -1,116 +0,0 @@
1
- // This is your Prisma schema file,
2
- // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
-
4
- // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5
- // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6
-
7
- generator client {
8
- provider = "prisma-client-js"
9
- }
10
-
11
- datasource db {
12
- provider = "sqlite"
13
- url = env("DATABASE_URL")
14
- }
15
-
16
- // --- MONOREPO DATA MODEL ---
17
-
18
- /// Represents a single package within the monorepo, based on the pnpm/package.json data.
19
- model Package {
20
- // Primary Key and Identity Field (using the package name as the unique ID)
21
- // Example: '@monodog/dashboard'
22
- name String @id @unique
23
-
24
- // Core Package Metadata
25
- version String
26
- type String // e.g., 'app', 'package'
27
-
28
- // Timestamps
29
- createdAt DateTime @default(now())
30
- lastUpdated DateTime @default(now())
31
-
32
- // Key Metrics and Relationships
33
- dependencies String? // The total number of direct dependencies
34
- // Manual Serialization Required: Stores a JSON array string of maintainers, e.g., '["team-frontend"]'
35
- maintainers String
36
- // Manual Serialization Required: Stores a JSON array string of tags, e.g., '["core", "ui"]'
37
- path String // The relative path in the file system, e.g., 'apps/dashboard'
38
-
39
- // Descriptions and Configuration
40
- description String
41
- license String
42
- repository String?
43
-
44
- // Manual Serialization Required: Stores the scripts object as a JSON string
45
- // Example: '{"dev": "vite", "build": "tsc && vite build"}'
46
- scripts String?
47
- status String @default("")
48
-
49
- devDependencies String?
50
- peerDependencies String?
51
- dependenciesInfo DependencyInfo[]
52
- commits Commit[]
53
- packageHealth PackageHealth?
54
- }
55
-
56
- model DependencyInfo {
57
- name String
58
- packageName String
59
- version String
60
- type String @default("")
61
- status String @default("")
62
- latest String?
63
- outdated Boolean @default(false)
64
- package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
65
-
66
- @@unique([name, packageName]) // Composite unique constraint
67
- }
68
-
69
- model Commit {
70
- hash String
71
- message String
72
- author String
73
- date DateTime?
74
- type String
75
- packageName String
76
- package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
77
-
78
- @@unique([hash, packageName])
79
- }
80
-
81
- model HealthStatus {
82
- id Int @id @default(autoincrement())
83
-
84
- // Package reference (without formal relation)
85
- packageName String @unique
86
- // package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
87
-
88
- // Health Metrics
89
- overallScore Float // Overall health score (0-100)
90
- buildStatus String // e.g., "passing", "failing", "unknown"
91
- testCoverage Float // Test coverage percentage (0-100)
92
- lintStatus String // e.g., "passing", "warning", "failing"
93
- security String // e.g., "secure", "vulnerabilities", "unknown"
94
- dependencies String // e.g., "up-to-date", "outdated", "vulnerable"
95
- // Timestamps
96
- createdAt DateTime @default(now())
97
- updatedAt DateTime @updatedAt
98
-
99
- @@map("health_status") // Optional: to specify the table name
100
- }
101
-
102
- model PackageHealth {
103
- id Int @id @default(autoincrement())
104
- packageName String @unique
105
- packageOverallScore Float
106
- packageBuildStatus String
107
- packageTestCoverage Float?
108
- packageLintStatus String
109
- packageSecurity String // Changed from securityAudit to packageSecurity
110
- packageDependencies String // Changed from dependencies to packageDependencies
111
- createdAt DateTime @default(now())
112
- updatedAt DateTime @updatedAt
113
- package Package @relation(fields: [packageName], references: [name], onDelete: Cascade)
114
-
115
- @@map("package_health")
116
- }