@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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/config/swagger-config.js +345 -0
- 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 +20 -21
- package/dist/middleware/error-handler.js +3 -10
- package/dist/middleware/index.js +4 -2
- package/dist/middleware/logger.js +63 -0
- package/dist/middleware/security.js +11 -10
- package/dist/middleware/server-startup.js +32 -25
- 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/serve.js +15 -2
- package/dist/services/health-service.js +84 -64
- package/dist/services/package-service.js +23 -1
- package/monodog-dashboard/dist/assets/{index-746f6c13.js → index-45e19f29.js} +1 -1
- package/monodog-dashboard/dist/index.html +1 -1
- package/package.json +14 -4
- package/prisma/schema/commit.prisma +11 -0
- package/prisma/schema/dependency-info.prisma +12 -0
- package/prisma/schema/health-status.prisma +14 -0
- package/prisma/schema/package-health.prisma +15 -0
- package/prisma/schema/package.prisma +21 -0
- package/prisma/schema/schema.prisma +15 -0
- package/src/config/swagger-config.ts +344 -0
- 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 +35 -24
- package/src/middleware/error-handler.ts +2 -15
- package/src/middleware/index.ts +3 -1
- package/src/middleware/logger.ts +58 -0
- package/src/middleware/security.ts +19 -10
- package/src/middleware/server-startup.ts +43 -30
- 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/serve.ts +19 -3
- 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/prisma/schema.prisma +0 -116
- /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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
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
|
+
}
|
package/prisma/schema.prisma
DELETED
|
@@ -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
|
-
}
|