Skip to content

chore(deps): upgrade to express 5 - #232

Merged
Bccorb merged 1 commit into
mainfrom
chore/express-5
Aug 31, 2026
Merged

chore(deps): upgrade to express 5#232
Bccorb merged 1 commit into
mainfrom
chore/express-5

Conversation

@Bccorb

@Bccorb Bccorb commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Supersedes #198, which was a version bump only. Express 5 broke four things here that needed real work.

What broke, and why

Every route with a query schema returned 404. Express 5 exposes req.query as a getter with no setter, and one that re-parses the URL on every read, so the assignment in defineRoute threw. That silently took out /internal/auth-events/*, /admin/auth-events, and /webauthn/register/start. The validated query is now installed as an own data property, which is also what makes the schema's coercions survive into the handler.

The default query parser moved from extended to simple, which would read a[b]=1 as the literal key a[b]. Pinned back to extended. The dashboard sends flat repeated keys (type=x&type=y) and the React SDK uses URLSearchParams, so nothing in tree depends on the difference, but an outside integrator might, and a dependency bump is the wrong place to change how query strings parse. Moving to the narrower parser stays available as a deliberate change, and is worth considering on its own: simple avoids the qs deep nesting surface.

A request with no body now arrives as undefined rather than {}. Bodies are validated as {} when absent, so a body-less request still reports its missing fields instead of one opaque "expected object, received undefined". DELETE /admin/users destructured req.body unguarded and threw a TypeError on a body-less call, so it now answers User not found. as it did before.

The SPA history fallback route no longer parsed. path-to-regexp v8 rejects a bare *, so /console/* is now the named /console/*splat. This was failing at registration time and crashing the whole adminDashboard integration file.

Types

Route params go through a new RouteRequest, since Express 5 widens req.params to string | string[] for the repeatable params this API does not use. That covers the 26 type errors without casting at each site.

Contract

No contract change. Every default Express 5 alters is pinned or restored, so no caller has to adapt and the SDKs need no coordinated release.

Verification

  • npm run typecheck, npm run lint, npm run format:check: clean
  • npm run test:run: 1194 passed, 1 skipped (the raw bump was 1144 passed / 43 failed)
  • npm run coverage: 98.79% statements, 96.36% branches, both above threshold
  • Both new tests were confirmed to fail without their fix

Noticed but not touched

Filed separately rather than folded in here: #229 (npm run build does not clean dist/), #230 (non-CORS errors answer 404 instead of 500), #231 (global rate limiters have no test coverage).

Bumps express 4.22.2 to 5.2.1 and @types/express to match. The HTTP contract is
unchanged: each default Express 5 alters is pinned or restored.

Query schema validation had stopped applying. Express 5 exposes req.query as a
getter with no setter that re-reads the URL on every access, so the assignment in
defineRoute threw and every route carrying a query schema answered 404. The
validated query is now installed as an own property so the schema's coercions
survive into the handler.

The default query parser moved from extended to simple, which would read a[b]=1
as the literal key "a[b]". Pinned back to extended so upgrading never silently
changes how a caller's query string parses.

A request with no body now arrives as undefined rather than {}. Bodies are
validated as {} when absent, so a body-less request still reports its missing
fields, and DELETE /admin/users answers "User not found." instead of throwing.

path-to-regexp v8 rejects a bare "*", so the SPA history fallback is now
/console/*splat.

Route params are typed through a new RouteRequest, since Express 5 widens
req.params to string | string[] for repeatable params this API does not use.
Comment thread src/lib/adminDashboard.ts Dismissed
@Bccorb
Bccorb merged commit 1dca9f7 into main Aug 31, 2026
4 checks passed
@Bccorb
Bccorb deleted the chore/express-5 branch August 31, 2026 12:46
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.

2 participants