Back to Vendure

Vendure dependency audit — change log

scripts/dependency-tracker/CHANGES.md

3.7.054.3 KB
Original Source

Vendure dependency audit — change log

This document tracks the dependency footprint of Vendure across the stages of the dependency audit effort. Each stage records the state of the dependency graph after a discrete change (or batch of changes) has landed on this branch, so we can quantify the reduction in supply-chain surface area over time.

Issue reference

See #4761 for the full audit assessment, rationale, and prioritised plan. This document is the running ledger of how the dependency footprint shrinks as each stage lands.

How to add a stage

  1. Land your changes (delete a dep, swap for a built-in, vendor a package, …).
  2. Regenerate the lockfile (does not touch node_modules):
    bash
    npm install --package-lock-only
    
  3. Append a snapshot to this file:
    bash
    node scripts/dependency-tracker/snapshot.mjs --stage="Stage N — <short description>" --append
    
  4. Add a short prose ### Changes section below the snapshot explaining what was removed / replaced and why.
  5. Commit the lockfile + this file together so the diff in CHANGES.md is reproducible.

For a machine-readable JSON snapshot (useful for scripting deltas):

bash
node scripts/dependency-tracker/snapshot.mjs --json > /tmp/before.json
# ... make changes, regen lockfile ...
node scripts/dependency-tracker/snapshot.mjs --json > /tmp/after.json
diff /tmp/before.json /tmp/after.json

Stage 0 — Baseline (audit start)

  • Commit: 51b439372 on chore/dependency-audit
  • Date: 2026-05-21T07:20:14.801Z
  • Total unique production packages: 1880

Per-Vendure-package transitive footprint

PackageDirect depsUnique transitive (prod)
@vendure/core41453
@vendure/common00
@vendure/email-plugin7290
@vendure/asset-server-plugin320
@vendure/admin-ui-plugin371
@vendure/telemetry-plugin9162
@vendure/harden-plugin2153
@vendure/job-queue-plugin223
@vendure/graphiql-plugin165
@vendure/testing834
@vendure/cli1192
@vendure/create1146
@vendure/dashboard67838
@vendure/ui-devkit11810
@vendure/admin-ui48115
<details> <summary>Per-direct-dep transitive counts (click to expand)</summary>

@vendure/core

Direct depTransitive count
@nestjs/terminus295
@nestjs/typeorm260
@nestjs/apollo237
typeorm186
@apollo/server151
@nestjs/graphql149
@nestjs/core102
@nestjs/platform-express102
express65
body-parser41
graphql-upload32
http-proxy-middleware19
@nestjs/common18
@graphql-tools/stitch17
ioredis11
cookie-session9
i18next-icu9
intl-messageformat8
fs-extra4
bcrypt3
graphql-scalars3
graphql-tag3
i18next3
mime-types2
rxjs2
@vendure/common1
cron-time-generator1
croner1
cronstrue1
csv-parse1
graphql1
graphql-fields1
i18next-fs-backend1
i18next-http-middleware1
image-size1
ms1
nanoid1
picocolors1
progress1
reflect-metadata1
semver1

@vendure/email-plugin

Direct depTransitive count
mjml140
@types/nodemailer77
express65
handlebars6
fs-extra4
dateformat1
nodemailer1

@vendure/asset-server-plugin

Direct depTransitive count
file-type10
sharp6
fs-extra4

@vendure/admin-ui-plugin

Direct depTransitive count
express-rate-limit66
fs-extra4
date-fns1

@vendure/telemetry-plugin

Direct depTransitive count
@opentelemetry/auto-instrumentations-node161
@opentelemetry/sdk-node78
@opentelemetry/exporter-logs-otlp-proto25
@opentelemetry/exporter-trace-otlp-http25
@opentelemetry/sdk-logs6
@opentelemetry/resources4
@opentelemetry/context-async-hooks2
@opentelemetry/api1
javascript-stringify1

@vendure/harden-plugin

Direct depTransitive count
@apollo/server151
graphql-query-complexity3

@vendure/job-queue-plugin

Direct depTransitive count
bullmq23
ioredis11

@vendure/graphiql-plugin

Direct depTransitive count
express65

@vendure/testing

Direct depTransitive count
form-data20
node-fetch7
graphql-tag3
@graphql-typed-document-node/core2
@vendure/common1
faker1
graphql1
sql.js1

@vendure/cli

Direct depTransitive count
ts-node35
ts-morph26
change-case16
@clack/prompts4
fs-extra4
tsconfig-paths4
@vendure/common1
commander1
dotenv1
picocolors1
strip-json-comments1

@vendure/create

Direct depTransitive count
open10
tcp-port-used7
cross-spawn6
handlebars6
tar6
@clack/prompts4
fs-extra4
@vendure/common1
commander1
picocolors1
semver1

@vendure/dashboard

Direct depTransitive count
@vendure-io/ui424
@vendure-io/design-tokens325
@lingui/vite-plugin281
@tanstack/router-plugin261
@lingui/cli191
@vitejs/plugin-react175
@tailwindcss/vite141
vite132
@tanstack/eslint-plugin-query113
@lingui/react87
@lingui/babel-plugin-lingui-macro85
@lingui/core85
express-rate-limit66
@tiptap/starter-kit60
@babel/preset-typescript51
@tiptap/react51
@babel/preset-react47
recharts44
@tiptap/extension-floating-menu40
@babel/core39
@tiptap/extension-placeholder38
@tiptap/extension-image37
@tiptap/extension-table37
@tiptap/extension-text-style37
@tiptap/pm35
vaul33
@tanstack/router-devtools21
fast-glob18
@tanstack/react-router15
react-dropzone10
@dnd-kit/modifiers8
@dnd-kit/sortable8
motion8
@dnd-kit/core7
gql.tada7
react-day-picker6
@tanstack/react-query-devtools5
@tanstack/react-table5
@hookform/resolvers4
@uidotdev/usehooks4
fs-extra4
input-otp4
json-edit-react4
next-themes4
sonner4
tsconfig-paths4
@tanstack/react-query3
@types/react-dom3
react-dom3
@types/react2
acorn-walk2
lucide-react2
react-hook-form2
@fontsource-variable/geist-mono1
@fontsource-variable/inter1
@fontsource-variable/public-sans1
acorn1
awesome-graphql-client1
clsx1
date-fns1
graphql1
react1
strip-json-comments1
tailwind-merge1
tailwindcss1
tw-animate-css1
zod1

@vendure/ui-devkit

Direct depTransitive count
@angular-devkit/build-angular705
@angular/cli221
@angular/compiler-cli62
chokidar15
glob8
chalk6
fs-extra4
@angular/compiler2
rxjs2
@vendure/admin-ui1
@vendure/common1

@vendure/admin-ui

Direct depTransitive count
apollo-angular36
apollo-upload-client35
@apollo/client32
@clr/angular20
ngx-translate-messageformat-compiler16
@clr/core14
@clr/ui12
@cds/core11
prosemirror-menu10
@angular/platform-browser-dynamic9
@ng-select/ng-select9
@angular/cdk8
@angular/forms8
@angular/router8
@messageformat/core8
prosemirror-gapcursor8
prosemirror-tables8
@angular/platform-browser7
prosemirror-history7
prosemirror-keymap7
@angular/animations6
@ngx-translate/core6
@ngx-translate/http-loader6
ngx-pagination6
prosemirror-commands6
prosemirror-dropcursor6
prosemirror-inputrules6
prosemirror-schema-list6
@angular/common5
messageformat5
prosemirror-state5
@angular/core4
prosemirror-schema-basic3
react-dom3
@biesbjerg/ngx-translate-extract-marker2
@clr/icons2
rxjs2
@angular/language-service1
@vendure/common1
@webcomponents/custom-elements1
chartist1
codejar1
dayjs1
graphql1
just-extend1
react1
tslib1
zone.js1
</details>

Stage 1 — @types/nodemailer: pick up upstream AWS SDK removal

  • Commit: 905ec160a on chore/dependency-audit
  • Date: 2026-05-21T07:50:42.183Z
  • Total unique production packages: 1807

Per-Vendure-package transitive footprint

PackageDirect depsUnique transitive (prod)
@vendure/core41453
@vendure/common00
@vendure/email-plugin7216
@vendure/asset-server-plugin320
@vendure/admin-ui-plugin371
@vendure/telemetry-plugin9162
@vendure/harden-plugin2153
@vendure/job-queue-plugin223
@vendure/graphiql-plugin165
@vendure/testing834
@vendure/cli1192
@vendure/create1146
@vendure/dashboard67838
@vendure/ui-devkit11810
@vendure/admin-ui48115
<details> <summary>Per-direct-dep transitive counts (click to expand)</summary>

@vendure/core

Direct depTransitive count
@nestjs/terminus295
@nestjs/typeorm260
@nestjs/apollo237
typeorm186
@apollo/server151
@nestjs/graphql149
@nestjs/core102
@nestjs/platform-express102
express65
body-parser41
graphql-upload32
http-proxy-middleware19
@nestjs/common18
@graphql-tools/stitch17
ioredis11
cookie-session9
i18next-icu9
intl-messageformat8
fs-extra4
bcrypt3
graphql-scalars3
graphql-tag3
i18next3
mime-types2
rxjs2
@vendure/common1
cron-time-generator1
croner1
cronstrue1
csv-parse1
graphql1
graphql-fields1
i18next-fs-backend1
i18next-http-middleware1
image-size1
ms1
nanoid1
picocolors1
progress1
reflect-metadata1
semver1

@vendure/email-plugin

Direct depTransitive count
mjml140
express65
handlebars6
fs-extra4
@types/nodemailer3
dateformat1
nodemailer1

@vendure/asset-server-plugin

Direct depTransitive count
file-type10
sharp6
fs-extra4

@vendure/admin-ui-plugin

Direct depTransitive count
express-rate-limit66
fs-extra4
date-fns1

@vendure/telemetry-plugin

Direct depTransitive count
@opentelemetry/auto-instrumentations-node161
@opentelemetry/sdk-node78
@opentelemetry/exporter-logs-otlp-proto25
@opentelemetry/exporter-trace-otlp-http25
@opentelemetry/sdk-logs6
@opentelemetry/resources4
@opentelemetry/context-async-hooks2
@opentelemetry/api1
javascript-stringify1

@vendure/harden-plugin

Direct depTransitive count
@apollo/server151
graphql-query-complexity3

@vendure/job-queue-plugin

Direct depTransitive count
bullmq23
ioredis11

@vendure/graphiql-plugin

Direct depTransitive count
express65

@vendure/testing

Direct depTransitive count
form-data20
node-fetch7
graphql-tag3
@graphql-typed-document-node/core2
@vendure/common1
faker1
graphql1
sql.js1

@vendure/cli

Direct depTransitive count
ts-node35
ts-morph26
change-case16
@clack/prompts4
fs-extra4
tsconfig-paths4
@vendure/common1
commander1
dotenv1
picocolors1
strip-json-comments1

@vendure/create

Direct depTransitive count
open10
tcp-port-used7
cross-spawn6
handlebars6
tar6
@clack/prompts4
fs-extra4
@vendure/common1
commander1
picocolors1
semver1

@vendure/dashboard

Direct depTransitive count
@vendure-io/ui424
@vendure-io/design-tokens325
@lingui/vite-plugin281
@tanstack/router-plugin261
@lingui/cli191
@vitejs/plugin-react175
@tailwindcss/vite141
vite132
@tanstack/eslint-plugin-query113
@lingui/react87
@lingui/babel-plugin-lingui-macro85
@lingui/core85
express-rate-limit66
@tiptap/starter-kit60
@babel/preset-typescript51
@tiptap/react51
@babel/preset-react47
recharts44
@tiptap/extension-floating-menu40
@babel/core39
@tiptap/extension-placeholder38
@tiptap/extension-image37
@tiptap/extension-table37
@tiptap/extension-text-style37
@tiptap/pm35
vaul33
@tanstack/router-devtools21
fast-glob18
@tanstack/react-router15
react-dropzone10
@dnd-kit/modifiers8
@dnd-kit/sortable8
motion8
@dnd-kit/core7
gql.tada7
react-day-picker6
@tanstack/react-query-devtools5
@tanstack/react-table5
@hookform/resolvers4
@uidotdev/usehooks4
fs-extra4
input-otp4
json-edit-react4
next-themes4
sonner4
tsconfig-paths4
@tanstack/react-query3
@types/react-dom3
react-dom3
@types/react2
acorn-walk2
lucide-react2
react-hook-form2
@fontsource-variable/geist-mono1
@fontsource-variable/inter1
@fontsource-variable/public-sans1
acorn1
awesome-graphql-client1
clsx1
date-fns1
graphql1
react1
strip-json-comments1
tailwind-merge1
tailwindcss1
tw-animate-css1
zod1

@vendure/ui-devkit

Direct depTransitive count
@angular-devkit/build-angular705
@angular/cli221
@angular/compiler-cli62
chokidar15
glob8
chalk6
fs-extra4
@angular/compiler2
rxjs2
@vendure/admin-ui1
@vendure/common1

@vendure/admin-ui

Direct depTransitive count
apollo-angular36
apollo-upload-client35
@apollo/client32
@clr/angular20
ngx-translate-messageformat-compiler16
@clr/core14
@clr/ui12
@cds/core11
prosemirror-menu10
@angular/platform-browser-dynamic9
@ng-select/ng-select9
@angular/cdk8
@angular/forms8
@angular/router8
@messageformat/core8
prosemirror-gapcursor8
prosemirror-tables8
@angular/platform-browser7
prosemirror-history7
prosemirror-keymap7
@angular/animations6
@ngx-translate/core6
@ngx-translate/http-loader6
ngx-pagination6
prosemirror-commands6
prosemirror-dropcursor6
prosemirror-inputrules6
prosemirror-schema-list6
@angular/common5
messageformat5
prosemirror-state5
@angular/core4
prosemirror-schema-basic3
react-dom3
@biesbjerg/ngx-translate-extract-marker2
@clr/icons2
rxjs2
@angular/language-service1
@vendure/common1
@webcomponents/custom-elements1
chartist1
codejar1
dayjs1
graphql1
just-extend1
react1
tslib1
zone.js1
</details>

Changes

Bumped @types/nodemailer from ^6.4.9 to ^6.4.22 in both packages/email-plugin/package.json and the workspace root package.json (used by dev-server to satisfy EmailPlugin type resolution).

Why: @types/nodemailer versions 6.4.19 through 6.4.21 declared @aws-sdk/client-ses as a runtime dependencies entry, pulling ~76 AWS SDK and Smithy packages into every install that resolved the types — even consumers who never touch SES. This was a regression introduced upstream in DefinitelyTyped PR #73297 and flagged on discussion #74080 on 2025-11-14 — citing "the latest security issues on NPMJS" as the same supply-chain motivation that prompted our audit.

The fix landed upstream as DefinitelyTyped PR #74249 ("Remove AWS SDK from dependencies, use structural types") and shipped to npm as @types/[email protected] on 2026-01-26. Our existing spec floor of ^6.4.9 already permitted it; the lockfile had simply never been refreshed since. Bumping the floor to ^6.4.22 makes the fix mandatory and prevents a future refresh from silently regressing back to 6.4.21.

Caveat for future bumps: the 7.0.x line of @types/nodemailer still carries @aws-sdk/client-sesv2 as a runtime dep — the structural-types fix was backported to v6 and forward-ported to v8, but not to v7. Stay on v6 (or jump straight to v8) to keep the install clean.

Results:

MetricBeforeAfterΔ
Total unique prod packages (repo-wide)1,8801,807−73
@vendure/email-plugin transitive (prod)290216−74
@types/nodemailer subtree773−74

Stage 2 — Remove body-parser direct dep from @vendure/core

  • Commit: ca3d09390 on chore/dependency-audit
  • Date: 2026-05-21T08:18:00.680Z
  • Total unique production packages: 1807

Per-Vendure-package transitive footprint

PackageDirect depsUnique transitive (prod)
@vendure/core40453
@vendure/common00
@vendure/email-plugin7216
@vendure/asset-server-plugin320
@vendure/admin-ui-plugin371
@vendure/telemetry-plugin9162
@vendure/harden-plugin2153
@vendure/job-queue-plugin223
@vendure/graphiql-plugin165
@vendure/testing834
@vendure/cli1192
@vendure/create1146
@vendure/dashboard67838
@vendure/ui-devkit11810
@vendure/admin-ui48115
<details> <summary>Per-direct-dep transitive counts (click to expand)</summary>

@vendure/core

