Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/node-20-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@mawesome/dependency-audit': minor
---

Widen the supported Node range from `>=24.12.0` to `^20.19.0 || >=22.9.0`.
45 changes: 45 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,48 @@ jobs:
run: pnpm verify
- name: Audit dependencies
run: pnpm audit --audit-level=high

# The full gate needs Node >=24.12 (internal .ts scripts rely on native type stripping), so this job exercises the published package's Node floor separately.
# It installs and builds on Node 24, then runs dependency-audit's tests and built CLI on each supported Node line.
node-compat:
name: Node ${{ matrix.node }} compat
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: [20, 24, 26]
steps:
- name: Harden runner
uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2
with:
egress-policy: audit
- name: Check out
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Set up pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
# check-latest so a stale runner-cached 24.x below the root >=24.12 floor can't be used.
- name: Set up Node.js 24 (build toolchain)
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24
cache: pnpm
check-latest: true
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build dependency-audit
run: pnpm --filter @mawesome/dependency-audit build
- name: Set up Node.js ${{ matrix.node }} (latest)
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: ${{ matrix.node }}
check-latest: true
# Invoke vitest directly: pnpm enforces the root engines (>=24.12) on every `pnpm run`, which would fail on the older matrix lines.
- name: Run tests on Node ${{ matrix.node }}
working-directory: packages/dependency-audit
run: node_modules/.bin/vitest run
- name: Smoke-test the built CLI on Node ${{ matrix.node }}
run: |
node packages/dependency-audit/dist/cli.js --version
node packages/dependency-audit/dist/cli.js --no-progress packages/dependency-audit
2 changes: 1 addition & 1 deletion packages/dependency-audit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,6 @@
"vitest": "^4.1.7"
},
"engines": {
"node": ">=24.12.0"
"node": "^20.19.0 || >=22.9.0"
}
}
9 changes: 7 additions & 2 deletions packages/dependency-audit/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';

const here = dirname(fileURLToPath(import.meta.url));
const cli = join(here, '..', 'src', 'cli.ts');
/*
* Spawn the TS source where Node strips types natively; on a Node line without type stripping (20.x in the CI compat matrix) fall back to the built CLI, which that job builds beforehand.
*/
const cli = process.features.typescript
? join(here, '..', 'src', 'cli.ts')
: join(here, '..', 'dist', 'cli.js');
const targets = join(here, 'fixtures', 'targets');
// A self-contained target (no declared deps → no registry access) keeps the CLI hermetic.
const okTarget = join(targets, 'require-forms');
Expand All @@ -21,7 +26,7 @@ const badTarget = join(targets, '__no_such_target__');
*/

/**
* Runs the CLI as a subprocess (Node strips the TS types), capturing status + stdout + stderr.
* Runs the CLI as a subprocess, capturing status + stdout + stderr.
* `spawnSync` always captures both streams (even on a clean exit), so a test can assert that a successful run emits nothing on stderr — the child's stderr is a pipe, not a TTY, so the progress spinner stays silent.
* `FORCE_COLOR` / `NO_COLOR` are cleared for the child by default so every output assertion is hermetic regardless of the runner's environment; a test that wants color re-sets them via `env` (a key set to `undefined` stays unset — Node omits undefined env).
*/
Expand Down
7 changes: 4 additions & 3 deletions packages/dependency-audit/tsdown.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { defineConfig } from 'tsdown';
* `bin` field, never imported, so a CJS twin and `.d.ts` are dead weight.
* Both emit .js/.cjs (not fixed .mjs/.cjs) to match the manifest, since type:module.
* `browser` is platform:neutral so no Node globals leak into the browser bundle.
* `target` matches the `engines` floor (Node >=20.19) so emitted syntax never exceeds it.
*/
export default defineConfig([
{
Expand All @@ -16,7 +17,7 @@ export default defineConfig([
dts: true,
fixedExtension: false,
platform: 'node',
target: 'node24',
target: 'node20.19',
sourcemap: true,
clean: true,
},
Expand All @@ -29,7 +30,7 @@ export default defineConfig([
// The core imports only `node:path` (bundler-aliased to path-browserify); keep it
// external so neutral platform doesn't warn about an unresolved Node builtin.
external: [/^node:/],
target: 'node24',
target: 'node20.19',
sourcemap: true,
clean: false,
},
Expand All @@ -39,7 +40,7 @@ export default defineConfig([
dts: false,
fixedExtension: false,
platform: 'node',
target: 'node24',
target: 'node20.19',
sourcemap: true,
clean: false,
},
Expand Down
Loading