dependency-radar 0.6.1 → 0.8.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/README.md CHANGED
@@ -4,7 +4,7 @@ Dependency Radar inspects your Node.js dependency graph and makes structural ris
4
4
 
5
5
  Unlike basic audit tools, it builds the graph from lockfiles, understands PNPM workspaces, validates declared vs inferred licences, and highlights structural risks before they become production problems.
6
6
 
7
- No accounts. No uploads. Runs entirely on your machine.
7
+ No accounts. No uploads. Nothing leaves your machine.
8
8
 
9
9
  The simplest way to get started is to go to your project root and run:
10
10
 
@@ -27,13 +27,16 @@ This runs a scan against the current project and writes a self-contained `depend
27
27
  ## What you get
28
28
 
29
29
  - **Vulnerability scanning** — runs `npm audit` / `pnpm audit` / `yarn audit` and surfaces advisories with severity, fix availability, and reachability heuristics
30
- - **Licence analysis** — validates SPDX declarations, infers licences from `LICENSE` files, and flags mismatches, unknown licences, and strong copyleft
30
+ - **License analysis** — validates SPDX declarations, infers licences from `LICENSE` files, and flags mismatches, unknown licences, and strong copyleft
31
31
  - **Interactive dependency graph** — explore your full dependency tree visually, including direct, dev, and transitive relationships
32
32
  - **Upgrade friction analysis** — identifies upgrade blockers: peer constraints, engine ranges, native bindings, install scripts, deprecated packages
33
33
  - **Import usage heuristics** — classifies each dependency's runtime impact (`runtime`, `build`, `testing`, `tooling`, `mixed`) based on where it's imported in your source
34
34
  - **Full transitive tree** — shows depth, parent relationships, fan-in/fan-out, and dependency origins
35
35
  - **Workspace support** — works across npm, pnpm, and Yarn workspaces
36
36
  - **CI-friendly** — `--fail-on` flag lets you enforce licence and vulnerability policies in pipelines
37
+ - **Review-friendly outputs** — emit JSON, SARIF, CycloneDX SBOM, or SPDX SBOM artifacts from the same local scan
38
+ - **Change comparison** — compare a fresh scan with a previous `dependency-radar.json` to see added dependencies, removed dependencies, version changes, and new findings
39
+ - **Lockfile supply-chain signals** — flags git/local/tarball sources, missing integrity, unexpected registry hosts, and optional npm signature/provenance verification
37
40
  - **Completely offline-capable** — use `--offline` to skip registry calls; all package metadata is read from local `node_modules`
38
41
  - **Single self-contained HTML file** — no server needed; open it locally, attach it to a ticket, or share it with your team
39
42
 
@@ -57,7 +60,7 @@ This runs a scan against the current project and writes a self-contained `depend
57
60
  Modern Node projects pull in hundreds (or thousands) of transitive dependencies, and most of the risk is structural, not obvious.
58
61
 
59
62
  - `npm audit` tells you about known vulnerabilities, but it does not explain how a dependency got there, whether it is reachable at runtime, or how deep it sits in your graph.
60
- - Licence tooling often trusts `package.json` declarations, even though they can be missing, invalid, or wrong, and rarely checks what is actually in the installed `LICENSE` file.
63
+ - License tooling often trusts `package.json` declarations, even though they can be missing, invalid, or wrong, and rarely checks what is actually in the installed `LICENSE` file.
61
64
  - Monorepos and PNPM workspaces make the tree harder to reason about, especially when package manager outputs include optional platform variants that are not installed on your machine.
62
65
  - Upgrade pain usually shows up late, when a Node major bump or a package update breaks due to peer dependency constraints, engine ranges, native bindings, or install scripts.
63
66
 
@@ -92,15 +95,85 @@ The `scan` command is the default and can also be run explicitly as `npx depende
92
95
  | Flag | Description |
93
96
  |---|---|
94
97
  | `--project <path>` | Path to the project to scan (defaults to current directory) |
98
+ | `--quiet` | Suppress progress/info logs, browser opening, and footer messaging while keeping the final summary and failures visible |
95
99
  | `--out <path>` | Output path for the report file |
100
+ | `--format <format>` | Output format: `html`, `json`, `sarif`, `cyclonedx`, or `spdx` |
101
+ | `--sbom <format>` | Convenience alias for SBOM output: `cyclonedx` or `spdx` |
102
+ | `--target-node <major>` | Add Node major compatibility findings based on local `engines.node` metadata |
103
+ | `--audit-signatures` | Run `npm audit signatures` for registry signature/provenance verification (opt-in; skipped with `--offline`) |
104
+ | `--schema` | Print the current Dependency Radar JSON schema, or write it with `--out <path>` |
96
105
  | `--offline` | Skip `npm audit` and `npm outdated` (useful for offline/air-gapped scans) |
97
106
  | `--json` | Output JSON instead of HTML (`dependency-radar.json`) |
107
+ | `--timestamp` | Add a local timestamp to generated report filenames (`dependency-radar.YYYY-MM-DD_HH-mm-ss.html`) |
98
108
  | `--no-report` | Run analysis only; no HTML/JSON output written |
99
109
  | `--keep-temp` | Keep the temporary `.dependency-radar/` folder for debugging |
100
110
  | `--open` | Open the generated report using the system default browser |
101
111
  | `--fail-on <rules>` | Fail with exit code 1 when selected policy rules are violated (see below) |
102
112
  | `--help` | Show all options |
103
113
 
114
+ ### Explain one dependency in the terminal
115
+
116
+ Use `explain` when you want a fast terminal view for one package without generating HTML or JSON output:
117
+
118
+ ```bash
119
+ npx dependency-radar explain lodash
120
+ ```
121
+
122
+ This reuses the normal scan model and then filters it in memory. `explain` does not add its own extra lookup pipeline and does not write `dependency-radar.html`, but it can still trigger the same network-dependent `audit` and `outdated` steps as a normal scan unless you pass `--offline`.
123
+
124
+ `explain` shows the signals already present in Dependency Radar's scan model, including:
125
+
126
+ - direct vs transitive
127
+ - scope and introduction classification
128
+ - runtime impact heuristics
129
+ - root packages and direct parents
130
+ - static import evidence and top import locations
131
+ - vulnerability summary when audit data is available
132
+ - licence status
133
+ - upgrade blockers
134
+ - other detected versions of the same package
135
+
136
+ Examples:
137
+
138
+ ```bash
139
+ npx dependency-radar explain lodash
140
+ ```
141
+
142
+ ```bash
143
+ npx dependency-radar explain lodash --project ./my-app
144
+ ```
145
+
146
+ ```bash
147
+ npx dependency-radar explain lodash --project ./my-app --offline
148
+ ```
149
+
150
+ Notes:
151
+
152
+ - `explain` matches by package name only. If multiple installed versions exist, each version is shown in its own block.
153
+ - Vulnerabilities are reported only when audit data is available. With `--offline`, the command prints `not available (--offline)` instead of implying `none`.
154
+ - "Static import evidence" means Dependency Radar found local source imports for that package. It is a code-usage heuristic, not exploit reachability analysis.
155
+ - "Introduced via root packages" and "Direct parents" are shown from the current scan model. The command does not currently print full ancestry chains.
156
+
157
+ ### Show why a dependency is present
158
+
159
+ Use `why` to print shortest dependency paths from direct dependencies to a package:
160
+
161
+ ```bash
162
+ npx dependency-radar why lodash
163
+ ```
164
+
165
+ This uses the same local scan model as the HTML report. When full paths are unavailable, it falls back to the package origins and direct parent evidence available in the report model.
166
+
167
+ ### Compare against a previous report
168
+
169
+ Use `compare` to scan the current project and compare it with an earlier JSON report:
170
+
171
+ ```bash
172
+ npx dependency-radar compare ./dependency-radar-before.json --json --offline
173
+ ```
174
+
175
+ The comparison highlights added dependencies, removed dependencies, one-version package changes, new findings, and resolved findings. This is useful in pull requests and release checks.
176
+
104
177
  ### CI policy enforcement (`--fail-on`)
105
178
 
106
179
  ```
