@manojkmfsi/monodog 1.1.6 → 1.1.8

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 (53) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/package.json +1 -1
  4. package/src/config/swagger-config.ts +0 -344
  5. package/src/config-loader.ts +0 -97
  6. package/src/constants/index.ts +0 -13
  7. package/src/constants/middleware.ts +0 -83
  8. package/src/constants/port.ts +0 -20
  9. package/src/constants/security.ts +0 -78
  10. package/src/controllers/commit-controller.ts +0 -31
  11. package/src/controllers/config-controller.ts +0 -42
  12. package/src/controllers/health-controller.ts +0 -24
  13. package/src/controllers/package-controller.ts +0 -67
  14. package/src/get-db-url.ts +0 -9
  15. package/src/index.ts +0 -9
  16. package/src/middleware/dashboard-startup.ts +0 -161
  17. package/src/middleware/error-handler.ts +0 -50
  18. package/src/middleware/index.ts +0 -20
  19. package/src/middleware/logger.ts +0 -65
  20. package/src/middleware/security.ts +0 -90
  21. package/src/middleware/server-startup.ts +0 -153
  22. package/src/middleware/swagger-middleware.ts +0 -58
  23. package/src/repositories/commit-repository.ts +0 -108
  24. package/src/repositories/dependency-repository.ts +0 -110
  25. package/src/repositories/index.ts +0 -10
  26. package/src/repositories/package-health-repository.ts +0 -75
  27. package/src/repositories/package-repository.ts +0 -142
  28. package/src/repositories/prisma-client.ts +0 -25
  29. package/src/routes/commit-routes.ts +0 -10
  30. package/src/routes/config-routes.ts +0 -14
  31. package/src/routes/health-routes.ts +0 -14
  32. package/src/routes/package-routes.ts +0 -22
  33. package/src/serve.ts +0 -41
  34. package/src/services/commit-service.ts +0 -44
  35. package/src/services/config-service.ts +0 -391
  36. package/src/services/git-service.ts +0 -140
  37. package/src/services/health-service.ts +0 -162
  38. package/src/services/package-service.ts +0 -228
  39. package/src/setup.ts +0 -78
  40. package/src/types/ci.ts +0 -122
  41. package/src/types/config.ts +0 -22
  42. package/src/types/database.ts +0 -67
  43. package/src/types/git.ts +0 -33
  44. package/src/types/health.ts +0 -11
  45. package/src/types/index.ts +0 -23
  46. package/src/types/package.ts +0 -39
  47. package/src/types/scanner.ts +0 -31
  48. package/src/types/swagger-jsdoc.d.ts +0 -15
  49. package/src/utils/ci-status.ts +0 -535
  50. package/src/utils/db-utils.ts +0 -92
  51. package/src/utils/health-utils.ts +0 -67
  52. package/src/utils/monorepo-scanner.ts +0 -576
  53. package/src/utils/utilities.ts +0 -427
@@ -1,576 +0,0 @@
1
- // Monorepo Scanner
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { execSync } from 'child_process';
5
- import { AppLogger } from '../middleware/logger';
6
- import type {
7
- PackageInfo,
8
- DependencyInfo,
9
- PackageHealth,
10
- MonorepoStats,
11
- ScanResult,
12
- PackageReport,
13
- } from '../types';
14
- import {
15
- scanMonorepo,
16
- calculatePackageHealth,
17
- generateMonorepoStats,
18
- findCircularDependencies,
19
- generateDependencyGraph,
20
- checkOutdatedDependencies,
21
- getPackageSize,
22
- } from './utilities';
23
-
24
- export class MonorepoScanner {
25
- private rootDir: string;
26
- private cache: Map<string, any> = new Map();
27
- private cacheExpiry = 5 * 60 * 1000; // 5 minutes
28
-
29
- constructor(rootDir: string = process.cwd()) {
30
- this.rootDir = rootDir;
31
- }
32
-
33
- /**
34
- * Performs a complete scan of the monorepo
35
- */
36
- async scan(): Promise<ScanResult> {
37
- const startTime = Date.now();
38
-
39
- try {
40
- // Check cache first
41
- const cacheKey = 'full-scan';
42
- const cached = this.getFromCache(cacheKey);
43
- if (cached) {
44
- return cached;
45
- }
46
-
47
- AppLogger.debug('Starting monorepo scan...');
48
-
49
- // Scan all packages
50
- const packages = scanMonorepo(this.rootDir);
51
- AppLogger.debug(`Found ${packages.length} packages`);
52
-
53
- // Generate statistics
54
- const stats = generateMonorepoStats(packages);
55
-
56
- // Generate dependency graph
57
- const dependencyGraph = generateDependencyGraph(packages);
58
-
59
- // Find circular dependencies
60
- const circularDependencies = findCircularDependencies(packages);
61
-
62
- // Check for outdated packages
63
- const outdatedPackages = this.findOutdatedPackages(packages);
64
-
65
- const result: ScanResult = {
66
- packages,
67
- stats,
68
- dependencyGraph,
69
- circularDependencies,
70
- outdatedPackages,
71
- scanTimestamp: new Date(),
72
- scanDuration: Date.now() - startTime,
73
- };
74
-
75
- // Cache the result
76
- this.setCache(cacheKey, result);
77
-
78
- AppLogger.debug(`Scan completed in ${result.scanDuration}ms`);
79
- return result;
80
- } catch (error) {
81
- AppLogger.error('Error during scan', error as Error);
82
- throw error;
83
- }
84
- }
85
-
86
- /**
87
- * Generates detailed reports for all packages
88
- */
89
- async generatePackageReports(): Promise<PackageReport[]> {
90
- const packages = scanMonorepo(this.rootDir);
91
- const reports: PackageReport[] = [];
92
-
93
- for (const pkg of packages) {
94
- try {
95
- const report = await this.generatePackageReport(pkg);
96
- reports.push(report);
97
- } catch (error) {
98
- AppLogger.error(`Error generating report for ${pkg.name}`, error as Error);
99
- }
100
- }
101
-
102
- return reports;
103
- }
104
-
105
- /**
106
- * Generates a detailed report for a specific package
107
- */
108
- async generatePackageReport(pkg: PackageInfo): Promise<PackageReport> {
109
- const health = await this.assessPackageHealth(pkg);
110
- const size = getPackageSize(pkg.path);
111
- const outdatedDeps = checkOutdatedDependencies(pkg);
112
- const lastModified = this.getLastModified(pkg.path);
113
- const gitInfo = await this.getGitInfo(pkg.path);
114
-
115
- return {
116
- package: pkg,
117
- health,
118
- size,
119
- outdatedDeps,
120
- lastModified,
121
- gitInfo,
122
- };
123
- }
124
-
125
- /**
126
- * Assesses the health of a package
127
- */
128
- private async assessPackageHealth(pkg: PackageInfo): Promise<PackageHealth> {
129
- // Check build status
130
- const buildStatus = await this.checkBuildStatus(pkg);
131
-
132
- // Check test coverage
133
- const testCoverage = await this.checkTestCoverage(pkg);
134
-
135
- // Check lint status
136
- const lintStatus = await this.checkLintStatus(pkg);
137
-
138
- // Check security audit
139
- const securityAudit = await this.checkSecurityAudit(pkg);
140
-
141
- return calculatePackageHealth(
142
- buildStatus,
143
- testCoverage,
144
- lintStatus,
145
- securityAudit
146
- );
147
- }
148
-
149
- /**
150
- * Checks if a package builds successfully
151
- */
152
- async checkBuildStatus(
153
- pkg: PackageInfo
154
- ): Promise<PackageHealth['buildStatus']> {
155
- try {
156
- if (pkg.scripts.build) {
157
- // Try to run build command
158
- execSync('npm run build', {
159
- cwd: pkg.path,
160
- stdio: 'pipe',
161
- timeout: 30000,
162
- });
163
- return 'success';
164
- }
165
- return 'unknown';
166
- } catch (error) {
167
- return 'failed';
168
- }
169
- }
170
-
171
- /**
172
- * Checks test coverage for a package
173
- */
174
- // async checkTestCoverage(pkg: PackageInfo): Promise<number> {
175
- // try {
176
- // if (pkg.scripts.test) {
177
- // // This would typically run tests and parse coverage reports
178
- // // For now, return a mock value
179
- // return Math.floor(Math.random() * 100);
180
- // }
181
- // return 0;
182
- // } catch (error) {
183
- // return 0;
184
- // }
185
- // }
186
- async checkTestCoverage(pkg: PackageInfo): Promise<number> {
187
- try {
188
- // First, check for existing coverage reports
189
- const coveragePaths = [
190
- path.join(pkg.path, 'coverage', 'coverage-summary.json'),
191
- path.join(pkg.path, 'coverage', 'lcov.info'),
192
- path.join(pkg.path, 'coverage', 'clover.xml'),
193
- path.join(pkg.path, 'coverage.json'),
194
- ];
195
-
196
- // Look for any coverage file that exists
197
- for (const coveragePath of coveragePaths) {
198
- if (fs.existsSync(coveragePath)) {
199
- if (coveragePath.endsWith('coverage-summary.json')) {
200
- try {
201
- const coverage = JSON.parse(
202
- fs.readFileSync(coveragePath, 'utf8')
203
- );
204
- return (
205
- coverage.total?.lines?.pct ||
206
- coverage.total?.statements?.pct ||
207
- 0
208
- );
209
- } catch (error) {
210
- AppLogger.warn(`Error parsing coverage file for ${pkg.name}`);
211
- }
212
- }
213
- // If we find any coverage file but can't parse it, assume coverage exists
214
- return 0; // Default coverage if files exist but can't parse
215
- }
216
- }
217
-
218
- // If no coverage files found and package has test script
219
- if (pkg.scripts.test) {
220
- // Return a reasonable default based on whether tests are likely to have coverage
221
- const hasCoverageSetup =
222
- pkg.scripts.test.includes('--coverage') ||
223
- pkg.scripts.test.includes('coverage') ||
224
- pkg.devDependencies?.jest ||
225
- pkg.devDependencies?.nyc ||
226
- pkg.devDependencies?.['@types/jest'];
227
-
228
- return hasCoverageSetup ? 30 : 0; // Reasonable defaults
229
- }
230
-
231
- return 0;
232
- } catch (error) {
233
- AppLogger.warn(`Error checking coverage for ${pkg.name}`);
234
- return 0;
235
- }
236
- }
237
-
238
- /**
239
- * Checks lint status for a package
240
- */
241
- async checkLintStatus(
242
- pkg: PackageInfo
243
- ): Promise<PackageHealth['lintStatus']> {
244
- try {
245
- if (pkg.scripts.lint) {
246
- // Try to run lint command
247
- execSync('npm run lint', {
248
- cwd: pkg.path,
249
- stdio: 'pipe',
250
- timeout: 10000,
251
- });
252
- return 'pass';
253
- }
254
- return 'unknown';
255
- } catch (error) {
256
- return 'fail';
257
- }
258
- }
259
-
260
- /**
261
- * Checks security audit for a package
262
- */
263
- async checkSecurityAudit(
264
- pkg: PackageInfo
265
- ): Promise<PackageHealth['securityAudit']> {
266
- try {
267
- // Run npm audit
268
- const result = execSync('npm audit --json', {
269
- cwd: pkg.path,
270
- stdio: 'pipe',
271
- timeout: 15000,
272
- });
273
-
274
- const audit = JSON.parse(result.toString());
275
- return audit.metadata.vulnerabilities.total === 0 ? 'pass' : 'fail';
276
- } catch (error) {
277
- return 'unknown';
278
- }
279
- }
280
-
281
- /**
282
- * Finds packages with outdated dependencies
283
- */
284
- private findOutdatedPackages(packages: PackageInfo[]): string[] {
285
- const outdated: string[] = [];
286
-
287
- for (const pkg of packages) {
288
- const outdatedDeps = checkOutdatedDependencies(pkg);
289
- if (outdatedDeps.length > 0) {
290
- outdated.push(pkg.name);
291
- }
292
- }
293
-
294
- return outdated;
295
- }
296
-
297
- /**
298
- * Gets the last modified date of a package
299
- */
300
- private getLastModified(packagePath: string): Date {
301
- try {
302
- const stats = fs.statSync(packagePath);
303
- return stats.mtime;
304
- } catch (error) {
305
- return new Date();
306
- }
307
- }
308
-
309
- /**
310
- * Gets git information for a package
311
- */
312
- private async getGitInfo(
313
- packagePath: string
314
- ): Promise<PackageReport['gitInfo'] | undefined> {
315
- try {
316
- // Check if this is a git repository
317
- const gitPath = path.join(packagePath, '.git');
318
- if (!fs.existsSync(gitPath)) {
319
- return undefined;
320
- }
321
-
322
- // Get last commit info
323
- const lastCommit = execSync('git rev-parse HEAD', {
324
- cwd: packagePath,
325
- stdio: 'pipe',
326
- })
327
- .toString()
328
- .trim();
329
-
330
- const lastCommitDate = new Date(
331
- execSync('git log -1 --format=%cd', {
332
- cwd: packagePath,
333
- stdio: 'pipe',
334
- })
335
- .toString()
336
- .trim()
337
- );
338
-
339
- const author = execSync('git log -1 --format=%an', {
340
- cwd: packagePath,
341
- stdio: 'pipe',
342
- })
343
- .toString()
344
- .trim();
345
-
346
- const branch = execSync('git branch --show-current', {
347
- cwd: packagePath,
348
- stdio: 'pipe',
349
- })
350
- .toString()
351
- .trim();
352
-
353
- return {
354
- lastCommit: lastCommit.substring(0, 7),
355
- lastCommitDate,
356
- author,
357
- branch,
358
- };
359
- } catch (error) {
360
- return undefined;
361
- }
362
- }
363
-
364
- /**
365
- * Scans for specific file types in packages
366
- */
367
- scanForFileTypes(fileTypes: string[]): Record<string, string[]> {
368
- const results: Record<string, string[]> = {};
369
-
370
- for (const fileType of fileTypes) {
371
- results[fileType] = [];
372
- }
373
-
374
- const packages = scanMonorepo(this.rootDir);
375
-
376
- for (const pkg of packages) {
377
- this.scanPackageForFiles(pkg.path, fileTypes, results);
378
- }
379
-
380
- return results;
381
- }
382
-
383
- /**
384
- * Recursively scans a package directory for specific file types
385
- */
386
- private scanPackageForFiles(
387
- packagePath: string,
388
- fileTypes: string[],
389
- results: Record<string, string[]>
390
- ): void {
391
- try {
392
- const items = fs.readdirSync(packagePath, { withFileTypes: true });
393
-
394
- for (const item of items) {
395
- const fullPath = path.join(packagePath, item.name);
396
-
397
- if (item.isDirectory()) {
398
- // Skip certain directories
399
- if (!['node_modules', 'dist', 'build', '.git'].includes(item.name)) {
400
- this.scanPackageForFiles(fullPath, fileTypes, results);
401
- }
402
- } else {
403
- // Check file extension
404
- const ext = path.extname(item.name);
405
- if (fileTypes.includes(ext)) {
406
- results[ext].push(fullPath);
407
- }
408
- }
409
- }
410
- } catch (error) {
411
- // Skip directories we can't read
412
- }
413
- }
414
-
415
- /**
416
- * Gets cache value if not expired
417
- */
418
- private getFromCache(key: string): any {
419
- const cached = this.cache.get(key);
420
- if (cached && Date.now() - cached.timestamp < this.cacheExpiry) {
421
- return cached.data;
422
- }
423
- return null;
424
- }
425
-
426
- /**
427
- * Sets cache value with timestamp
428
- */
429
- private setCache(key: string, data: any): void {
430
- this.cache.set(key, {
431
- data,
432
- timestamp: Date.now(),
433
- });
434
- }
435
-
436
- /**
437
- * Clears the cache
438
- */
439
- clearCache(): void {
440
- this.cache.clear();
441
- }
442
-
443
- /**
444
- * Exports scan results to various formats
445
- */
446
- exportResults(results: ScanResult, format: 'json' | 'csv' | 'html'): string {
447
- switch (format) {
448
- case 'json':
449
- return JSON.stringify(results, null, 2);
450
- case 'csv':
451
- return this.exportToCSV(results);
452
- case 'html':
453
- return this.exportToHTML(results);
454
- default:
455
- throw new Error(`Unsupported format: ${format}`);
456
- }
457
- }
458
-
459
- /**
460
- * Exports results to CSV format
461
- */
462
- private exportToCSV(results: ScanResult): string {
463
- const headers = [
464
- 'Package',
465
- 'Type',
466
- 'Version',
467
- 'Dependencies',
468
- 'Health Score',
469
- ];
470
- const rows = results.packages.map(pkg => [
471
- pkg.name,
472
- pkg.type,
473
- pkg.version,
474
- Object.keys(pkg.dependencies).length,
475
- 'N/A', // Would need health calculation
476
- ]);
477
-
478
- return [headers, ...rows]
479
- .map(row => row.map(cell => `"${cell}"`).join(','))
480
- .join('\n');
481
- }
482
-
483
- /**
484
- * Exports results to HTML format
485
- */
486
- private exportToHTML(results: ScanResult): string {
487
- return `
488
- <!DOCTYPE html>
489
- <html>
490
- <head>
491
- <title>Monorepo Scan Report</title>
492
- <style>
493
- body { font-family: Arial, sans-serif; margin: 20px; }
494
- table { border-collapse: collapse; width: 100%; }
495
- th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
496
- th { background-color: #f2f2f2; }
497
- </style>
498
- </head>
499
- <body>
500
- <h1>Monorepo Scan Report</h1>
501
- <p>Generated: ${results.scanTimestamp}</p>
502
- <p>Duration: ${results.scanDuration}ms</p>
503
-
504
- <h2>Summary</h2>
505
- <ul>
506
- <li>Total Packages: ${results.stats.totalPackages}</li>
507
- <li>Applications: ${results.stats.apps}</li>
508
- <li>Libraries: ${results.stats.libraries}</li>
509
- <li>Tools: ${results.stats.tools}</li>
510
- </ul>
511
-
512
- <h2>Packages</h2>
513
- <table>
514
- <tr>
515
- <th>Name</th>
516
- <th>Type</th>
517
- <th>Version</th>
518
- <th>Dependencies</th>
519
- </tr>
520
- ${results.packages
521
- .map(
522
- pkg => `
523
- <tr>
524
- <td>${pkg.name}</td>
525
- <td>${pkg.type}</td>
526
- <td>${pkg.version}</td>
527
- <td>${Object.keys(pkg.dependencies).length}</td>
528
- </tr>
529
- `
530
- )
531
- .join('')}
532
- </table>
533
- </body>
534
- </html>
535
- `;
536
- }
537
- }
538
-
539
- // Export default instance
540
- export const scanner = new MonorepoScanner();
541
-
542
- // Export convenience functions
543
- export async function quickScan(): Promise<ScanResult> {
544
- return scanner.scan();
545
- }
546
-
547
- export async function generateReports(): Promise<PackageReport[]> {
548
- return scanner.generatePackageReports();
549
- }
550
-
551
- export function scanForFiles(fileTypes: string[]): Record<string, string[]> {
552
- return scanner.scanForFileTypes(fileTypes);
553
- }
554
-
555
- // Fix these function signatures - they should accept single PackageInfo objects
556
- export async function funCheckBuildStatus(
557
- pkg: PackageInfo
558
- ): Promise<PackageHealth['buildStatus']> {
559
- return scanner.checkBuildStatus(pkg);
560
- }
561
-
562
- export async function funCheckTestCoverage(pkg: PackageInfo): Promise<number> {
563
- return scanner.checkTestCoverage(pkg);
564
- }
565
-
566
- export async function funCheckLintStatus(
567
- pkg: PackageInfo
568
- ): Promise<PackageHealth['lintStatus']> {
569
- return scanner.checkLintStatus(pkg);
570
- }
571
-
572
- export async function funCheckSecurityAudit(
573
- pkg: PackageInfo
574
- ): Promise<PackageHealth['securityAudit']> {
575
- return scanner.checkSecurityAudit(pkg);
576
- }