Direct depTransitive count
@nestjs/terminus295
@nestjs/typeorm260
@nestjs/apollo237
typeorm186
@apollo/server151
@nestjs/graphql149
@nestjs/core102
@nestjs/platform-express102
express65
graphql-upload32
http-proxy-middleware19
@nestjs/common18
@graphql-tools/stitch17
ioredis11
cookie-session9
i18next-icu9
intl-messageformat8
fs-extra4
bcrypt3
graphql-scalars3
graphql-tag3
i18next3
mime-types2
rxjs2
@vendure/common1
cron-time-generator1
croner1
cronstrue1
csv-parse1
graphql1
graphql-fields1
i18next-fs-backend1
i18next-http-middleware1
image-size1
ms1
nanoid1
picocolors1
progress1
reflect-metadata1
semver1

@vendure/email-plugin

Direct depTransitive count
mjml140
express65
handlebars6
fs-extra4
@types/nodemailer3
dateformat1
nodemailer1

@vendure/asset-server-plugin

Direct depTransitive count
file-type10
sharp6
fs-extra4

@vendure/admin-ui-plugin

Direct depTransitive count
express-rate-limit66
fs-extra4
date-fns1

@vendure/telemetry-plugin

Direct depTransitive count
@opentelemetry/auto-instrumentations-node161
@opentelemetry/sdk-node78
@opentelemetry/exporter-logs-otlp-proto25
@opentelemetry/exporter-trace-otlp-http25
@opentelemetry/sdk-logs6
@opentelemetry/resources4
@opentelemetry/context-async-hooks2
@opentelemetry/api1
javascript-stringify1

@vendure/harden-plugin

Direct depTransitive count
@apollo/server151
graphql-query-complexity3

@vendure/job-queue-plugin

Direct depTransitive count
bullmq23
ioredis11

@vendure/graphiql-plugin

Direct depTransitive count
express65

@vendure/testing

Direct depTransitive count
form-data20
node-fetch7
graphql-tag3
@graphql-typed-document-node/core2
@vendure/common1
faker1
graphql1
sql.js1

@vendure/cli

Direct depTransitive count
ts-node35
ts-morph26
change-case16
@clack/prompts4
fs-extra4
tsconfig-paths4
@vendure/common1
commander1
dotenv1
picocolors1
strip-json-comments1

@vendure/create

Direct depTransitive count
open10
tcp-port-used7
cross-spawn6
handlebars6
tar6
@clack/prompts4
fs-extra4
@vendure/common1
commander1
picocolors1
semver1

@vendure/dashboard

Direct depTransitive count
@vendure-io/ui424
@vendure-io/design-tokens325
@lingui/vite-plugin281
@tanstack/router-plugin261
@lingui/cli191
@vitejs/plugin-react175
@tailwindcss/vite141
vite132
@tanstack/eslint-plugin-query113
@lingui/react87
@lingui/babel-plugin-lingui-macro85
@lingui/core85
express-rate-limit66
@tiptap/starter-kit60
@babel/preset-typescript51
@tiptap/react51
@babel/preset-react47
recharts44
@tiptap/extension-floating-menu40
@babel/core39
@tiptap/extension-placeholder38
@tiptap/extension-image37
@tiptap/extension-table37
@tiptap/extension-text-style37
@tiptap/pm35
vaul33
@tanstack/router-devtools21
fast-glob18
@tanstack/react-router15
react-dropzone10
@dnd-kit/modifiers8
@dnd-kit/sortable8
motion8
@dnd-kit/core7
gql.tada7
react-day-picker6
@tanstack/react-query-devtools5
@tanstack/react-table5
@hookform/resolvers4
@uidotdev/usehooks4
fs-extra4
input-otp4
json-edit-react4
next-themes4
sonner4
tsconfig-paths4
@tanstack/react-query3
@types/react-dom3
react-dom3
@types/react2
acorn-walk2
lucide-react2
react-hook-form2
@fontsource-variable/geist-mono1
@fontsource-variable/inter1
@fontsource-variable/public-sans1
acorn1
awesome-graphql-client1
clsx1
date-fns1
graphql1
react1
strip-json-comments1
tailwind-merge1
tailwindcss1
tw-animate-css1
zod1

@vendure/ui-devkit

Direct depTransitive count
@angular-devkit/build-angular705
@angular/cli221
@angular/compiler-cli62
chokidar15
glob8
chalk6
fs-extra4
@angular/compiler2
rxjs2
@vendure/admin-ui1
@vendure/common1

@vendure/admin-ui

Direct depTransitive count
apollo-angular36
apollo-upload-client35
@apollo/client32
@clr/angular20
ngx-translate-messageformat-compiler16
@clr/core14
@clr/ui12
@cds/core11
prosemirror-menu10
@angular/platform-browser-dynamic9
@ng-select/ng-select9
@angular/cdk8
@angular/forms8
@angular/router8
@messageformat/core8
prosemirror-gapcursor8
prosemirror-tables8
@angular/platform-browser7
prosemirror-history7
prosemirror-keymap7
@angular/animations6
@ngx-translate/core6
@ngx-translate/http-loader6
ngx-pagination6
prosemirror-commands6
prosemirror-dropcursor6
prosemirror-inputrules6
prosemirror-schema-list6
@angular/common5
messageformat5
prosemirror-state5
@angular/core4
prosemirror-schema-basic3
react-dom3
@biesbjerg/ngx-translate-extract-marker2
@clr/icons2
rxjs2
@angular/language-service1
@vendure/common1
@webcomponents/custom-elements1
chartist1
codejar1
dayjs1
graphql1
just-extend1
react1
tslib1
zone.js1
</details>

Changes

Removed body-parser from @vendure/core/package.json and updated the documented user-facing pattern in packages/core/src/common/types/common-types.ts (JSDoc on the Middleware interface) to recommend import { json } from 'express' instead of import { json } from 'body-parser'. Regenerated docs/docs/reference/typescript-api/common/middleware.mdx from the new JSDoc.

Why: body-parser was declared as a direct dependency of @vendure/core but never imported in source. Its only references were in JSDoc / generated docs telling users to use import { json } from 'body-parser' to override the JSON payload size limit. The JSDoc text "Vendure relies on the body-parser middleware to parse incoming JSON data" was true under the Express 4 / older NestJS stack but became inaccurate after the Express 5 / NestJS 11 / Apollo Server v5 upgrade — Vendure now relies on Express 5's built-in JSON parser, which re-exports body-parser v2 directly (exports.json = bodyParser.json in node_modules/express/lib/express.js). The documented express.json() is byte-identical in behaviour to body-parser.json().

Honest impact assessment. The repo-wide unique-package count did not move:

MetricStage 1Stage 2Δ
Total unique prod packages (repo-wide)1,8071,8070
@vendure/core direct dep count4140−1
@vendure/core transitive union (prod)4534530

body-parser's 41-package subtree remains reachable through @apollo/server's bundled [email protected] (and via [email protected], which still appears as a non-dev parent in our admin-ui lockfile resolution). The supply-chain win is deferred to:

  1. Apollo Server upgrade — once @apollo/server is bumped past its Express 4 internal pin (Apollo Server v5+ already supports this), the transitive pull of [email protected] disappears.
  2. Admin-UI retirement (karma) — when the Angular admin-ui is fully retired in favour of the React dashboard.

This change still has standalone value:

  • We no longer declare a dependency our code doesn't import.
  • We're no longer pinning a body-parser version (^1.20.2) we don't control downstream.
  • The JSDoc is now factually accurate about the current stack.
  • The new documented pattern (import { json } from 'express') is the modern Express 5 idiom and doesn't require users to declare any extra dependency.

User-facing note. Users who copied the old import { json } from 'body-parser' snippet into their own configs will continue to work today because body-parser is still hoisted at top-level via the transitive parents above. Once those parents drop body-parser (deferred wins), a clean install will fail with Cannot find module 'body-parser' for those users. Recovery is a one-line swap to import { json } from 'express' (identical behaviour) or bun add body-parser (preserves the old pattern).

Audit lesson recorded. Per-direct-dep subtree counts (as reported by snapshot.mjs) overstate removal savings when subtrees overlap with those of other declared parents. The honest savings only show up in the union (transitiveTotal) when the last declared parent of a subtree is removed. Worth considering a future enhancement to the snapshot script: an "additive transitive" column that reports packages reachable only via a given direct dep.

Stage 3 — Drop node-fetch + form-data direct deps (native fetch/FormData)

  • Commit: 324cc22f3 on chore/dependency-audit
  • Date: 2026-05-21T09:02:58.355Z
  • Total unique production packages: 1807

Per-Vendure-package transitive footprint

PackageDirect depsUnique transitive (prod)
@vendure/core40453
@vendure/common00
@vendure/email-plugin7216
@vendure/asset-server-plugin320
@vendure/admin-ui-plugin371
@vendure/telemetry-plugin9162
@vendure/harden-plugin2153
@vendure/job-queue-plugin223
@vendure/graphiql-plugin165
@vendure/testing67
@vendure/cli1192
@vendure/create1146
@vendure/dashboard67838
@vendure/ui-devkit11810
@vendure/admin-ui48115
<details> <summary>Per-direct-dep transitive counts (click to expand)</summary>

@vendure/core

Direct depTransitive count
@nestjs/terminus295
@nestjs/typeorm260
@nestjs/apollo237
typeorm186
@apollo/server151
@nestjs/graphql149
@nestjs/core102
@nestjs/platform-express102
express65
graphql-upload32
http-proxy-middleware19
@nestjs/common18
@graphql-tools/stitch17
ioredis11
cookie-session9
i18next-icu9
intl-messageformat8
fs-extra4
bcrypt3
graphql-scalars3
graphql-tag3
i18next3
mime-types2
rxjs2
@vendure/common1
cron-time-generator1
croner1
cronstrue1
csv-parse1
graphql1
graphql-fields1
i18next-fs-backend1
i18next-http-middleware1
image-size1
ms1
nanoid1
picocolors1
progress1
reflect-metadata1
semver1

@vendure/email-plugin

Direct depTransitive count
mjml140
express65
handlebars6
fs-extra4
@types/nodemailer3
dateformat1
nodemailer1

@vendure/asset-server-plugin

Direct depTransitive count
file-type10
sharp6
fs-extra4

@vendure/admin-ui-plugin

Direct depTransitive count
express-rate-limit66
fs-extra4
date-fns1

@vendure/telemetry-plugin

Direct depTransitive count
@opentelemetry/auto-instrumentations-node161
@opentelemetry/sdk-node78
@opentelemetry/exporter-logs-otlp-proto25
@opentelemetry/exporter-trace-otlp-http25
@opentelemetry/sdk-logs6
@opentelemetry/resources4
@opentelemetry/context-async-hooks2
@opentelemetry/api1
javascript-stringify1

@vendure/harden-plugin

Direct depTransitive count
@apollo/server151
graphql-query-complexity3

@vendure/job-queue-plugin

Direct depTransitive count
bullmq23
ioredis11

@vendure/graphiql-plugin

Direct depTransitive count
express65

@vendure/testing

Direct depTransitive count
graphql-tag3
@graphql-typed-document-node/core2
@vendure/common1
faker1
graphql1
sql.js1

@vendure/cli

Direct depTransitive count
ts-node35
ts-morph26
change-case16
@clack/prompts4
fs-extra4
tsconfig-paths4
@vendure/common1
commander1
dotenv1
picocolors1
strip-json-comments1

@vendure/create

Direct depTransitive count
open10
tcp-port-used7
cross-spawn6
handlebars6
tar6
@clack/prompts4
fs-extra4
@vendure/common1
commander1
picocolors1
semver1

@vendure/dashboard

Direct depTransitive count
@vendure-io/ui424
@vendure-io/design-tokens325
@lingui/vite-plugin281
@tanstack/router-plugin261
@lingui/cli191
@vitejs/plugin-react175
@tailwindcss/vite141
vite132
@tanstack/eslint-plugin-query113
@lingui/react87
@lingui/babel-plugin-lingui-macro85
@lingui/core85
express-rate-limit66
@tiptap/starter-kit60
@babel/preset-typescript51
@tiptap/react51
@babel/preset-react47
recharts44
@tiptap/extension-floating-menu40
@babel/core39
@tiptap/extension-placeholder38
@tiptap/extension-image37
@tiptap/extension-table37
@tiptap/extension-text-style37
@tiptap/pm35
vaul33
@tanstack/router-devtools21
fast-glob18
@tanstack/react-router15
react-dropzone10
@dnd-kit/modifiers8
@dnd-kit/sortable8
motion8
@dnd-kit/core7
gql.tada7
react-day-picker6
@tanstack/react-query-devtools5
@tanstack/react-table5
@hookform/resolvers4
@uidotdev/usehooks4
fs-extra4
input-otp4
json-edit-react4
next-themes4
sonner4
tsconfig-paths4
@tanstack/react-query3
@types/react-dom3
react-dom3
@types/react2
acorn-walk2
lucide-react2
react-hook-form2
@fontsource-variable/geist-mono1
@fontsource-variable/inter1
@fontsource-variable/public-sans1
acorn1
awesome-graphql-client1
clsx1
date-fns1
graphql1
react1
strip-json-comments1
tailwind-merge1
tailwindcss1
tw-animate-css1
zod1

@vendure/ui-devkit

Direct depTransitive count
@angular-devkit/build-angular705
@angular/cli221
@angular/compiler-cli62
chokidar15
glob8
chalk6
fs-extra4
@angular/compiler2
rxjs2
@vendure/admin-ui1
@vendure/common1

@vendure/admin-ui

Direct depTransitive count
apollo-angular36
apollo-upload-client35
@apollo/client32
@clr/angular20
ngx-translate-messageformat-compiler16
@clr/core14
@clr/ui12
@cds/core11
prosemirror-menu10
@angular/platform-browser-dynamic9
@ng-select/ng-select9
@angular/cdk8
@angular/forms8
@angular/router8
@messageformat/core8
prosemirror-gapcursor8
prosemirror-tables8
@angular/platform-browser7
prosemirror-history7
prosemirror-keymap7
@angular/animations6
@ngx-translate/core6
@ngx-translate/http-loader6
ngx-pagination6
prosemirror-commands6
prosemirror-dropcursor6
prosemirror-inputrules6
prosemirror-schema-list6
@angular/common5
messageformat5
prosemirror-state5
@angular/core4
prosemirror-schema-basic3
react-dom3
@biesbjerg/ngx-translate-extract-marker2
@clr/icons2
rxjs2
@angular/language-service1
@vendure/common1
@webcomponents/custom-elements1
chartist1
codejar1
dayjs1
graphql1
just-extend1
react1
tslib1
zone.js1
</details>

Changes

Removed node-fetch@^2.7.0 and form-data@^4.0.0 from the workspace. Three call-sites were rewritten to use Node's built-in fetch, FormData, Blob, and AbortSignal.timeout (all available on the supported engine range ^20.19.0 || >=22.12.0):

FileBeforeAfter
packages/core/src/health-check/http-health-check-strategy.tsimport fetch from 'node-fetch'; fetch(url, { timeout })native fetch; fetch(url, { signal: AbortSignal.timeout(timeout) }) when a timeout is supplied
packages/testing/src/simple-graphql-client.tsnode-fetch (with named RequestInit/Response imports) + form-data for multipart uploadnative fetch/FormData/Blob; a minimal inline extension to MIME table preserves per-part Content-Type for common test fixtures (images, pdf, txt, json) — the same behaviour form-data previously got from mime-types
packages/asset-server-plugin/e2e/asset-server-plugin.e2e-spec.tsnode-fetch + res.buffer()native fetch + Buffer.from(await res.arrayBuffer())

Package-level changes:

  • packages/testing/package.json: dropped node-fetch, form-data, @types/node-fetch.
  • packages/asset-server-plugin/package.json: dropped node-fetch, @types/node-fetch (both devDependencies).
  • packages/core: no package.json change — the node-fetch import in http-health-check-strategy.ts was never declared in dependencies. It had been working purely via Bun's flat-hoisted node_modules resolving a sibling-workspace copy. The native-fetch rewrite incidentally fixes that latent declaration bug.

Impact

  • Workspace direct declarations of node-fetch / form-data / @types/node-fetch: 0 (down from 3 / 1 / 2 respectively).
  • @vendure/testing published footprint: direct deps 8 → 6, unique transitive 34 → 7. Downstream users installing just @vendure/testing no longer pull either subtree.
  • Repo-wide unique production package count: 1807 (unchanged) — same subtree-overlap effect observed in Stage 2:
    • [email protected] is still anchored by @apollo/server@4, cross-fetch, fbjs (via mjml), gaxios, web-resource-inliner.
    • [email protected] is still anchored by axios (mjml subtree) and by @types/node-fetch — which is itself only present because @apollo/server@4 declares it.