@@ -117,6 +190,7 @@ Supported rules:
117
190
  | `licence-mismatch` | Fail if at least one dependency has a declared-vs-inferred licence mismatch |
118
191
  | `copyleft-detected` | Fail if strong copyleft (GPL/AGPL) appears in runtime dependencies |
119
192
  | `unknown-licence` | Fail if at least one dependency has neither declared nor inferred licence data |
193
+ | `supply-chain-source` | Fail if lockfile source signals detect git/local/tarball sources, missing integrity, or unexpected registry hosts |
120
194
 
121
195
  When rules are violated, Dependency Radar prints `✖ Policy violations detected:` and exits `1`. Unknown rules also exit `1` with a clear error message.
122
196
 
@@ -132,6 +206,42 @@ npx dependency-radar --open
132
206
  npx dependency-radar --project ./my-app --out ./reports/dependency-radar.html
133
207
  ```
134
208
 
209
+ ### Example: write SARIF for CI/code scanning
210
+
211
+ ```bash
212
+ npx dependency-radar --format sarif --out ./reports/dependency-radar.sarif
213
+ ```
214
+
215
+ ### Example: write an SBOM
216
+
217
+ ```bash
218
+ npx dependency-radar --sbom cyclonedx --out ./reports/bom.cdx.json
219
+ ```
220
+
221
+ ```bash
222
+ npx dependency-radar --sbom spdx --out ./reports/bom.spdx.json
223
+ ```
224
+
225
+ ### Example: check Node upgrade readiness signals
226
+
227
+ ```bash
228
+ npx dependency-radar --target-node 22
229
+ ```
230
+
231
+ ### Example: verify npm registry signatures/provenance
232
+
233
+ ```bash
234
+ npx dependency-radar --audit-signatures
235
+ ```
236
+
237
+ This runs `npm audit signatures` as an opt-in online check. It is skipped when `--offline` is used.
238
+
239
+ ### Example: write the JSON schema
240
+
241
+ ```bash
242
+ npx dependency-radar --schema --out ./reports/dependency-radar.schema.json
243
+ ```
244
+
135
245
  ### Example: keep temp files for debugging
136
246
  ```bash
137
247
  npx dependency-radar --keep-temp
@@ -149,6 +259,20 @@ npx dependency-radar --offline
149
259
  npx dependency-radar --no-report --fail-on reachable-vuln,licence-mismatch
150
260
  ```
151
261
 
262
+ ### Example: quiet mode for CI or scripting
263
+
264
+ ```bash
265
+ npx dependency-radar scan --quiet --no-report
266
+ ```
267
+
268
+ `--quiet` is quiet, not silent:
269
+
270
+ - the scan still runs fully
271
+ - reports are still generated unless `--no-report` is set
272
+ - the final summary block is still printed
273
+ - policy failures are still printed
274
+ - progress/info logs, automatic browser opening, and the promotional footer are suppressed
275
+
152
276
  __Note:__ When used with `--no-report`, the `--keep-temp` flag is ignored.
153
277
  Temporary files are normally deleted automatically.
154
278
  If you intentionally use `--keep-temp` (without `--no-report`) for debugging,
@@ -160,16 +284,16 @@ At the end of each scan, the CLI prints a summary block with high-level counts,
160
284
 
161
285
  ```text
162
286
  Summary:
