Skip to content

chore(deps): update all packages to latest working versions - #236

Merged
antosubash merged 10 commits into
mainfrom
worktree-deps-update
Aug 5, 2026
Merged

chore(deps): update all packages to latest working versions#236
antosubash merged 10 commits into
mainfrom
worktree-deps-update

Conversation

@antosubash

@antosubash antosubash commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Updates every dependency in the repo to the latest version that actually works, verified at each step rather than in one bulk bump.

JavaScript

Seven staged commits, each verified with tests + typecheck + build before moving on:

Stage Change
In-range biome 2.4→2.5.7, vite 8.0→8.2, vitest 4.1.5→4.1.10, react 19.2.5→19.2.8, radix-ui 1.4→1.6.7, @base-ui/react 1.4→1.7, lucide-react 1.14→1.28, recharts 3.8→3.10, tailwindcss 4.2→4.3, react-hook-form 7.74→7.84, zod 4.4.1→4.4.3, +45 more
Dev tooling majors jest-dom 6→7, jsdom 25→30, @vitejs/plugin-react 5→6, @types/node 25→26, rollup-plugin-visualizer 5→7
i18n i18next 23→26, react-i18next 15→17
UI react-day-picker 9→10
Compiler TypeScript 5.9→7.0
Docs site vue 3.5.33→3.5.40, vitepress 1.6.3→1.6.4

npm audit goes from 6 vulnerabilities (1 low, 5 high) to 0 in the main workspace.

Code changes the upgrades required

  • TypeScript 7 removes baseUrl. All 11 tsconfigs set baseUrl: "." next to paths entries already written relative to the config's own directory (./*, ../../packages/ui/src/*) — which is exactly how TS resolves paths when baseUrl is absent, so removing it preserves resolution. Applied to the new-module scaffold template too, so make new-module keeps emitting a config that type-checks. Paths-without-baseUrl has been valid since TS 4.4, so scaffolded modules still work for consumers on TS 5.x.
  • react-day-picker 10 removes the table class slot — the vendored shadcn calendar now styles the grid through month_grid, merging the library default like every other slot in that file.
  • @types/node moved to the workspace root. packages/tsconfig/base.json mandates types: ["vite/client", "node"] for every project, but @types/node was declared only in host/client_app, so the other 12 projects relied on npm hoisting it to the root. Bumping it to v26 stopped that hoisting and CI's typecheck failed with TS2688 on every module. Declaring it at the root (where vite already lives, for the same reason) makes resolution deterministic instead of hoisting-dependent.
  • biome migrate for the 2.5 config format ($schema pin, recommendedpreset).
  • Vite 8.2 native config loader warnings: vitest.config.ts.mts, and vite.config.ts moves __dirnameimport.meta.dirname and gives ./compress-assets an explicit extension. That loader becomes the default in a future major.

Python

No manifest changes, and none are needed. uv.lock is gitignored, so every uv sync resolves fresh — the project was already on the latest of everything (fastapi 0.141.1, starlette 1.3.1, pydantic 2.13.4, sqlalchemy 2.0.51, sqlmodel 0.0.39, uvicorn 0.52.1, celery 5.6.3, ruff 0.16.1, ty 0.0.66). I confirmed no third-party dependency is capped anywhere; the only == pins are the intentional internal simple_module_*==0.0.26 workspace locks.

Deliberately not upgraded

@inertiajs/react stays on 2.3.27 (latest v2) rather than 3.6.1. Inertia 3 is a migration, not a bump:

  1. It drops the data-page attribute for initial page data in favour of <script type="application/json">. The server side is fastapi-inertia, whose latest release (1.1.0) hardcodes <div id="app" data-page='...'> — so the client would not boot.
  2. It removes the arrow-function .layout form (Page.layout = (page) => <Layout>{page}</Layout>), which 21 .tsx files in this repo use.

vitepress stays on 1.6.4 — 2.0 is alpha-only. This leaves 3 unfixable advisories in the docs workspace, all from one chain (esbuild<=0.24.2 ← vite<=6.4.2 ← vitepress<=1.6.4); it is a dev-server-only issue in a devDependency of the docs site.

Verification

Ran from a clean install (npm ci + uv sync --all-packages), then a full /ship pipeline:
browser QA across three categories, plus local CI.

Local CI — all green

Step Result
Lint / format (ruff, biome)
Typecheck (ty, tsc × 13 projects)
Python tests ✅ 1505 passed, 2 skipped
JS tests ✅ 44 passed
Build (Vite) ✅ 333 ms
E2E suite (Playwright) ✅ 12 passed

Also verified: Vite 8.2 boots with no native-config-loader warnings (confirming the
import.meta.dirname / .mts changes), and the ui chunk stayed byte-identical at 50.57 kB
across the baseUrl removal (confirming the @simple-module-py/ui/* alias still resolves).

Browser QA — 53 tests, 0 dependency regressions

Category Passed Failed
Happy Path 16 0
Form & Input Validation 14 2 (both pre-existing)
Error States & Edge Cases 23 0

Verified specifically against what this branch changed:

  • i18next 23 → 26 — the full ~200-entry catalogue was read off the Inertia page prop; every
    value resolves, custom {placeholder} delimiters intact, zero raw keys across 12+ pages.
  • Radix 1.4 → 1.6.7 — Tabs (click + keyboard), Switch, Select, DropdownMenu, AlertDialog all
    work; Escape closes and returns focus to the trigger.
  • react-day-picker 9 → 10 — zero runtime blast radius: the Audit Log date filters are native
    <input type="datetime-local">, and Calendar has no live consumer anywhere in the UI.
  • Vite 8.2 / TS 7 — all 9 routes render on direct full page load (not just Inertia client
    nav), exercising the manifest/entrypoint wiring. No Page "X" not found at any point.
  • Console held at baseline (one /favicon.ico 404) for the entire session.
  • XSS payloads and unicode (中文 / émoji / Arabic RTL) round-trip escaped — no injection.

Methodology note: the first QA attempt fanned out three agents in parallel; one detected that
the Playwright MCP server exposes a single shared browser, so the agents were interleaving on
each other's tabs. That run was discarded in full and re-run serially. All numbers above come
from the serial re-run.

Tests added

Two regression tests, both covering upgrades that had no automated coverage:

  1. packages/ui/src/components/ui/calendar.test.tsx — react-day-picker v10 renamed the table
    class slot to month_grid, fixed by hand here. No page mounts Calendar and no test covered
    it, so only the type-checker was watching.
  2. tests/e2e/test_i18n_rendering.py — asserts translations resolve on all 8 admin pages. A
    broken i18next degrades every page at once yet breaks no existing assertion, because the other
    suites match by role/accessible-name and a raw key is still a visible heading. Detection
    compares rendered text against the catalogue the server shipped for that page rather than
    matching a dotted-key shape — shape matching false-positives on Settings and Feature Flags,
    which legitimately display dotted identifiers as data. Verified non-vacuous with a negative
    control (injecting a real catalogue key is detected).

Known issues — all pre-existing, none introduced here

This PR changes zero Python files; each of these was confirmed absent from its diff.

  1. P1 — inviting an already-registered email returns a raw 500.
    modules/users/users/admin/api.py:76-97admin_invite_user has no try/except around
    service.invite(...), while the sibling admin_create_user catches UserAlreadyExists and
    returns 409 at line 122. Fix is to mirror the existing except block.
  2. P2 — Create/Invite swallow structured 422 errors. The client tests
    typeof data?.detail === 'string', but FastAPI returns an array for 422, so it falls back to
    a generic "Failed to create user" with no field detail. Same bug in Create.tsx and Invite.tsx.
  3. Dual auth providers break boot. A clean uv sync --all-packages installs both users and
    keycloak, tripping SM020 so the app refuses to start — keycloak has to be uninstalled to run
    the app or the e2e suite. make doctor is not in CI, so nothing gates this.
  4. SM_ENVIRONMENT=production cannot boot on a fresh install. register_module_settings
    builds BackgroundTasksSettings() from defaults during register_settings, and its own
    validator rejects the default redis://localhost broker. DB hydration runs later in the
    lifespan and the class ignores SM_BG_TASKS_* env vars, so there is no escape hatch.

These are deliberately not fixed here — they are unrelated to a dependency upgrade and would
widen this diff into application logic. Worth a separate PR.

https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA

Bumps every dependency that already satisfied its declared caret range:
biome 2.4→2.5.7, vite 8.0→8.2, vitest 4.1.5→4.1.10, react 19.2.5→19.2.8,
radix-ui 1.4→1.6.7, @base-ui/react 1.4→1.7, lucide-react 1.14→1.28,
recharts 3.8→3.10, tailwindcss 4.2→4.3, react-hook-form 7.74→7.84,
zod 4.4.1→4.4.3 and others.

peerDependencies and workspace "*" refs are deliberately left permissive.
Resolves all 6 reported npm audit advisories (now 0).

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
jest-dom 6→7, jsdom 25→30, @vitejs/plugin-react 5→6, @types/node 25→26,
rollup-plugin-visualizer 5→7.

Renames vitest.config.ts to .mts: Vite 8.2 warns that ESM syntax in a file
loaded as CommonJS is unsupported by the native config loader, which becomes
the default in a future major.

Runs 'biome migrate' for the 2.5 config format — bumps the $schema pin and
replaces the deprecated linter 'recommended' field with 'preset'.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
Verified against packages/i18n's suite, which exercises the surface most
likely to break across these majors: custom '{'/'}' interpolation delimiters,
keySeparator/nsSeparator disabled for flat dotted keys, CLDR plural suffixes,
missing-key passthrough and runtime locale swapping. All pass unchanged.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
v10 removes the 'table' class slot; the month grid is styled through
'month_grid'. Updates the vendored shadcn calendar accordingly and merges
the library default class, matching how every other slot in the component
is composed.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
TypeScript 7 removes the 'baseUrl' compiler option. Every tsconfig here set
'baseUrl: "."' alongside 'paths' entries that were already written relative
to the config's own directory ('./*', '../../packages/ui/src/*'), which is
exactly how TS resolves 'paths' when 'baseUrl' is absent — so dropping the
option preserves resolution rather than changing it.

Applied to all 11 tsconfigs plus the new-module scaffold template, so
'make new-module' keeps emitting a config that type-checks. Paths without
baseUrl have been valid since TS 4.4, so scaffolded modules still work for
consumers on TS 5.x.

Verified: tsc clean across all 13 projects, and the Vite build emits a
byte-identical ui chunk (50.57 kB / 13.01 kB gzip), confirming the
@simple-module-py/ui/* alias still resolves.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
vue 3.5.33→3.5.40, vitepress 1.6.3→1.6.4 (latest stable — 2.0 is alpha only),
and 'npm audit fix' for the transitive postcss sourceMappingURL advisories
(GHSA-6g55-p6wh-862q and follow-ups).

The remaining advisories all trace to a single unfixable chain,
esbuild<=0.24.2 <- vite<=6.4.2 <- vitepress<=1.6.4. It is a dev-server-only
issue in a devDependency of the docs site, and clearing it would mean moving
to the vitepress 2.0 alpha.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
…oader

Vite 8.2 warns that this config uses features its native (Node
type-stripping) loader cannot handle, and that loader becomes the default in
a future major:

  - __dirname is not defined in an ESM config -> import.meta.dirname
  - the relative './compress-assets' import needs an explicit extension,
    since the native loader does no extension guessing

Importing a .ts extension requires allowImportingTsExtensions, enabled on
host/client_app only (legal because the shared base sets noEmit).

Verified by starting the dev server (warning-free) and loading the app in a
browser — pages render with zero console errors — plus tsc and a production
build, since __dirname backed 'root' and the module-manifest path.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7345659
Status: ✅  Deploy successful!
Preview URL: https://74fde864.simple-module-python.pages.dev
Branch Preview URL: https://worktree-deps-update.simple-module-python.pages.dev

View logs

CI's JS typecheck failed with TS2688 'Cannot find type definition file for
node' on every module and package project, while passing locally.

packages/tsconfig/base.json mandates types: ["vite/client", "node"] for
every project, but @types/node was declared only in host/client_app, so
module/package projects depended on npm hoisting it to the workspace root.
Bumping it to v26 stopped that hoisting and npm nested it under
host/client_app, leaving the other 12 projects with no resolvable copy.
vite is already a root devDependency for exactly this reason.

It passed locally only because this worktree sits inside the parent checkout,
so TypeScript's typeRoots walk escaped the worktree and found the parent's
node_modules/@types/node. Verified the fix with a clean 'npm ci' plus a
--listFiles scan confirming zero files now resolve outside the worktree.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
The v9→10 upgrade renamed the `table` class slot to `month_grid`, which I
fixed by hand in calendar.tsx. Nothing would have caught getting that wrong:
no page mounts Calendar, so the component had zero render coverage and only
the type-checker was watching.

These tests pin the render contract — grid renders, the month_grid class
override lands, nav chevrons resolve — so the next react-day-picker major
fails loudly here instead of at whatever point someone first mounts a date
picker.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
i18next 23 -> 26 was the highest-risk bump in this branch and had no
automated coverage. A broken key resolution degrades every page at once
but breaks no existing assertion: the other suites locate elements by
role and accessible name, and a raw `users.browse.title` is still a
perfectly visible heading.

Detection compares rendered text against the catalogue the server
actually shipped for that page (props.i18n.messages) rather than
matching a dotted-key shape. Shape matching gives false positives —
Settings and Feature Flags legitimately display dotted identifiers as
data (`branding.app_name`, `file_storage.public_uploads`); those are
absent from the catalogue and correctly ignored.

Verified non-vacuous with a negative control: injecting a real
catalogue key into the DOM is detected.

Claude-Session: https://claude.ai/code/session_01YPzNXSuvVnZidQo7ebqMZA
@antosubash
antosubash merged commit c753292 into main Aug 5, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant