Skip to content

chore(deps): refresh dependencies, base image and drop dead packages - #111

Merged
albanm merged 1 commit into
masterfrom
chore-deps-refresh
Sep 9, 2026
Merged

chore(deps): refresh dependencies, base image and drop dead packages#111
albanm merged 1 commit into
masterfrom
chore-deps-refresh

Conversation

@BatLeDev

@BatLeDev BatLeDev commented Sep 9, 2026

Copy link
Copy Markdown
Member

Dependency refresh pass: measure, security, free wins, proven majors, and documented refusals for the rest.

Security. npm audit was already at 0 on both trees, but the trivy scan of the published images showed everything was hiding elsewhere: the alpine layer and the base image's npm.

Image Before (6.2.0) After
api — alpine 2 CRITICAL / 19 HIGH 0
api — node_modules 1 CRITICAL / 42 HIGH 4 HIGH
worker — alpine 15 CRITICAL / 80 HIGH 0
worker — node_modules 2 CRITICAL / 42 HIGH 4 HIGH

node:24.11.1-alpine3.22node:24.20.0-alpine3.23 with apk upgrade --no-cache (as on data-fair master), plus npm update, which clears every application-level finding. The 4 remaining HIGH are in the bundled npm: the worker needs it for npm rebuild on plugins with native modules, the api for npm config set https-proxy.

Dead dependencies. tar in the worker, never imported — lib-node-registry uses tar-stream. @types/tar and @types/tar-stream go too: tar-stream has shipped its own types since 3.2.1. The only consequence in code, in the 5.2.0 upgrade script: the entry header type is now derived from those types, and pack.entry().end() takes the explicit undefined that the streamx types require.

Majors adopted, each verified against real behaviour rather than its changelog:

  • config 4 → 5: resolved config identical on our .mjs files, re-checked inside the alpine image for both api and worker
  • nanoid 5 → 6: same exports, same alphabet, same length
  • crypto-random-string 5 → 6: the url-safe alphabet gains . and ~, both unreserved in the query string where the webhookKey lands — only newly generated keys change shape, existing ones stay valid
  • @vueuse/core 13 → 14, unplugin-auto-import 19 → 21, unplugin-vue-components 28 → 32: UI build and vue-tsc green
  • @types/multer 1 → 2 (multer is already on 2.x), @types/nodemailer 6 → 8

This aligns config, nanoid, @vueuse/core, unplugin-* and @types/multer with data-fair master.

Declined, with the precise blocker:

  • croner 9 → 10 rejects the N/step syntax that toCRON() (shared/runs.ts) emits for every stepped field. Compared over 60,000 cases: 47,040 diffs are that error, only 5 are a real divergence (resolution of the ambiguous hour on the DST fall-back). Migrating means rewriting toCRON() to min-59/step — not */step, which shifts the offset: 15/20 is 15,35,55 whereas */20 is 0,20,40. That changes already-stored schedulings → dedicated PR.
  • mongodb 6 → 7: staying on 6 to remain aligned with data-fair, catalogs and events.

Undeclared dependencies. Five dependencies that were imported but only resolved through hoisting are now declared the way the sister repos declare them: debug in api (the worker already declared it), ofetch in ui (as in data-fair and events), fs-extra in shared, mongodb in worker — an optional peer of lib-node that worker/src/mongo.ts needs at runtime, declared the same way by catalogs/worker — and mongodb as a devDependency of shared, which only imports its types (a runtime dep there would reach up to the ui, which depends on shared).

Two others are deliberately left undeclared: @data-fair/lib-express in ui/vite.config.ts (data-fair, catalogs, agents and portals all import it there without declaring it) and fast-deep-equal in ui (same situation in data-fair, catalogs and portals). Fixing them here only would break the uniformity — it is a cross-repo chore.

Heads-up.

  • Verified locally: lint, check-types and the unit tests (163 passed) are green. The api/e2e tests did not run — dev environment down. CI must run them with a fresh Vite cache, since unplugin-* changes the module graph.
  • apk upgrade --no-cache makes the build non-deterministic over time: two builds of the same Dockerfile will not necessarily produce the same alpine layer. That is the accepted trade-off, aligned with data-fair master.
  • The lockfile churn is drift absorption across ~180 packages; the root chokidar 4→3.6.0 is a hoisting inversion, not a downgrade (consumers move to a nested 5.0.0).

Security
- base image node:24.11.1-alpine3.22 -> node:24.20.0-alpine3.23 plus
  `apk upgrade --no-cache`, which clears the whole alpine layer
  (api 2 CRITICAL / 19 HIGH -> 0, worker 15 CRITICAL / 80 HIGH -> 0)
  and ships npm 11.19.0 instead of 11.6.2
- `npm update` across the workspaces clears every app-level finding
  (tar, nanoid, axios, multer, nodemailer, fast-uri, minimatch...)

Dead dependencies
- worker: tar, never imported (lib-node-registry uses tar-stream)
- worker: @types/tar and @types/tar-stream, superseded by the types
  tar-stream ships since 3.2.1 — the upgrade script now derives the
  entry header type from them

Undeclared dependencies — imported but resolving only through hoisting,
declared the way the sister repos declare them
- api: debug, already declared by worker
- ui: ofetch, as in data-fair and events
- worker: mongodb, an optional peer of lib-node that worker/src/mongo.ts
  needs at runtime, as catalogs/worker declares it
- shared: fs-extra, and mongodb as a devDependency since shared only
  imports its types (a runtime dep there would reach the ui, which
  depends on shared)

Majors, each verified against real behaviour
- config 4 -> 5: resolved config is byte-identical on our .mjs config
  files, verified inside the alpine image for both api and worker
- nanoid 5 -> 6: same exports, same alphabet, same length
- crypto-random-string 5 -> 6: url-safe alphabet now also uses . and ~,
  both unreserved in the query string the webhook key lands in
- @vueuse/core 13 -> 14, unplugin-auto-import 19 -> 21,
  unplugin-vue-components 28 -> 32: ui builds and vue-tsc passes
- @types/multer 1 -> 2 (multer is already 2.x), @types/nodemailer 6 -> 8

Declined
- croner 9 -> 10: it rejects the `N/step` cron syntax that
  shared/runs.ts toCRON() emits for every stepped scheduling. Migrating
  means rewriting toCRON to `min-59/step` (not `*/step`, which shifts
  the offset) and re-checking stored schedulings — its own PR.
- mongodb 6 -> 7: staying on 6 to match data-fair, catalogs and events.

Aligns config, nanoid, @vueuse/core, unplugin-* and @types/multer with
data-fair master.
@BatLeDev BatLeDev changed the title chore(deps): refresh dependencies and base image chore(deps): refresh dependencies, base image and drop dead packages Sep 9, 2026
@albanm
albanm merged commit 4e0ed31 into master Sep 9, 2026
6 checks passed
@albanm
albanm deleted the chore-deps-refresh branch September 9, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants