guardrail-core 1.0.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 (189) hide show
  1. package/dist/__tests__/autopilot.test.d.ts +7 -0
  2. package/dist/__tests__/autopilot.test.d.ts.map +1 -0
  3. package/dist/__tests__/autopilot.test.js +156 -0
  4. package/dist/__tests__/tier-config.test.d.ts +9 -0
  5. package/dist/__tests__/tier-config.test.d.ts.map +1 -0
  6. package/dist/__tests__/tier-config.test.js +230 -0
  7. package/dist/__tests__/utils/hash-inline.test.d.ts +2 -0
  8. package/dist/__tests__/utils/hash-inline.test.d.ts.map +1 -0
  9. package/dist/__tests__/utils/hash-inline.test.js +62 -0
  10. package/dist/__tests__/utils/hash.test.d.ts +3 -0
  11. package/dist/__tests__/utils/hash.test.d.ts.map +1 -0
  12. package/dist/__tests__/utils/hash.test.js +95 -0
  13. package/dist/__tests__/utils/simple.test.d.ts +1 -0
  14. package/dist/__tests__/utils/simple.test.d.ts.map +1 -0
  15. package/dist/__tests__/utils/simple.test.js +10 -0
  16. package/dist/__tests__/utils/utils-simple.test.d.ts +1 -0
  17. package/dist/__tests__/utils/utils-simple.test.d.ts.map +1 -0
  18. package/dist/__tests__/utils/utils-simple.test.js +6 -0
  19. package/dist/__tests__/utils/utils.test.d.ts +15 -0
  20. package/dist/__tests__/utils/utils.test.d.ts.map +1 -0
  21. package/dist/__tests__/utils/utils.test.js +172 -0
  22. package/dist/autopilot/autopilot-runner.d.ts +33 -0
  23. package/dist/autopilot/autopilot-runner.d.ts.map +1 -0
  24. package/dist/autopilot/autopilot-runner.js +479 -0
  25. package/dist/autopilot/index.d.ts +6 -0
  26. package/dist/autopilot/index.d.ts.map +1 -0
  27. package/dist/autopilot/index.js +25 -0
  28. package/dist/autopilot/types.d.ts +102 -0
  29. package/dist/autopilot/types.d.ts.map +1 -0
  30. package/dist/autopilot/types.js +18 -0
  31. package/dist/cache/index.d.ts +7 -0
  32. package/dist/cache/index.d.ts.map +1 -0
  33. package/dist/cache/index.js +22 -0
  34. package/dist/cache/redis-cache.d.ts +145 -0
  35. package/dist/cache/redis-cache.d.ts.map +1 -0
  36. package/dist/cache/redis-cache.js +459 -0
  37. package/dist/ci/github-actions.d.ts +77 -0
  38. package/dist/ci/github-actions.d.ts.map +1 -0
  39. package/dist/ci/github-actions.js +277 -0
  40. package/dist/ci/index.d.ts +12 -0
  41. package/dist/ci/index.d.ts.map +1 -0
  42. package/dist/ci/index.js +27 -0
  43. package/dist/ci/pre-commit.d.ts +65 -0
  44. package/dist/ci/pre-commit.d.ts.map +1 -0
  45. package/dist/ci/pre-commit.js +286 -0
  46. package/dist/entitlements.d.ts +149 -0
  47. package/dist/entitlements.d.ts.map +1 -0
  48. package/dist/entitlements.js +464 -0
  49. package/dist/env.d.ts +113 -0
  50. package/dist/env.d.ts.map +1 -0
  51. package/dist/env.js +204 -0
  52. package/dist/fix-packs/__tests__/generate-fix-packs.test.d.ts +7 -0
  53. package/dist/fix-packs/__tests__/generate-fix-packs.test.d.ts.map +1 -0
  54. package/dist/fix-packs/__tests__/generate-fix-packs.test.js +250 -0
  55. package/dist/fix-packs/generate-fix-packs.d.ts +15 -0
  56. package/dist/fix-packs/generate-fix-packs.d.ts.map +1 -0
  57. package/dist/fix-packs/generate-fix-packs.js +505 -0
  58. package/dist/fix-packs/index.d.ts +8 -0
  59. package/dist/fix-packs/index.d.ts.map +1 -0
  60. package/dist/fix-packs/index.js +23 -0
  61. package/dist/fix-packs/types.d.ts +113 -0
  62. package/dist/fix-packs/types.d.ts.map +1 -0
  63. package/dist/fix-packs/types.js +71 -0
  64. package/dist/index.d.ts +13 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +28 -0
  67. package/dist/metrics/prometheus.d.ts +99 -0
  68. package/dist/metrics/prometheus.d.ts.map +1 -0
  69. package/dist/metrics/prometheus.js +306 -0
  70. package/dist/quota-ledger.d.ts +119 -0
  71. package/dist/quota-ledger.d.ts.map +1 -0
  72. package/dist/quota-ledger.js +462 -0
  73. package/dist/rbac/__tests__/permissions.test.d.ts +8 -0
  74. package/dist/rbac/__tests__/permissions.test.d.ts.map +1 -0
  75. package/dist/rbac/__tests__/permissions.test.js +350 -0
  76. package/dist/rbac/index.d.ts +9 -0
  77. package/dist/rbac/index.d.ts.map +1 -0
  78. package/dist/rbac/index.js +32 -0
  79. package/dist/rbac/permissions.d.ts +71 -0
  80. package/dist/rbac/permissions.d.ts.map +1 -0
  81. package/dist/rbac/permissions.js +247 -0
  82. package/dist/rbac/types.d.ts +69 -0
  83. package/dist/rbac/types.d.ts.map +1 -0
  84. package/dist/rbac/types.js +213 -0
  85. package/dist/tier-config.d.ts +203 -0
  86. package/dist/tier-config.d.ts.map +1 -0
  87. package/dist/tier-config.js +675 -0
  88. package/dist/types.d.ts +365 -0
  89. package/dist/types.d.ts.map +1 -0
  90. package/dist/types.js +5 -0
  91. package/dist/utils.d.ts +36 -0
  92. package/dist/utils.d.ts.map +1 -0
  93. package/dist/utils.js +127 -0
  94. package/dist/verified-autofix/__tests__/format-validator.test.d.ts +11 -0
  95. package/dist/verified-autofix/__tests__/format-validator.test.d.ts.map +1 -0
  96. package/dist/verified-autofix/__tests__/format-validator.test.js +285 -0
  97. package/dist/verified-autofix/__tests__/pipeline.test.d.ts +11 -0
  98. package/dist/verified-autofix/__tests__/pipeline.test.d.ts.map +1 -0
  99. package/dist/verified-autofix/__tests__/pipeline.test.js +389 -0
  100. package/dist/verified-autofix/__tests__/repo-fingerprint.test.d.ts +11 -0
  101. package/dist/verified-autofix/__tests__/repo-fingerprint.test.d.ts.map +1 -0
  102. package/dist/verified-autofix/__tests__/repo-fingerprint.test.js +236 -0
  103. package/dist/verified-autofix/__tests__/workspace.test.d.ts +11 -0
  104. package/dist/verified-autofix/__tests__/workspace.test.d.ts.map +1 -0
  105. package/dist/verified-autofix/__tests__/workspace.test.js +314 -0
  106. package/dist/verified-autofix/format-validator.d.ts +101 -0
  107. package/dist/verified-autofix/format-validator.d.ts.map +1 -0
  108. package/dist/verified-autofix/format-validator.js +446 -0
  109. package/dist/verified-autofix/index.d.ts +14 -0
  110. package/dist/verified-autofix/index.d.ts.map +1 -0
  111. package/dist/verified-autofix/index.js +39 -0
  112. package/dist/verified-autofix/pipeline.d.ts +68 -0
  113. package/dist/verified-autofix/pipeline.d.ts.map +1 -0
  114. package/dist/verified-autofix/pipeline.js +330 -0
  115. package/dist/verified-autofix/repo-fingerprint.d.ts +56 -0
  116. package/dist/verified-autofix/repo-fingerprint.d.ts.map +1 -0
  117. package/dist/verified-autofix/repo-fingerprint.js +396 -0
  118. package/dist/verified-autofix/workspace.d.ts +83 -0
  119. package/dist/verified-autofix/workspace.d.ts.map +1 -0
  120. package/dist/verified-autofix/workspace.js +454 -0
  121. package/dist/verified-autofix.d.ts +182 -0
  122. package/dist/verified-autofix.d.ts.map +1 -0
  123. package/dist/verified-autofix.js +1021 -0
  124. package/dist/visualization/dependency-graph.d.ts +79 -0
  125. package/dist/visualization/dependency-graph.d.ts.map +1 -0
  126. package/dist/visualization/dependency-graph.js +399 -0
  127. package/dist/visualization/index.d.ts +5 -0
  128. package/dist/visualization/index.d.ts.map +1 -0
  129. package/dist/visualization/index.js +20 -0
  130. package/package.json +29 -0
  131. package/src/__tests__/autopilot.test.ts +196 -0
  132. package/src/__tests__/tier-config.test.ts +289 -0
  133. package/src/__tests__/utils/hash-inline.test.ts +76 -0
  134. package/src/__tests__/utils/hash.test.ts +119 -0
  135. package/src/__tests__/utils/simple.test.ts +10 -0
  136. package/src/__tests__/utils/utils-simple.test.ts +5 -0
  137. package/src/__tests__/utils/utils.test.ts +203 -0
  138. package/src/autopilot/autopilot-runner.ts +503 -0
  139. package/src/autopilot/index.ts +6 -0
  140. package/src/autopilot/types.ts +119 -0
  141. package/src/cache/index.ts +7 -0
  142. package/src/cache/redis-cache.d.ts +155 -0
  143. package/src/cache/redis-cache.d.ts.map +1 -0
  144. package/src/cache/redis-cache.ts +517 -0
  145. package/src/ci/github-actions.ts +335 -0
  146. package/src/ci/index.ts +12 -0
  147. package/src/ci/pre-commit.ts +338 -0
  148. package/src/db/usage-schema.prisma +114 -0
  149. package/src/entitlements.ts +570 -0
  150. package/src/env.d.ts +68 -0
  151. package/src/env.d.ts.map +1 -0
  152. package/src/env.ts +247 -0
  153. package/src/fix-packs/__tests__/generate-fix-packs.test.ts +317 -0
  154. package/src/fix-packs/generate-fix-packs.ts +577 -0
  155. package/src/fix-packs/index.ts +8 -0
  156. package/src/fix-packs/types.ts +206 -0
  157. package/src/index.d.ts +7 -0
  158. package/src/index.d.ts.map +1 -0
  159. package/src/index.ts +12 -0
  160. package/src/metrics/prometheus.d.ts +104 -0
  161. package/src/metrics/prometheus.d.ts.map +1 -0
  162. package/src/metrics/prometheus.ts +446 -0
  163. package/src/quota-ledger.ts +548 -0
  164. package/src/rbac/__tests__/permissions.test.ts +446 -0
  165. package/src/rbac/index.ts +46 -0
  166. package/src/rbac/permissions.ts +301 -0
  167. package/src/rbac/types.ts +298 -0
  168. package/src/tier-config.json +157 -0
  169. package/src/tier-config.ts +815 -0
  170. package/src/types.d.ts +365 -0
  171. package/src/types.d.ts.map +1 -0
  172. package/src/types.ts +441 -0
  173. package/src/utils.d.ts +36 -0
  174. package/src/utils.d.ts.map +1 -0
  175. package/src/utils.ts +140 -0
  176. package/src/verified-autofix/__tests__/format-validator.test.ts +335 -0
  177. package/src/verified-autofix/__tests__/pipeline.test.ts +419 -0
  178. package/src/verified-autofix/__tests__/repo-fingerprint.test.ts +241 -0
  179. package/src/verified-autofix/__tests__/workspace.test.ts +373 -0
  180. package/src/verified-autofix/format-validator.ts +517 -0
  181. package/src/verified-autofix/index.ts +63 -0
  182. package/src/verified-autofix/pipeline.ts +403 -0
  183. package/src/verified-autofix/repo-fingerprint.ts +459 -0
  184. package/src/verified-autofix/workspace.ts +531 -0
  185. package/src/verified-autofix.ts +1187 -0
  186. package/src/visualization/dependency-graph.d.ts +85 -0
  187. package/src/visualization/dependency-graph.d.ts.map +1 -0
  188. package/src/visualization/dependency-graph.ts +495 -0
  189. package/src/visualization/index.ts +5 -0
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Visual Dependency Graph Generator
3
+ *
4
+ * Generates interactive dependency graphs showing:
5
+ * - Package dependencies and their relationships
6
+ * - Vulnerability status of each package
7
+ * - License compatibility
8
+ * - Security risk levels
9
+ */
10
+ export interface DependencyNode {
11
+ id: string;
12
+ name: string;
13
+ version: string;
14
+ type: "root" | "direct" | "transitive";
15
+ vulnerabilities: VulnerabilityInfo[];
16
+ license: string;
17
+ riskLevel: "none" | "low" | "medium" | "high" | "critical";
18
+ depth: number;
19
+ size?: number;
20
+ }
21
+ export interface DependencyEdge {
22
+ source: string;
23
+ target: string;
24
+ type: "dependency" | "devDependency" | "peerDependency";
25
+ }
26
+ export interface VulnerabilityInfo {
27
+ id: string;
28
+ severity: "low" | "medium" | "high" | "critical";
29
+ title: string;
30
+ }
31
+ export interface DependencyGraph {
32
+ nodes: DependencyNode[];
33
+ edges: DependencyEdge[];
34
+ metadata: {
35
+ projectName: string;
36
+ totalPackages: number;
37
+ vulnerablePackages: number;
38
+ riskDistribution: Record<string, number>;
39
+ generatedAt: string;
40
+ };
41
+ }
42
+ export interface GraphRenderOptions {
43
+ format: "svg" | "html" | "json" | "d3" | "mermaid";
44
+ width?: number;
45
+ height?: number;
46
+ showVulnerabilities?: boolean;
47
+ showLicenses?: boolean;
48
+ highlightVulnerable?: boolean;
49
+ maxDepth?: number;
50
+ colorScheme?: "default" | "colorblind" | "dark";
51
+ }
52
+ export declare class DependencyGraphGenerator {
53
+ /**
54
+ * Generate dependency graph from package.json
55
+ */
56
+ generateFromPackageJson(
57
+ packageJsonPath: string,
58
+ options?: Partial<GraphRenderOptions>,
59
+ ): Promise<DependencyGraph>;
60
+ /**
61
+ * Create a dependency node
62
+ */
63
+ private createNode;
64
+ /**
65
+ * Get transitive dependencies
66
+ */
67
+ private getTransitiveDeps;
68
+ /**
69
+ * Render graph to Mermaid format
70
+ */
71
+ renderToMermaid(graph: DependencyGraph): string;
72
+ /**
73
+ * Render graph to D3.js compatible JSON
74
+ */
75
+ renderToD3(graph: DependencyGraph): string;
76
+ /**
77
+ * Render graph to HTML with embedded visualization
78
+ */
79
+ renderToHTML(
80
+ graph: DependencyGraph,
81
+ options?: Partial<GraphRenderOptions>,
82
+ ): string;
83
+ }
84
+ export declare const dependencyGraphGenerator: DependencyGraphGenerator;
85
+ //# sourceMappingURL=dependency-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["dependency-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;IACvC,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,GAAG,eAAe,GAAG,gBAAgB,CAAC;CACzD;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACjD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,EAAE;QACR,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzC,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;CACjD;AAED,qBAAa,wBAAwB;IACnC;;OAEG;IACG,uBAAuB,CAC3B,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,OAAO,CAAC,kBAAkB,CAAM,GACxC,OAAO,CAAC,eAAe,CAAC;IAyF3B;;OAEG;YACW,UAAU;IAoDxB;;OAEG;YACW,iBAAiB;IAgD/B;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAsC/C;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAqB1C;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAAG,MAAM;CA4HxF;AAGD,eAAO,MAAM,wBAAwB,0BAAiC,CAAC"}
@@ -0,0 +1,495 @@
1
+ /**
2
+ * Visual Dependency Graph Generator
3
+ *
4
+ * Generates interactive dependency graphs showing:
5
+ * - Package dependencies and their relationships
6
+ * - Vulnerability status of each package
7
+ * - License compatibility
8
+ * - Security risk levels
9
+ */
10
+
11
+ export interface DependencyNode {
12
+ id: string;
13
+ name: string;
14
+ version: string;
15
+ type: "root" | "direct" | "transitive";
16
+ vulnerabilities: VulnerabilityInfo[];
17
+ license: string;
18
+ riskLevel: "none" | "low" | "medium" | "high" | "critical";
19
+ depth: number;
20
+ size?: number;
21
+ }
22
+
23
+ export interface DependencyEdge {
24
+ source: string;
25
+ target: string;
26
+ type: "dependency" | "devDependency" | "peerDependency";
27
+ }
28
+
29
+ export interface VulnerabilityInfo {
30
+ id: string;
31
+ severity: "low" | "medium" | "high" | "critical";
32
+ title: string;
33
+ }
34
+
35
+ export interface DependencyGraph {
36
+ nodes: DependencyNode[];
37
+ edges: DependencyEdge[];
38
+ metadata: {
39
+ projectName: string;
40
+ totalPackages: number;
41
+ vulnerablePackages: number;
42
+ riskDistribution: Record<string, number>;
43
+ generatedAt: string;
44
+ };
45
+ }
46
+
47
+ export interface GraphRenderOptions {
48
+ format: "svg" | "html" | "json" | "d3" | "mermaid";
49
+ width?: number;
50
+ height?: number;
51
+ showVulnerabilities?: boolean;
52
+ showLicenses?: boolean;
53
+ highlightVulnerable?: boolean;
54
+ maxDepth?: number;
55
+ colorScheme?: "default" | "colorblind" | "dark";
56
+ }
57
+
58
+ export class DependencyGraphGenerator {
59
+ /**
60
+ * Generate dependency graph from package.json
61
+ */
62
+ async generateFromPackageJson(
63
+ packageJsonPath: string,
64
+ options: Partial<GraphRenderOptions> = {},
65
+ ): Promise<DependencyGraph> {
66
+ const { readFileSync } = await import("fs");
67
+ const { dirname } = await import("path");
68
+
69
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
70
+ const projectDir = dirname(packageJsonPath);
71
+
72
+ const nodes: DependencyNode[] = [];
73
+ const edges: DependencyEdge[] = [];
74
+ const visited = new Set<string>();
75
+
76
+ // Add root node
77
+ const rootId = `${packageJson.name}@${packageJson.version}`;
78
+ nodes.push({
79
+ id: rootId,
80
+ name: packageJson.name || "root",
81
+ version: packageJson.version || "0.0.0",
82
+ type: "root",
83
+ vulnerabilities: [],
84
+ license: packageJson.license || "UNKNOWN",
85
+ riskLevel: "none",
86
+ depth: 0,
87
+ });
88
+
89
+ // Process direct dependencies
90
+ const deps = packageJson.dependencies || {};
91
+ const devDeps = packageJson.devDependencies || {};
92
+
93
+ for (const [name, version] of Object.entries(deps)) {
94
+ const nodeId = `${name}@${version}`;
95
+ if (!visited.has(nodeId)) {
96
+ visited.add(nodeId);
97
+ const node = await this.createNode(
98
+ name,
99
+ String(version),
100
+ "direct",
101
+ 1,
102
+ projectDir,
103
+ );
104
+ nodes.push(node);
105
+ edges.push({ source: rootId, target: nodeId, type: "dependency" });
106
+
107
+ // Check for transitive dependencies
108
+ if (options.maxDepth !== 1) {
109
+ const transitives = await this.getTransitiveDeps(
110
+ name,
111
+ projectDir,
112
+ visited,
113
+ 2,
114
+ options.maxDepth || 3,
115
+ );
116
+ for (const trans of transitives.nodes) {
117
+ nodes.push(trans);
118
+ }
119
+ for (const edge of transitives.edges) {
120
+ edges.push(edge);
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ for (const [name, version] of Object.entries(devDeps)) {
127
+ const nodeId = `${name}@${version}`;
128
+ if (!visited.has(nodeId)) {
129
+ visited.add(nodeId);
130
+ const node = await this.createNode(
131
+ name,
132
+ String(version),
133
+ "direct",
134
+ 1,
135
+ projectDir,
136
+ );
137
+ nodes.push(node);
138
+ edges.push({ source: rootId, target: nodeId, type: "devDependency" });
139
+ }
140
+ }
141
+
142
+ // Calculate risk distribution
143
+ const riskDistribution: Record<string, number> = {
144
+ none: 0,
145
+ low: 0,
146
+ medium: 0,
147
+ high: 0,
148
+ critical: 0,
149
+ };
150
+ for (const node of nodes) {
151
+ const level = node.riskLevel;
152
+ if (typeof riskDistribution[level] === "number") {
153
+ riskDistribution[level]++;
154
+ }
155
+ }
156
+
157
+ const vulnerablePackages = nodes.filter(
158
+ (n) => n.vulnerabilities.length > 0,
159
+ ).length;
160
+
161
+ return {
162
+ nodes,
163
+ edges,
164
+ metadata: {
165
+ projectName: packageJson.name || "unknown",
166
+ totalPackages: nodes.length,
167
+ vulnerablePackages,
168
+ riskDistribution,
169
+ generatedAt: new Date().toISOString(),
170
+ },
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Create a dependency node
176
+ */
177
+ private async createNode(
178
+ name: string,
179
+ version: string,
180
+ type: "root" | "direct" | "transitive",
181
+ depth: number,
182
+ projectDir: string,
183
+ ): Promise<DependencyNode> {
184
+ const { existsSync, readFileSync } = await import("fs");
185
+ const { join } = await import("path");
186
+
187
+ const versionStr = String(version).replace(/^[\^~]/, "");
188
+ const nodeId = `${name}@${version}`;
189
+
190
+ // Try to get license from node_modules
191
+ let license = "UNKNOWN";
192
+ const pkgPath = join(projectDir, "node_modules", name, "package.json");
193
+ if (existsSync(pkgPath)) {
194
+ try {
195
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
196
+ license = pkg.license || "UNKNOWN";
197
+ } catch {
198
+ // Skip
199
+ }
200
+ }
201
+
202
+ // Placeholder for vulnerability check - would integrate with vulnerability DB
203
+ const vulnerabilities: VulnerabilityInfo[] = [];
204
+
205
+ // Calculate risk level based on vulnerabilities
206
+ let riskLevel: "none" | "low" | "medium" | "high" | "critical" = "none";
207
+ if (vulnerabilities.some((v) => v.severity === "critical")) {
208
+ riskLevel = "critical";
209
+ } else if (vulnerabilities.some((v) => v.severity === "high")) {
210
+ riskLevel = "high";
211
+ } else if (vulnerabilities.some((v) => v.severity === "medium")) {
212
+ riskLevel = "medium";
213
+ } else if (vulnerabilities.length > 0) {
214
+ riskLevel = "low";
215
+ }
216
+
217
+ return {
218
+ id: nodeId,
219
+ name,
220
+ version: versionStr,
221
+ type,
222
+ vulnerabilities,
223
+ license,
224
+ riskLevel,
225
+ depth,
226
+ };
227
+ }
228
+
229
+ /**
230
+ * Get transitive dependencies
231
+ */
232
+ private async getTransitiveDeps(
233
+ packageName: string,
234
+ projectDir: string,
235
+ visited: Set<string>,
236
+ currentDepth: number,
237
+ maxDepth: number,
238
+ ): Promise<{ nodes: DependencyNode[]; edges: DependencyEdge[] }> {
239
+ const { existsSync, readFileSync } = await import("fs");
240
+ const { join } = await import("path");
241
+
242
+ const nodes: DependencyNode[] = [];
243
+ const edges: DependencyEdge[] = [];
244
+
245
+ if (currentDepth > maxDepth) {
246
+ return { nodes, edges };
247
+ }
248
+
249
+ const pkgPath = join(
250
+ projectDir,
251
+ "node_modules",
252
+ packageName,
253
+ "package.json",
254
+ );
255
+ if (!existsSync(pkgPath)) {
256
+ return { nodes, edges };
257
+ }
258
+
259
+ try {
260
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
261
+ const deps = pkg.dependencies || {};
262
+ const parentId = `${packageName}@${pkg.version}`;
263
+
264
+ for (const [name, version] of Object.entries(deps)) {
265
+ const nodeId = `${name}@${version}`;
266
+ if (!visited.has(nodeId)) {
267
+ visited.add(nodeId);
268
+ const node = await this.createNode(
269
+ name,
270
+ String(version),
271
+ "transitive",
272
+ currentDepth,
273
+ projectDir,
274
+ );
275
+ nodes.push(node);
276
+ edges.push({ source: parentId, target: nodeId, type: "dependency" });
277
+
278
+ // Recurse for deeper transitive deps
279
+ const deeper = await this.getTransitiveDeps(
280
+ name,
281
+ projectDir,
282
+ visited,
283
+ currentDepth + 1,
284
+ maxDepth,
285
+ );
286
+ nodes.push(...deeper.nodes);
287
+ edges.push(...deeper.edges);
288
+ }
289
+ }
290
+ } catch {
291
+ // Skip packages we can't read
292
+ }
293
+
294
+ return { nodes, edges };
295
+ }
296
+
297
+ /**
298
+ * Render graph to Mermaid format
299
+ */
300
+ renderToMermaid(graph: DependencyGraph): string {
301
+ const lines: string[] = ["graph TD"];
302
+
303
+ // Define node styles based on risk level
304
+ const riskStyles: Record<string, string> = {
305
+ none: "fill:#90EE90",
306
+ low: "fill:#FFFF99",
307
+ medium: "fill:#FFB347",
308
+ high: "fill:#FF6B6B",
309
+ critical: "fill:#FF0000,color:#fff",
310
+ };
311
+
312
+ // Add nodes
313
+ for (const node of graph.nodes) {
314
+ const label = `${node.name}@${node.version}`;
315
+ const safeId = node.id.replace(/[@./]/g, "_");
316
+ lines.push(` ${safeId}["${label}"]`);
317
+ }
318
+
319
+ // Add edges
320
+ for (const edge of graph.edges) {
321
+ const sourceId = edge.source.replace(/[@./]/g, "_");
322
+ const targetId = edge.target.replace(/[@./]/g, "_");
323
+ const edgeStyle = edge.type === "devDependency" ? "-->" : "-->";
324
+ lines.push(` ${sourceId} ${edgeStyle} ${targetId}`);
325
+ }
326
+
327
+ // Add styles
328
+ lines.push("");
329
+ for (const node of graph.nodes) {
330
+ const safeId = node.id.replace(/[@./]/g, "_");
331
+ const style = riskStyles[node.riskLevel];
332
+ lines.push(` style ${safeId} ${style}`);
333
+ }
334
+
335
+ return lines.join("\n");
336
+ }
337
+
338
+ /**
339
+ * Render graph to D3.js compatible JSON
340
+ */
341
+ renderToD3(graph: DependencyGraph): string {
342
+ const d3Data = {
343
+ nodes: graph.nodes.map((node) => ({
344
+ id: node.id,
345
+ name: node.name,
346
+ version: node.version,
347
+ group: node.type === "root" ? 1 : node.type === "direct" ? 2 : 3,
348
+ riskLevel: node.riskLevel,
349
+ vulnerabilities: node.vulnerabilities.length,
350
+ license: node.license,
351
+ })),
352
+ links: graph.edges.map((edge) => ({
353
+ source: edge.source,
354
+ target: edge.target,
355
+ type: edge.type,
356
+ })),
357
+ };
358
+
359
+ return JSON.stringify(d3Data, null, 2);
360
+ }
361
+
362
+ /**
363
+ * Render graph to HTML with embedded visualization
364
+ */
365
+ renderToHTML(
366
+ graph: DependencyGraph,
367
+ options: Partial<GraphRenderOptions> = {},
368
+ ): string {
369
+ const width = options.width || 1200;
370
+ const height = options.height || 800;
371
+ const d3Data = this.renderToD3(graph);
372
+
373
+ return `<!DOCTYPE html>
374
+ <html lang="en">
375
+ <head>
376
+ <meta charset="UTF-8">
377
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
378
+ <title>Dependency Graph - ${graph.metadata.projectName}</title>
379
+ <script src="https://d3js.org/d3.v7.min.js"></script>
380
+ <style>
381
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
382
+ .container { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
383
+ h1 { margin: 0 0 10px 0; color: #333; }
384
+ .stats { display: flex; gap: 20px; margin-bottom: 20px; }
385
+ .stat { background: #f0f0f0; padding: 10px 15px; border-radius: 4px; }
386
+ .stat-label { font-size: 12px; color: #666; }
387
+ .stat-value { font-size: 24px; font-weight: bold; }
388
+ .critical { color: #ff0000; }
389
+ .high { color: #ff6b6b; }
390
+ .medium { color: #ffb347; }
391
+ .low { color: #ffd700; }
392
+ svg { display: block; margin: 0 auto; }
393
+ .node circle { stroke: #fff; stroke-width: 2px; }
394
+ .node text { font-size: 10px; pointer-events: none; }
395
+ .link { stroke: #999; stroke-opacity: 0.6; }
396
+ .tooltip { position: absolute; background: #333; color: white; padding: 8px 12px; border-radius: 4px; font-size: 12px; pointer-events: none; }
397
+ </style>
398
+ </head>
399
+ <body>
400
+ <div class="container">
401
+ <h1>Dependency Graph: ${graph.metadata.projectName}</h1>
402
+ <div class="stats">
403
+ <div class="stat">
404
+ <div class="stat-label">Total Packages</div>
405
+ <div class="stat-value">${graph.metadata.totalPackages}</div>
406
+ </div>
407
+ <div class="stat">
408
+ <div class="stat-label">Vulnerable</div>
409
+ <div class="stat-value critical">${graph.metadata.vulnerablePackages}</div>
410
+ </div>
411
+ <div class="stat">
412
+ <div class="stat-label">Critical</div>
413
+ <div class="stat-value critical">${graph.metadata.riskDistribution["critical"]}</div>
414
+ </div>
415
+ <div class="stat">
416
+ <div class="stat-label">High</div>
417
+ <div class="stat-value high">${graph.metadata.riskDistribution["high"]}</div>
418
+ </div>
419
+ </div>
420
+ <svg width="${width}" height="${height}"></svg>
421
+ </div>
422
+ <script>
423
+ const data = ${d3Data};
424
+ const width = ${width};
425
+ const height = ${height};
426
+
427
+ const color = d3.scaleOrdinal()
428
+ .domain(['none', 'low', 'medium', 'high', 'critical'])
429
+ .range(['#90EE90', '#FFFF99', '#FFB347', '#FF6B6B', '#FF0000']);
430
+
431
+ const simulation = d3.forceSimulation(data.nodes)
432
+ .force('link', d3.forceLink(data.links).id(d => d.id).distance(100))
433
+ .force('charge', d3.forceManyBody().strength(-200))
434
+ .force('center', d3.forceCenter(width / 2, height / 2));
435
+
436
+ const svg = d3.select('svg');
437
+
438
+ const link = svg.append('g')
439
+ .selectAll('line')
440
+ .data(data.links)
441
+ .join('line')
442
+ .attr('class', 'link');
443
+
444
+ const node = svg.append('g')
445
+ .selectAll('g')
446
+ .data(data.nodes)
447
+ .join('g')
448
+ .attr('class', 'node')
449
+ .call(d3.drag()
450
+ .on('start', dragstarted)
451
+ .on('drag', dragged)
452
+ .on('end', dragended));
453
+
454
+ node.append('circle')
455
+ .attr('r', d => d.group === 1 ? 20 : d.group === 2 ? 12 : 8)
456
+ .attr('fill', d => color(d.riskLevel));
457
+
458
+ node.append('text')
459
+ .attr('dx', 15)
460
+ .attr('dy', 4)
461
+ .text(d => d.name);
462
+
463
+ simulation.on('tick', () => {
464
+ link
465
+ .attr('x1', d => d.source.x)
466
+ .attr('y1', d => d.source.y)
467
+ .attr('x2', d => d.target.x)
468
+ .attr('y2', d => d.target.y);
469
+ node.attr('transform', d => \`translate(\${d.x},\${d.y})\`);
470
+ });
471
+
472
+ function dragstarted(event) {
473
+ if (!event.active) simulation.alphaTarget(0.3).restart();
474
+ event.subject.fx = event.subject.x;
475
+ event.subject.fy = event.subject.y;
476
+ }
477
+
478
+ function dragged(event) {
479
+ event.subject.fx = event.x;
480
+ event.subject.fy = event.y;
481
+ }
482
+
483
+ function dragended(event) {
484
+ if (!event.active) simulation.alphaTarget(0);
485
+ event.subject.fx = null;
486
+ event.subject.fy = null;
487
+ }
488
+ </script>
489
+ </body>
490
+ </html>`;
491
+ }
492
+ }
493
+
494
+ // Export singleton
495
+ export const dependencyGraphGenerator = new DependencyGraphGenerator();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Visualization Module
3
+ */
4
+
5
+ export * from './dependency-graph';