So the bulk transitive collapse for both packages is gated on the same Apollo Server v5 upgrade noted in the #4761 Apollo v5 comment. Once @apollo/server@5 lands (which itself is gated on @nestjs/apollo@14), @types/node-fetch, [email protected], and a chunk of the form-data subtree all drop in one cascade alongside body-parser.

The correctness win is independent and unconditional: our published packages no longer declare node-fetch or form-data at all, and the undeclared-dep latent bug in @vendure/core's deprecated health-check is fixed at the same time.

Stage final — after #4762-#4771 landed on minor

  • Commit: c18f46f28 on minor
  • Date: 2026-05-22T14:51:59.031Z
  • Total unique production packages: 1735

Per-Vendure-package transitive footprint

PackageDirect depsUnique transitive (prod)
@vendure/core37432
@vendure/common00
@vendure/email-plugin7216
@vendure/asset-server-plugin320
@vendure/admin-ui-plugin371
@vendure/telemetry-plugin16100
@vendure/harden-plugin2153
@vendure/job-queue-plugin223
@vendure/graphiql-plugin165
@vendure/testing79
@vendure/cli1183
@vendure/create1039
@vendure/dashboard67838
@vendure/ui-devkit11810
@vendure/admin-ui48115
<details> <summary>Per-direct-dep transitive counts (click to expand)</summary>

@vendure/core

Direct depTransitive count
@nestjs/typeorm260
@nestjs/apollo237
typeorm186
@apollo/server151
@nestjs/graphql149
@nestjs/core102
@nestjs/platform-express102
express65
graphql-upload32
http-proxy-middleware19
@nestjs/common18
@graphql-tools/stitch17
ioredis11
cookie-session9
i18next-icu9
intl-messageformat8
fs-extra4
bcrypt3
graphql-scalars3
graphql-tag3
i18next3
mime-types2
rxjs2
@vendure/common1
cron-time-generator1
croner1
cronstrue1
csv-parse1
graphql1
i18next-fs-backend1
i18next-http-middleware1
image-size1
ms1
nanoid1
picocolors1
reflect-metadata1
semver1

@vendure/email-plugin

Direct depTransitive count
mjml140
express65
handlebars6
fs-extra4
@types/nodemailer3
dateformat1
nodemailer1

@vendure/asset-server-plugin

Direct depTransitive count
file-type10
sharp6
fs-extra4

@vendure/admin-ui-plugin

Direct depTransitive count
express-rate-limit66
fs-extra4
date-fns1

@vendure/telemetry-plugin

Direct depTransitive count
@opentelemetry/sdk-node78
@opentelemetry/instrumentation-pg35
@opentelemetry/exporter-logs-otlp-proto25
@opentelemetry/exporter-trace-otlp-http25
@opentelemetry/instrumentation-http23
@opentelemetry/instrumentation-mysql223
@opentelemetry/instrumentation-express22
@opentelemetry/instrumentation-ioredis22
@opentelemetry/instrumentation-nestjs-core21
@opentelemetry/instrumentation-graphql20
@opentelemetry/instrumentation-runtime-node14
@opentelemetry/sdk-logs6
@opentelemetry/resources4
@opentelemetry/context-async-hooks2
@opentelemetry/api1
javascript-stringify1

@vendure/harden-plugin

Direct depTransitive count
@apollo/server151
graphql-query-complexity3

@vendure/job-queue-plugin

Direct depTransitive count
bullmq23
ioredis11

@vendure/graphiql-plugin

Direct depTransitive count
express65

@vendure/testing

Direct depTransitive count
graphql-tag3
@graphql-typed-document-node/core2
mime-types2
@vendure/common1
faker1
graphql1
sql.js1

@vendure/cli

Direct depTransitive count
ts-node35
ts-morph26
cross-spawn6
@clack/prompts4
fs-extra4
tsconfig-paths4
@vendure/common1
commander1
dotenv1
picocolors1
strip-json-comments1

@vendure/create

Direct depTransitive count
open10
cross-spawn6
handlebars6
tar6
@clack/prompts4
fs-extra4
@vendure/common1
commander1
picocolors1
semver1

@vendure/dashboard

Direct depTransitive count
@vendure-io/ui424
@vendure-io/design-tokens325
@lingui/vite-plugin281
@tanstack/router-plugin261
@lingui/cli191
@vitejs/plugin-react175
@tailwindcss/vite141
vite132
@tanstack/eslint-plugin-query113
@lingui/react87
@lingui/babel-plugin-lingui-macro85
@lingui/core85
express-rate-limit66
@tiptap/starter-kit60
@babel/preset-typescript51
@tiptap/react51
@babel/preset-react47
recharts44
@tiptap/extension-floating-menu40
@babel/core39
@tiptap/extension-placeholder38
@tiptap/extension-image37
@tiptap/extension-table37
@tiptap/extension-text-style37
@tiptap/pm35
vaul33
@tanstack/router-devtools21
fast-glob18
@tanstack/react-router15
react-dropzone10
@dnd-kit/modifiers8
@dnd-kit/sortable8
motion8
@dnd-kit/core7
gql.tada7
react-day-picker6
@tanstack/react-query-devtools5
@tanstack/react-table5
@hookform/resolvers4
@uidotdev/usehooks4
fs-extra4
input-otp4
json-edit-react4
next-themes4
sonner4
tsconfig-paths4
@tanstack/react-query3
@types/react-dom3
react-dom3
@types/react2
acorn-walk2
lucide-react2
react-hook-form2
@fontsource-variable/geist-mono1
@fontsource-variable/inter1
@fontsource-variable/public-sans1
acorn1
awesome-graphql-client1
clsx1
date-fns1
graphql1
react1
strip-json-comments1
tailwind-merge1
tailwindcss1
tw-animate-css1
zod1

