Web upgrade: Next 16 + React 19 + MSAL v4 - #114
Merged
Conversation
react 19.2 aligns the declared dependency with the React the app router has been running all along (Next-vendored 19 canary). msal-react 3.0.29 is the React-19-compatible bridge that only needs msal-browser 4 — deliberately NOT msal v5, whose COOP redirect bridge requires new bridge pages per origin plus app-registration changes (separate project). The react-leaflet peer overrides are gone: react 19 satisfies react-leaflet 5 natively. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- msalConfig: allowNativeBroker -> allowPlatformBroker (v4 rename); storeAuthStateInCookie stays (deprecated in v4, removed only in v5) - zero-arg useRef() removed in @types/react 19: GlobalSearch (2x), dashboard autoLoadTimerRef - React.MutableRefObject -> React.RefObject in 5 session/progress hooks (all refs are mutable in 19 types) - layout: data-scroll-behavior="smooth" opt-in so route changes keep jumping instead of animating (Next 16 stopped suppressing CSS smooth-scroll during navigation) - next.config: analyzer comment - Turbopack default build skips the webpack-only analyzer, use --webpack for ANALYZE runs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Next 16 rewrites next-env.d.ts on every dev/build run and the routes import inside flips between .next/types and .next/dev/types (vercel/ next.js#86001) - official guidance is to gitignore it. CI now runs `next typegen` before tsc so the type stubs exist on a fresh checkout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Minimal flat config from eslint-config-next@16 (core-web-vitals + typescript) with build-output ignores. Lint stays out of CI as before; the 264 pre-existing findings are untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
okieselbach
added a commit
that referenced
this pull request
Jul 30, 2026
#115) typedRoutes: true (stable in Next 16; `next typegen` already runs in CI before tsc since #114). A typo'd <Link>/router.push target now fails the build instead of 404ing at runtime — the failure class behind the recent RSC/routing incidents. - lib/routes.ts: registry helpers return `Route`; withQuery validates the base path literal. New: deviceBlockUrl (OpsEventsSection previously hand-built /admin/security/device-block against the registry rule), route() to compile-check dynamic-section literals (nav configs, section index redirects), trustedRoute() as the single named seam for runtime-data hrefs (backend-emitted notification deep links, persisted post-login return URL). - Nav types (NavItem, ExpandableSubItem, PageSectionItem) carry Route hrefs — every sidebar/navbar entry is compile-checked. - ClientRedirect is generic so dynamic-section literals infer. Verified: tsc clean; negative test (typo'd static + dynamic routes) fails compilation as intended; 611/611 vitest; static export builds with an unchanged route list. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
okieselbach
added a commit
that referenced
this pull request
Jul 30, 2026
* feat(web): typed routes — broken internal links are now compile errors typedRoutes: true (stable in Next 16; `next typegen` already runs in CI before tsc since #114). A typo'd <Link>/router.push target now fails the build instead of 404ing at runtime — the failure class behind the recent RSC/routing incidents. - lib/routes.ts: registry helpers return `Route`; withQuery validates the base path literal. New: deviceBlockUrl (OpsEventsSection previously hand-built /admin/security/device-block against the registry rule), route() to compile-check dynamic-section literals (nav configs, section index redirects), trustedRoute() as the single named seam for runtime-data hrefs (backend-emitted notification deep links, persisted post-login return URL). - Nav types (NavItem, ExpandableSubItem, PageSectionItem) carry Route hrefs — every sidebar/navbar entry is compile-checked. - ClientRedirect is generic so dynamic-section literals infer. Verified: tsc clean; negative test (typo'd static + dynamic routes) fails compilation as intended; 611/611 vitest; static export builds with an unchanged route list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(web): lint findings to zero errors + CI lint gate Package deal — fixes only land together with the gate, otherwise they drift right back. CI web job now runs `eslint . --max-warnings 163`: errors fail outright, the warning cap is a ratchet (lower it when fixing warnings, never raise it). Fixed to zero (mechanical categories, behavior unchanged): - no-unused-vars (49): dead imports/locals removed; where a prop is part of a live call-site contract, only the destructured binding dropped - no-explicit-any (29): real structural types for event payloads (EnrollmentEvent.data et al -> Record<string, unknown> + per-event interfaces), SignalR passthroughs typed via the library's own signatures; five consumer files got typing-only follow-through - no-unescaped-entities (15), prefer-const, jsx-no-comment-textnodes - no-require-imports (5): scripts/**/*.js override — Node CJS scripts, require() is correct there - one stale eslint-disable directive removed Deliberately NOT fixed inline: the React-Compiler hooks rules new in eslint-plugin-react-hooks v6 (set-state-in-effect 93, refs 26, static-components 14, purity 6, immutability 5, preserve-manual-memoization 3) are demoted to warn in eslint.config.mjs — each is a per-site behavioral refactor in auth/SignalR-adjacent code, to be burned down incrementally under the ratchet. Verified: eslint 0 errors / 163 warnings (gate command exits 0), tsc clean, vitest 611/611, static export builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Aligns the declared React with what the app router actually runs (Next-vendored React 19) and moves to current majors: next 16.2.12, react/react-dom 19.2.8, @types/react 19, msal-browser 4.30.0, msal-react 3.0.29, eslint-config-next 16.
allowNativeBroker->allowPlatformBroker. msal v5 (COOP redirect bridge, per-origin bridge pages, Entra app-registration redirect-URI changes,storeAuthStateInCookieremoval) is a separate future project.overrideshotfix (9739d27) is removed — react 19 satisfies react-leaflet 5 natively.useRef()call sites,MutableRefObject->RefObjectin 5 hooks.data-scroll-behavior="smooth"on<html>— Next 16 no longer suppresses CSS smooth-scroll during navigation; without it every route change would animate to top.next-env.d.tsis now gitignored (Next 16 rewrites it per tool and flips the routes import between.next/typesand.next/dev/types, next-env.d.ts toggles between .next/dev/types/routes.d.ts and .next/types/routes.d.ts even with typedRoutes: false vercel/next.js#86001; official docs say untrack). CI runsnpx next typegenbeforetscso fresh checkouts type-check.next lintwas removed in 16: lint script is noweslint .with a minimal flat config; the 264 pre-existing findings are untouched and lint stays out of CI (as before).Verification
npm ci->next typegen->tsc --noEmit(0) -> vitest 611/611.out/) has an identical route set vs. the pre-upgrade baseline (161 files; Next 16 additionally emits/_not-found/*— additive).next dev, including a full authenticated pass (dev app registration): sign-in request carriesx-client-VER=4.30.0, silent completion -> dashboard with live data (token acquisition works); sidebar client-nav without full-page reload (guards the 1593232 fix this deploy also ships); real geo map renders and survives navigate-away-and-back with no "Map container is already initialized"; recharts (/sla), inspector, dark mode OK.Post-merge checks
next build --webpack./.../index.txt200 on clicks).Rollback: single revert — no infra, SWA-config, or app-registration changes involved.
🤖 Generated with Claude Code