@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
@@ -12,6 +12,9 @@ import {
12
12
  import { PackageHealthRepository, PackageRepository } from '../repositories';
13
13
  import type { TransformedPackageHealth, HealthResponse, PackageHealthModel } from '../types/database';
14
14
 
15
+ // Track in-flight health refresh requests to prevent duplicates
16
+ let inFlightHealthRefresh: Promise<HealthResponse> | null = null;
17
+
15
18
  export const getHealthSummaryService = async (): Promise<HealthResponse> => {
16
19
  const packageHealthData = await PackageHealthRepository.findAll() as PackageHealthModel[];
17
20
  console.log('packageHealthData -->', packageHealthData.length);
@@ -55,83 +58,104 @@ export const getHealthSummaryService = async (): Promise<HealthResponse> => {
55
58
  }
56
59
 
57
60
  export const healthRefreshService = async (rootDir: string) => {
58
- const packages = scanMonorepo(rootDir);
59
- console.log('packages -->', packages.length);
60
- const healthMetrics = await Promise.all(
61
- packages.map(async pkg => {
62
- try {
63
- // Await each health check function since they return promises
64
- const buildStatus = await funCheckBuildStatus(pkg);
65
- const testCoverage = 0; //await funCheckTestCoverage(pkg); // skip test coverage for now
66
- const lintStatus = await funCheckLintStatus(pkg);
67
- const securityAudit = await funCheckSecurityAudit(pkg);
68
- // Calculate overall health score
69
- const overallScore = calculatePackageHealth(
70
- buildStatus,
71
- testCoverage,
72
- lintStatus,
73
- securityAudit
74
- );
75
-
76
- const health = {
77
- buildStatus: buildStatus,
78
- testCoverage: testCoverage,
79
- lintStatus: lintStatus,
80
- securityAudit: securityAudit,
81
- overallScore: overallScore.overallScore,
82
- };
83
- const packageStatus =
84
- health.overallScore >= 80
85
- ? 'healthy'
86
- : health.overallScore >= 60 && health.overallScore < 80
87
- ? 'warning'
88
- : 'error';
89
-
90
- console.log(pkg.name, '-->', health, packageStatus);
91
-
92
- await PackageHealthRepository.upsert({
93
- packageName: pkg.name,
94
- packageOverallScore: overallScore.overallScore,
95
- packageBuildStatus: buildStatus,
96
- packageTestCoverage: testCoverage,
97
- packageLintStatus: lintStatus,
98
- packageSecurity: securityAudit,
99
- packageDependencies: '',
100
- });
101
- // update related package status as well
102
- await PackageRepository.updateStatus(pkg.name, packageStatus);
103
- return {
104
- packageName: pkg.name,
105
- health,
106
- isHealthy: health.overallScore >= 80,
107
- };
108
- } catch (error) {
109
- return {
110
- packageName: pkg.name,
111
- health: {
112
- "buildStatus": "",
113
- "testCoverage": 0,
114
- "lintStatus": "",
115
- "securityAudit": "",
116
- "overallScore": 0
117
- },
118
- isHealthy: false,
119
- error: 'Failed to fetch health metrics1',
120
- };
121
- }
122
- })
123
- );
124
- return {
125
- packages: healthMetrics.filter(h => !h.error),
126
- summary: {
127
- total: packages.length,
128
- healthy: healthMetrics.filter(h => h.isHealthy).length,
129
- unhealthy: healthMetrics.filter(h => !h.isHealthy).length,
130
- averageScore:
131
- healthMetrics
132
- .filter(h => h.health)
133
- .reduce((sum, h) => sum + h.health!.overallScore, 0) /
134
- healthMetrics.filter(h => h.health).length,
135
- },
136
- };
61
+ // If a health refresh is already in progress, return the in-flight promise
62
+ if (inFlightHealthRefresh) {
63
+ console.log('Health refresh already in progress, returning cached promise');
64
+ return inFlightHealthRefresh;
65
+ }
66
+
67
+ // Create and store the health refresh promise
68
+ inFlightHealthRefresh = (async () => {
69
+ try {
70
+ const packages = scanMonorepo(rootDir);
71
+ console.log('packages -->', packages.length);
72
+ const healthMetrics = await Promise.all(
73
+ packages.map(async pkg => {
74
+ try {
75
+ // Await each health check function since they return promises
76
+ const buildStatus = await funCheckBuildStatus(pkg);
77
+ const testCoverage = 0; //await funCheckTestCoverage(pkg); // skip test coverage for now
78
+ const lintStatus = await funCheckLintStatus(pkg);
79
+ const securityAudit = await funCheckSecurityAudit(pkg);
80
+ // Calculate overall health score
81
+ const overallScore = calculatePackageHealth(
82
+ buildStatus,
83
+ testCoverage,
84
+ lintStatus,
85
+ securityAudit
86
+ );
87
+
88
+ const health = {
89
+ buildStatus: buildStatus,
90
+ testCoverage: testCoverage,
91
+ lintStatus: lintStatus,
92
+ securityAudit: securityAudit,
93
+ overallScore: overallScore.overallScore,
94
+ };
95
+ const packageStatus =
96
+ health.overallScore >= 80
97
+ ? 'healthy'
98
+ : health.overallScore >= 60 && health.overallScore < 80
99
+ ? 'warning'
100
+ : 'error';
101
+
102
+ console.log(pkg.name, '-->', health, packageStatus);
103
+
104
+ await PackageHealthRepository.upsert({
105
+ packageName: pkg.name,
106
+ packageOverallScore: overallScore.overallScore,
107
+ packageBuildStatus: buildStatus,
108
+ packageTestCoverage: testCoverage,
109
+ packageLintStatus: lintStatus,
110
+ packageSecurity: securityAudit,
111
+ packageDependencies: '',
112
+ });
113
+ // update related package status as well
114
+ await PackageRepository.updateStatus(pkg.name, packageStatus);
115
+ return {
116
+ packageName: pkg.name,
117
+ health,
118
+ isHealthy: health.overallScore >= 80,
119
+ };
120
+ } catch (error) {
121
+ return {
122
+ packageName: pkg.name,
123
+ health: {
124
+ "buildStatus": "",
125
+ "testCoverage": 0,
126
+ "lintStatus": "",
127
+ "securityAudit": "",
128
+ "overallScore": 0
129
+ },
130
+ isHealthy: false,
131
+ error: 'Failed to fetch health metrics1',
132
+ };
133
+ }
134
+ })
135
+ );
136
+
137
+ const result: HealthResponse = {
138
+ packages: healthMetrics.filter(h => !h.error),
139
+ summary: {
140
+ total: packages.length,
141
+ healthy: healthMetrics.filter(h => h.isHealthy).length,
142
+ unhealthy: healthMetrics.filter(h => !h.isHealthy).length,
143
+ averageScore:
144
+ healthMetrics.filter(h => h.health).length > 0
145
+ ? healthMetrics
146
+ .filter(h => h.health)
147
+ .reduce((sum, h) => sum + h.health!.overallScore, 0) /
148
+ healthMetrics.filter(h => h.health).length
149
+ : 0,
150
+ },
151
+ };
152
+
153
+ return result;
154
+ } finally {
155
+ // Clear the in-flight promise after completion
156
+ inFlightHealthRefresh = null;
157
+ }
158
+ })();
159
+
160
+ return inFlightHealthRefresh;
137
161
  }
@@ -160,7 +160,33 @@ export const refreshPackagesService = async (rootPath: string) => {
160
160
  await storePackage(pkg);
161
161
  }
162
162
 
163
- return packages;
163
+ // Return transformed packages like getPackagesService
164
+ const dbPackages = await PackageRepository.findAll();
165
+ const transformedPackages = dbPackages.map((pkg: PackageModel) => {
166
+ const transformedPkg = { ...pkg };
167
+
168
+ transformedPkg.maintainers = pkg.maintainers
169
+ ? JSON.parse(pkg.maintainers)
170
+ : [];
171
+
172
+ transformedPkg.scripts = pkg.scripts ? JSON.parse(pkg.scripts) : {};
173
+ transformedPkg.repository = pkg.repository
174
+ ? JSON.parse(pkg.repository)
175
+ : {};
176
+
177
+ transformedPkg.dependencies = pkg.dependencies
178
+ ? JSON.parse(pkg.dependencies)
179
+ : [];
180
+ transformedPkg.devDependencies = pkg.devDependencies
181
+ ? JSON.parse(pkg.devDependencies)
182
+ : [];
183
+ transformedPkg.peerDependencies = pkg.peerDependencies
184
+ ? JSON.parse(pkg.peerDependencies)
185
+ : [];
186
+ return transformedPkg;
187
+ });
188
+
189
+ return transformedPackages;
164
190
  }
165
191
 
166
192
  export const getPackageDetailService = async (name: string) => {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Type declarations for swagger-jsdoc
3
+ * Provides TypeScript support for swagger-jsdoc module
4
+ */
5
+
6
+ declare module 'swagger-jsdoc' {
7
+ interface SwaggerOptions {
8
+ definition?: Record<string, unknown>;
9
+ apis?: string[];
10
+ }
11
+
12
+ function swaggerJsDoc(options: SwaggerOptions): Record<string, unknown>;
13
+
14
+ export = swaggerJsDoc;
15
+ }
@@ -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
- }