@vendure/ui-devkit

Direct depTransitive count
@angular-devkit/build-angular705
@angular/cli221
@angular/compiler-cli62
chokidar15
glob8
chalk6
fs-extra4
@angular/compiler2
rxjs2
@vendure/admin-ui1
@vendure/common1

@vendure/admin-ui

Direct depTransitive count
apollo-angular36
apollo-upload-client35
@apollo/client32
@clr/angular20
ngx-translate-messageformat-compiler16
@clr/core14
@clr/ui12
@cds/core11
prosemirror-menu10
@angular/platform-browser-dynamic9
@ng-select/ng-select9
@angular/cdk8
@angular/forms8
@angular/router8
@messageformat/core8
prosemirror-gapcursor8
prosemirror-tables8
@angular/platform-browser7
prosemirror-history7
prosemirror-keymap7
@angular/animations6
@ngx-translate/core6
@ngx-translate/http-loader6
ngx-pagination6
prosemirror-commands6
prosemirror-dropcursor6
prosemirror-inputrules6
prosemirror-schema-list6
@angular/common5
messageformat5
prosemirror-state5
@angular/core4
prosemirror-schema-basic3
react-dom3
@biesbjerg/ngx-translate-extract-marker2
@clr/icons2
rxjs2
@angular/language-service1
@vendure/common1
@webcomponents/custom-elements1
chartist1
codejar1
dayjs1
graphql1
just-extend1
react1
tslib1
zone.js1
</details>

Changes

This is the closing snapshot of the supply-chain audit. The seven PRs that landed on minor between Stage 3 and here:

PRScope
#4762Stages 1–3 bundled: body-parser removal, @types/nodemailer recategorisation, node-fetch + form-data → native, cross-spawn formalised as a direct dep of @vendure/cli
#4764@vendure/telemetry-plugin: replaced @opentelemetry/auto-instrumentations-node with eight explicit instrumentations (http, express, nestjs-core, graphql, pg, mysql2, ioredis, runtime-node). Exposed getDefaultInstrumentations() so callers can extend the curated set without re-declaring it
#4767@vendure/cli: vendored camelCase / pascalCase / kebabCase / constantCase from [email protected], dropped the dep
#4768@vendure/create: replaced tcp-port-used with a native net.Socket implementation. Added an explicit 2s socket timeout so a DROP-firewalled host can't stall findAvailablePort for the OS-level connect timeout × PORT_SCAN_RANGE
#4769@vendure/core: vendored graphqlFields() (~70 LOC covering fragments, fragment spreads, @skip/@include with variables, field merging), dropped the graphql-fields dep
#4770@vendure/core: vendored a focused ProgressBar helper for the importer (silent in non-TTY environments, capped to stream.columns), dropped the progress dep
#4771@vendure/core: dropped @nestjs/terminus. Vendored HealthCheckError, HealthIndicator, HealthIndicatorFunction, HealthIndicatorResult as a compat shim. Replaced TypeOrmHealthIndicator with a direct SELECT 1 against the raw DataSource

Closed without merging: #4766 (mjml optional peer). Deferred.

Results

Total unique production packages across the repo: 1,807 → 1,735 (−72).

Combined with Stages 0–3 (1,880 → 1,807, −73), the audit removed 145 unique production packages end-to-end — matching the ≈145 figure quoted in the issue baseline.

Per-Vendure-package transitive footprint (Stage 0 baseline → final):

PackageDirect depsΔ directTransitiveΔ transitive
@vendure/core41 → 37−4453 → 432−21
@vendure/email-plugin7 → 70290 → 216−74
@vendure/telemetry-plugin9 → 16+7 (curated explicit)162 → 100−62
@vendure/testing8 → 7−134 → 9−25
@vendure/cli11 → 11092 → 83−9
@vendure/create11 → 10−146 → 39−7

Notes:

  • @vendure/telemetry-plugin gained 7 direct deps (one per curated instrumentation) but shed 62 transitives — the trade is intentional: explicit declarations a maintainer can audit at a glance, in exchange for losing the Mongo / Kafka / Hapi / Cassandra / etc. subtrees that auto-instrumentations-node carried for libraries Vendure doesn't use.
  • @vendure/core only shed 21 transitives despite removing four direct deps (body-parser, @nestjs/terminus, graphql-fields, progress). The terminus subtree (~295 packages quoted in the baseline) is mostly reachable through the rest of @nestjs/* and @apollo/server regardless — same overlap pattern documented for body-parser in Stage 2. The win is in direct attack surface, not raw transitive count.
  • @vendure/testing is the biggest relative win: 34 → 9 unique transitives (−74%). Plugin authors writing e2e suites pull in dramatically less now.

Keep-decisions documented during the audit

Where the audit considered a dep and decided against removal:

  • fs-extra — data-bearing-ish, subtree-overlap means modest saving, canonical-tier
  • cross-spawn — security-sensitive (Windows .cmd shell-escape handling)
  • dateformat — data-bearing (format-mask grammar)
  • cron-time-generator — public API surface (typeof CronTime exposure to plugin authors)
  • mime-types — data-bearing (IANA MIME registry snapshot, actively maintained upstream)
  • cookie-session, graphql-upload, http-proxy-middleware — canonical implementations of wire/spec contracts where rolling our own carries security risk for marginal gain

The full reasoning is captured as comments on #4761 so future audits don't re-litigate.