163
- • Direct deps scanned: 8
164
- • Transitive deps scanned: 65
165
- • Vulnerable packages: 5 (1 reachable)
166
- Unused installed deps: 0
167
- Licence mismatches: 3
168
- • Major upgrade blockers: 28
169
- - 14 strict peer dependency constraints
170
- - 6 narrow engine ranges
171
- - 4 deprecated packages
172
- - 4 native bindings
287
+ • Direct dependencies scanned: 6
288
+ • Transitive dependencies scanned: 62
289
+ • Vulnerable packages: 1 (0 reachable)
290
+ Dependencies with no static import reference: 0
291
+ License mismatches: 3
292
+ • Major upgrade blockers: 24
293
+ - 1 strict peer dependency constraint
294
+ - 22 narrow engine ranges
295
+ - 2 native bindings
296
+ - 1 install lifecycle script
173
297
  ```
174
298
 
175
299
  The blocker detail counts can overlap: a single package may contribute to multiple blocker categories.
@@ -183,23 +307,25 @@ The blocker detail counts can overlap: a single package may contribute to multip
183
307
  | pnpm | ✅ Lockfile-first (`pnpm-lock.yaml`) | ✅ | ✅ | ✅ |
184
308
  | Yarn Classic (v1) | ✅ Lockfile-first (`yarn.lock`) | ✅ | ✅ | ✅ |
185
309
  | Yarn Berry (v2+, node-modules linker) | ✅ Lockfile-first (`yarn.lock`) | ✅ | ⚠️ Plugin-dependent | ✅ |
186
- | Yarn Plug'n'Play | Not yet supported | | | |
310
+ | Yarn Plug'n'Play | ⚠️ Lockfile-derived graph only; package metadata may be incomplete without `node_modules` | | ⚠️ Plugin-dependent | |
311
+ | Bun | ⚠️ Text `bun.lock` parsing; binary `bun.lockb` is reported with a migration hint | N/A | ❌ | ⚠️ package.json workspaces only |
187
312
 
188
313
  ## Requirements
189
314
 
190
- - Node.js 14.14+
315
+ - Node.js 14.21.3 is currently the oldest version verified by our Docker release smoke test (`node:14.21.3-bullseye`)
191
316
  - Dependencies must be installed (`npm install` / `pnpm install` / `yarn install`) before scanning
192
317
 
193
318
  ## How a scan works
194
319
 
195
320
  When you run `npx dependency-radar` (or `dependency-radar scan`), the CLI executes this pipeline:
196
321
 
197
- 1. Parse CLI options (`--project`, `--out`, `--offline`, `--json`, `--no-report`, `--keep-temp`, `--open`, `--fail-on`).
322
+ 1. Parse CLI options (`--project`, `--out`, `--offline`, `--json`, `--timestamp`, `--no-report`, `--keep-temp`, `--open`, `--fail-on`, `--audit-signatures`, `--schema`).
198
323
  2. Detect workspace/package-manager context:
199
324
  - Workspace roots from `pnpm-workspace.yaml` or `package.json#workspaces`
200
325
  - Dependency policy from `package.json` and `pnpm-workspace.yaml` overrides/resolutions
201
326
  - Package manager from `packageManager`, lockfiles, and installed metadata
202
327
  - Yarn Plug'n'Play detection (`.pnp.cjs`/`.pnp.js` or `.yarnrc.yml nodeLinker: pnp`)
328
+ - Bun text lockfile detection (`bun.lock`; binary `bun.lockb` is not parsed)
203
329
  3. Create a temporary `.dependency-radar/` directory inside the scanned project.
204
330
  4. For each workspace package (or just the project root in single-package mode), collect dependency graph data:
205
331
  - Lockfile-first graph parsing (`pnpm-lock.yaml`, `npm-shrinkwrap.json`/`package-lock.json`, `yarn.lock`)
@@ -209,6 +335,8 @@ When you run `npx dependency-radar` (or `dependency-radar scan`), the CLI execut
209
335
  - Vulnerabilities (`npm audit` / `pnpm audit` / `yarn audit` or `yarn npm audit`)
210
336
  - Version drift (`npm outdated` / `pnpm outdated` / `yarn outdated`, where available)
211
337
  - Source import graph (static import/require parsing in `src/` or project root)
338
+ - Lockfile supply-chain source signals
339
+ - Optional npm registry signature/provenance verification (`--audit-signatures`)
212
340
  6. Normalize outputs into one internal shape and merge workspace package results.
213
341
  - PNPM lock/CLI dependency trees are filtered to installed-only packages (non-installed optional/platform variants are dropped)
214
342
  7. Resolve and crawl installed package directories in `node_modules` to collect local metadata:
@@ -220,13 +348,20 @@ When you run `npx dependency-radar` (or `dependency-radar scan`), the CLI execut
220
348
  - Root-cause/origin and runtime-impact heuristics
221
349
  - Install-time execution signals
222
350
  - Local package metadata (`description`, links, deprecation, TypeScript type availability, installed file count, CLI `bin` presence)
223
- 9. Write final output as either:
351
+ 9. Build normalized findings from the aggregated dependency model:
352
+ - Vulnerabilities, license review items, install-time execution surface, native bindings, deprecated packages, target Node compatibility findings, lockfile source signals, and npm signature/provenance failures
353
+ 10. Write final output as one of:
224
354
  - `dependency-radar.html` (self-contained report), or
225
355
  - `dependency-radar.json` (raw aggregated model)
226
- 10. Remove `.dependency-radar/` unless `--keep-temp` is set.
356
+ - SARIF (`--format sarif`)
357
+ - CycloneDX SBOM (`--format cyclonedx` / `--sbom cyclonedx`)
358
+ - SPDX SBOM (`--format spdx` / `--sbom spdx`)
359
+ 11. Remove `.dependency-radar/` unless `--keep-temp` is set.
227
360
 
228
361
  The scan is local-first: package metadata is read from `node_modules`; only audit/outdated commands require registry access.
229
362
 
363
+ The `explain` command reuses this same pipeline with report writing disabled, then filters the in-memory model down to a single package for terminal output.
364
+
230
365
  ### `node_modules` crawling details
231
366
 
232
367
  - Dependency metadata is read from installed package directories, not from registry documents.
@@ -340,7 +475,7 @@ The JSON schema matches the `AggregatedData` TypeScript interface in `src/types.
340
475
 
341
476
  ```ts
342
477
  export interface AggregatedData {
343
- schemaVersion: '1.3'; // Report schema version for compatibility checks
478
+ schemaVersion: '1.4'; // Report schema version for compatibility checks
344
479
  generatedAt: string; // ISO timestamp when the scan finished
345
480
  dependencyRadarVersion: string; // CLI version that produced the report
346
481
  git: {
@@ -378,11 +513,12 @@ export interface AggregatedData {
378
513
  nodeVersion: string; // Node.js version from process.versions.node
379
514
  runtimeVersion: string; // Node.js runtime version from process.version
380
515
  minRequiredMajor: number; // Strictest Node major required by dependency engines (0 if unknown)
516
+ targetNodeMajor?: number; // Node major passed through --target-node
381
517
  platform?: string; // OS platform (process.platform)
382
518
  arch?: string; // CPU architecture (process.arch)
383
519
  ci?: boolean; // True when CI indicators are detected
384
520
  packageManagerField?: string; // package.json packageManager field (e.g. pnpm@9.1.0)
385
- packageManager?: 'npm' | 'pnpm' | 'yarn'; // Package manager used for dependency/audit/outdated collection
521
+ packageManager?: 'npm' | 'pnpm' | 'yarn' | 'bun'; // Package manager used for dependency/audit/outdated collection
386
522
  packageManagerVersion?: string; // Version of the selected package manager (when available)
387
523
  toolVersions?: {
388
524
  npm?: string;
@@ -392,7 +528,7 @@ export interface AggregatedData {
392
528
  };
393
529
  workspaces: {
394
530
  enabled: boolean; // True when the scan used workspace aggregation
395
- type?: 'npm' | 'pnpm' | 'yarn' | 'none'; // Workspace mode (CLI currently always emits this)
531
+ type?: 'npm' | 'pnpm' | 'yarn' | 'bun' | 'none'; // Workspace mode (CLI currently always emits this)
396
532
  packageCount?: number; // Number of workspace packages scanned (CLI currently always emits this)
397
533
  workspacePackages?: WorkspacePackage[]; // Lightweight first-party workspace metadata
398
534
  };
@@ -400,7 +536,32 @@ export interface AggregatedData {
400
536
  dependencyCount: number; // Total EXTERNAL dependencies in the graph
401
537
  directCount: number; // External dependencies listed in package.json
402
538
  transitiveCount: number; // External dependencies pulled in by other dependencies
539
+ findingCount?: number; // Number of normalized findings generated from the dependency model
540
+ };
541
+ supplyChain?: {
542
+ signals: Array<{
543
+ type:
544
+ | 'git-dependency'
545
+ | 'file-dependency'
546
+ | 'non-registry-tarball'
547
+ | 'missing-integrity'
548
+ | 'unexpected-registry-host'
549
+ | 'signature-verification-failed'
550
+ | 'signature-verification-unavailable';
551
+ packageName?: string;
552
+ packageVersion?: string;
553
+ packageId?: string;
554
+ source: string;
555
+ detail: string;
556
+ }>;
557
+ signatureAudit?: {
558
+ attempted: boolean;
559
+ ok: boolean;
560
+ output?: string;
561
+ error?: string;
562
+ };
403
563
  };
564
+ findings?: DependencyFinding[]; // Normalized review/CI findings
404
565
  dependencies: Record<string, DependencyRecord>; // External third-party packages keyed by name@version
405
566
  }
406
567
 
@@ -536,9 +697,6 @@ export interface DependencyRecord {
536
697
 
537
698
  For full details and any future changes, see `src/types.ts`.
538
699
 
539
- Environment data includes Node.js version, OS platform, CPU architecture, and package manager versions.
540
- No personal information, usernames, paths, or environment variables are collected.
541
-
542
700
  ## Notes
543
701
 
544
702
  - The target project must have dependencies installed (run `npm install`, `pnpm install`, or `yarn install` first).
@@ -548,6 +706,8 @@ No personal information, usernames, paths, or environment variables are collecte
548
706
  - A temporary `.dependency-radar/` folder is created during the scan to store intermediate tool output.
549
707
  - Use `--keep-temp` to retain this folder for debugging; otherwise it is deleted automatically.
550
708
  - If some per-package tools fail (common in large workspaces), the scan continues and reports warnings; missing sections are marked unavailable where applicable.
709
+ - Environment data includes Node.js version, OS platform, CPU architecture, and package manager versions.
710
+ - No personal information, usernames, paths, or environment variables are collected.
551
711
 
552
712
  ---
553
713
 
@@ -576,11 +736,15 @@ npm run build
576
736
  | `npm run test:fixtures` | Run curated fixture integration tests (mostly offline scans) |
577
737
  | `npm run test:fixtures:online` | Run online fixture checks (audit/outdated regression coverage) |
578
738
  | `npm run test:fixtures:all` | Run all fixture integration tests |
579
- | `npm run test:release` | Full pre-release gate (`build` + unit + fixture + package dry run) |
739
+ | `npm run test:docker:node14` | Pack the published artifact and smoke-test it in Docker on Node `14.21.3` |
740
+ | `npm run test:docker` | Alias for the Node `14.21.3` Docker compatibility smoke test |
741
+ | `npm run test:release` | Full pre-release gate (`build` + unit + fixture + Docker Node 14 smoke test + package dry run) |
580
742
 
581
743
 
582
744
  Fixture orchestration lives in `/test-fixtures/package.json` with helper scripts under `/test-fixtures/scripts`.
583
745
 
746
+ The Docker smoke test uses the packed tarball, installs it inside `node:14.21.3-bullseye`, and runs an offline scan against `test-fixtures/license-edge-cases`. This verifies the published CLI on the oldest Node version we currently exercise in automation without requiring local Node 14 installation.
747
+
584
748
  ### Report UI Development
585
749
 
586
750
  The HTML report UI is developed in a separate Vite project located in `report-ui/`. This provides a proper development environment with hot reload, TypeScript support, and sample data.
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.aggregateData = aggregateData;
7
7
  const utils_1 = require("./utils");
8
8
  const license_1 = require("./license");
9
+ const findings_1 = require("./findings");
10
+ const nodeEngine_1 = require("./nodeEngine");
9
11
  const promises_1 = __importDefault(require("fs/promises"));
10
12
  const path_1 = __importDefault(require("path"));
11
13
  const os_1 = __importDefault(require("os"));
@@ -286,7 +288,7 @@ function isWorkspacePackageNode(node, input) {
286
288
  return false;
287
289
  }
288
290
  async function aggregateData(input) {
289
- var _a, _b, _c, _d, _e, _f, _g, _h;
291
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
290
292
  const pkg = input.pkgOverride || (await (0, utils_1.readPackageJson)(input.projectPath));
291
293
  let projectPkg = input.projectPackageJson;
292
294
  if (!projectPkg) {
@@ -305,7 +307,8 @@ async function aggregateData(input) {
305
307
  const importGraph = normalizeImportGraph((_c = input.importGraphResult) === null || _c === void 0 ? void 0 : _c.data);
306
308
  const usageResult = buildUsageSummary(importGraph, input.projectPath);
307
309
  const outdatedById = buildOutdatedMap(input.outdatedResult);
308
- const outdatedUnknownNames = new Set(((_d = input.outdatedResult) === null || _d === void 0 ? void 0 : _d.unknownNames) || []);
310
+ const supplyChain = normalizeSupplyChain((_d = input.supplyChainResult) === null || _d === void 0 ? void 0 : _d.data);
311
+ const outdatedUnknownNames = new Set(((_e = input.outdatedResult) === null || _e === void 0 ? void 0 : _e.unknownNames) || []);
309
312
  const packageMetaCache = new Map();
310
313
  const resolvePaths = input.resolvePaths && input.resolvePaths.length > 0
311
314
  ? input.resolvePaths
@@ -346,7 +349,7 @@ async function aggregateData(input) {
346
349
  const runtimeImpact = usageResult.runtimeImpact.get(node.name);
347
350
  const introduction = determineIntroduction(direct, scope, rootCauses, runtimeImpact);
348
351
  const parentIds = Array.from(node.parents).sort();
349
- const origins = buildOrigins(rootCauses, parentIds, (_e = input.workspaceUsage) === null || _e === void 0 ? void 0 : _e.get(node.name), input.workspaceEnabled, MAX_TOP_ROOT_PACKAGES, MAX_TOP_PARENT_PACKAGES);
352
+ const origins = buildOrigins(rootCauses, parentIds, (_f = input.workspaceUsage) === null || _f === void 0 ? void 0 : _f.get(node.name), input.workspaceEnabled, MAX_TOP_ROOT_PACKAGES, MAX_TOP_PARENT_PACKAGES);
350
353
  const execution = packageInsights.execution;
351
354
  const id = node.key;
352
355
  const upgrade = buildUpgradeBlock(packageInsights);
@@ -359,7 +362,10 @@ async function aggregateData(input) {
359
362
  ...(outdated ? { outdatedStatus: outdated.status } : {}),
360
363
  ...((outdated === null || outdated === void 0 ? void 0 : outdated.latestVersion) ? { latestVersion: outdated.latestVersion } : {}),
361
364
  ...((upgrade === null || upgrade === void 0 ? void 0 : upgrade.blockers) ? { blockers: upgrade.blockers } : {}),
362
- ...((upgrade === null || upgrade === void 0 ? void 0 : upgrade.blocksNodeMajor) ? { blocksNodeMajor: upgrade.blocksNodeMajor } : {})
365
+ ...((upgrade === null || upgrade === void 0 ? void 0 : upgrade.blocksNodeMajor) ? { blocksNodeMajor: upgrade.blocksNodeMajor } : {}),
366
+ ...(typeof input.targetNodeMajor === 'number' && packageInsights.nodeEngine
367
+ ? { targetNodeCompatible: (0, nodeEngine_1.isNodeEngineTargetCompatible)(packageInsights.nodeEngine, input.targetNodeMajor) }
368
+ : {})
363
369
  };
364
370
  dependencies[id] = {
365
371
  package: {
@@ -372,9 +378,9 @@ async function aggregateData(input) {
372
378
  deprecated: packageInsights.deprecated,
373
379
  links: {
374
380
  npm: `https://www.npmjs.com/package/${node.name}`,
375
- ...(((_f = packageInsights.links) === null || _f === void 0 ? void 0 : _f.repository) ? { repository: packageInsights.links.repository } : {}),
376
- ...(((_g = packageInsights.links) === null || _g === void 0 ? void 0 : _g.homepage) ? { homepage: packageInsights.links.homepage } : {}),
377
- ...(((_h = packageInsights.links) === null || _h === void 0 ? void 0 : _h.bugs) ? { bugs: packageInsights.links.bugs } : {})
381
+ ...(((_g = packageInsights.links) === null || _g === void 0 ? void 0 : _g.repository) ? { repository: packageInsights.links.repository } : {}),
382
+ ...(((_h = packageInsights.links) === null || _h === void 0 ? void 0 : _h.homepage) ? { homepage: packageInsights.links.homepage } : {}),
383
+ ...(((_j = packageInsights.links) === null || _j === void 0 ? void 0 : _j.bugs) ? { bugs: packageInsights.links.bugs } : {})
378
384
  }
379
385
  },
380
386
  compliance: {
@@ -416,8 +422,8 @@ async function aggregateData(input) {
416
422
  const nodeVersion = process.versions.node;
417
423
  const dependencyCount = nodes.length;
418
424
  const transitiveCount = dependencyCount - directCount;
419
- return {
420
- schemaVersion: '1.3',
425
+ const aggregated = {
426
+ schemaVersion: '1.4',
421
427
  generatedAt: new Date().toISOString(),
422
428
  dependencyRadarVersion,
423
429
  git: {
@@ -428,6 +434,7 @@ async function aggregateData(input) {
428
434
  nodeVersion,
429
435
  runtimeVersion,
430
436
  minRequiredMajor: minRequiredMajor !== null && minRequiredMajor !== void 0 ? minRequiredMajor : 0,
437
+ ...(typeof input.targetNodeMajor === 'number' ? { targetNodeMajor: input.targetNodeMajor } : {}),
431
438
  ...(input.platform ? { platform: input.platform } : {}),
432
439
  ...(input.arch ? { arch: input.arch } : {}),
433
440
  ...(typeof input.ci === 'boolean' ? { ci: input.ci } : {}),
@@ -449,8 +456,27 @@ async function aggregateData(input) {
449
456
  directCount,
450
457
  transitiveCount
451
458
  },
459
+ ...(supplyChain ? { supplyChain } : {}),
452
460
  dependencies
453
461
  };
462
+ const findings = (0, findings_1.buildDependencyFindings)(aggregated, { targetNodeMajor: input.targetNodeMajor });
463
+ aggregated.findings = findings;
464
+ aggregated.summary.findingCount = findings.length;
465
+ return aggregated;
466
+ }
467
+ function normalizeSupplyChain(data) {
468
+ if (!data || typeof data !== 'object')
469
+ return undefined;
470
+ const signals = Array.isArray(data.signals) ? data.signals : [];
471
+ const signatureAudit = data.signatureAudit && typeof data.signatureAudit === 'object'
472
+ ? data.signatureAudit
473
+ : undefined;
474
+ if (signals.length === 0 && !signatureAudit)
475
+ return undefined;
476
+ return {
477
+ signals,
478
+ ...(signatureAudit ? { signatureAudit } : {})
479
+ };
454
480
  }
455
481
  function deriveMinRequiredMajor(engineRanges) {
456
482
  let strictest;