- Removed duplicate @typescript-eslint/utils dependency in frontend/package.json - Updated TypeScript version from 5.9.3 to 6.0.1-rc in frontend/package.json and package.json - Adjusted ResizeObserver mock to use globalThis in tests - Modified tsconfig.json and tsconfig.node.json to include empty types array - Cleaned up package-lock.json to reflect TypeScript version change and updated dev dependencies
30 KiB
Major Dependency Upgrade Plan — ESLint v10, TypeScript 6.0, Vite 8
Date: 2026-03-11 Author: Planning Agent Status: Ready for Review Confidence Score: 88% (High for ESLint v10 + TS 6.0; Low for Vite 8 — unreleased)
1. Executive Summary
This plan covers the upgrade of three major frontend toolchain dependencies in the Charon project:
| Dependency | Current Version | Target Version | Status | Risk |
|---|---|---|---|---|
| ESLint | ^9.39.3 <10.0.0 |
^10.0.0 |
Released | Medium — plugin compat gate |
| TypeScript | ^5.9.3 |
^6.0.0 |
Beta (Feb 11) / RC (Mar 6) | Medium — 17+ deprecations |
| Vite | ^7.3.1 |
8.x |
Does not exist | N/A — monitor only |
Key Findings
-
ESLint v10 is released with a comprehensive migration guide. The primary blocker is a note in
lefthook.yml: "ESLint pinned at v9.x.x — do not upgrade until react-hooks plugin supports v10." Theeslint-plugin-react-hooks@7.0.1must be verified for ESLint v10 compatibility before proceeding. -
TypeScript 6.0 is real (Beta: Feb 11, 2026; RC: Mar 6, 2026). It is explicitly designed as a bridge release between TS 5.9 and the native Go-based TS 7.0. It introduces 17+ deprecations/breaking changes (new defaults for
strict,module,target,types,rootDir; removal ofoutFile, legacy module systems; deprecatedbaseUrl,moduleResolution: node). Charon's currenttsconfig.jsonis well-positioned — it already usesmoduleResolution: bundler,strict: true, andmodule: ESNext. The critical impact is thetypesdefault changing to[]. -
Vite 8 does not exist. The latest Vite major is v7 (released June 2025). Charon is already on Vite 7.3.1. This section of the plan documents monitoring strategy and readiness posture only.
Recommended Execution Order
PR-1: TypeScript 6.0 upgrade (fewer external dependencies, most self-contained)
PR-2: ESLint v10 upgrade (blocked on plugin compat verification)
PR-3: Vite 8 (deferred — version does not exist yet)
2. Current Dependency Inventory
Root package.json (/projects/Charon/package.json)
| Package | Current Version | Category |
|---|---|---|
typescript |
^5.9.3 |
devDependency |
vite |
^7.3.1 |
devDependency |
@playwright/test |
^1.58.2 |
devDependency |
prettier |
^3.8.1 |
devDependency |
markdownlint-cli2 |
^0.21.0 |
devDependency |
Frontend package.json (/projects/Charon/frontend/package.json)
| Package | Current Version | Category |
|---|---|---|
typescript |
^5.9.3 |
devDependency |
vite |
^7.3.1 |
devDependency |
vitest |
^4.0.18 |
devDependency |
eslint |
^9.39.3 <10.0.0 |
devDependency |
@eslint/js |
^9.39.3 <10.0.0 |
devDependency |
@eslint/css |
^1.0.0 |
devDependency |
@eslint/json |
^1.1.0 |
devDependency |
@eslint/markdown |
^7.5.1 |
devDependency |
typescript-eslint |
^8.57.0 |
devDependency |
@typescript-eslint/eslint-plugin |
^8.57.0 |
devDependency |
@typescript-eslint/parser |
^8.57.0 |
devDependency |
@vitejs/plugin-react |
^5.1.4 |
devDependency |
@vitest/coverage-istanbul |
^4.0.18 |
devDependency |
@vitest/coverage-v8 |
^4.0.18 |
devDependency |
@vitest/eslint-plugin |
^1.6.10 |
devDependency |
react |
^19.2.4 |
dependency |
react-dom |
^19.2.4 |
dependency |
react-router-dom |
^7.13.1 |
dependency |
@tanstack/react-query |
^5.90.21 |
dependency |
ESLint Plugin Inventory (18 plugins)
| Plugin | Current Version | ESLint v10 Risk |
|---|---|---|
eslint-plugin-react-hooks |
^7.0.1 |
HIGH — explicit blocker in lefthook.yml |
eslint-plugin-react-compiler |
^19.1.0-rc.2 |
Medium — RC, check compat |
eslint-plugin-react-refresh |
^0.5.2 |
Low |
eslint-plugin-import-x |
^4.16.1 |
Low — modern fork |
eslint-plugin-jsx-a11y |
^6.10.2 |
Medium |
eslint-plugin-security |
^4.0.0 |
Low |
eslint-plugin-sonarjs |
^4.0.2 |
Low |
eslint-plugin-unicorn |
^63.0.0 |
Low — actively maintained |
eslint-plugin-promise |
^7.2.1 |
Low |
eslint-plugin-unused-imports |
^4.4.1 |
Low |
eslint-plugin-no-unsanitized |
^4.1.5 |
Medium |
eslint-plugin-testing-library |
^7.16.0 |
Low |
typescript-eslint |
^8.57.0 |
Low — tracks ESLint closely |
@vitest/eslint-plugin |
^1.6.10 |
Low |
@eslint/css |
^1.0.0 |
Low — official ESLint |
@eslint/json |
^1.1.0 |
Low — official ESLint |
@eslint/markdown |
^7.5.1 |
Low — official ESLint |
Config Files Affected
| File | Impact Area |
|---|---|
frontend/tsconfig.json |
TS 6.0 — types, lib, defaults |
frontend/tsconfig.node.json |
TS 6.0 — minor |
frontend/tsconfig.build.json |
TS 6.0 — extends base |
frontend/eslint.config.js |
ESLint v10 — plugin compat |
eslint.config.js (root) |
ESLint v10 — imports frontend config |
frontend/package.json |
All — version bumps |
package.json (root) |
TS + Vite version bumps |
lefthook.yml |
ESLint v10 — remove pin note |
Dockerfile |
Node.js version (already compatible) |
Infrastructure
- Node.js:
24.14.0-alpine(Dockerfile) — meets all upgrade requirements - No
.npmrcfile exists in the project - Go:
1.26.1(not affected by frontend upgrades)
3. Breaking Changes Analysis
3.1 ESLint v10 Breaking Changes
Source: ESLint v10 Migration Guide
| # | Breaking Change | Impact on Charon | Action Required |
|---|---|---|---|
| 1 | Node.js ≥ v20.19, v22.13, or v24 required | None — already on Node 24.14.0 | None |
| 2 | eslint:recommended updated — 3 new rules: no-unassigned-vars, no-useless-assignment, preserve-caught-error |
May flag new violations in codebase | Fix flagged code or disable rules |
| 3 | New config file lookup — searches from linted file, not cwd | Flat config already used; minor risk for monorepo patterns | Verify root config is found correctly |
| 4 | Old .eslintrc format completely removed |
None — already using flat config | None |
| 5 | JSX references now tracked — fixes no-unused-vars for JSX components |
Positive — fewer false positives | May surface new true positives |
| 6 | eslint-env comments reported as errors |
Search codebase for /* eslint-env */ |
Remove if found |
| 7 | Jiti ≥ v2.2.0 required | Check transitive dep version | May need explicit install |
| 8 | Removed deprecated context members — context.getScope(), context.getAncestors(), etc. |
Affects plugins, not our config directly | All 18 plugins must be compatible |
| 9 | Removed deprecated SourceCode methods |
Same — plugin concern | Plugin compat verification |
| 10 | Program AST node range spans entire source | Unlikely to affect us | None |
Critical Plugin Gate: The eslint-plugin-react-hooks compatibility with ESLint v10 must be verified. The lefthook.yml at line ~98 explicitly states: "NOTE: ESLint pinned at v9.x.x — do not upgrade until react-hooks plugin supports v10."
3.2 TypeScript 6.0 Breaking Changes
Source: TypeScript 6.0 Beta Announcement and 6.0 Deprecation List
Default Value Changes
| Setting | Old Default | New Default | Charon Current | Action |
|---|---|---|---|---|
strict |
false |
true |
true (explicit) |
None — already set |
module |
commonjs |
esnext |
ESNext (explicit) |
None — already set |
target |
es5 |
es2025 (floating) |
ES2022 (explicit) |
None — already set |
types |
["*"] (all @types) |
[] (none) |
Not set | ACTION: Add "types": [] |
rootDir |
inferred | . (tsconfig dir) |
Not set | Verify — no emit, noEmit: true |
noUncheckedSideEffectImports |
false |
true |
Not set | Verify no side-effect import issues |
libReplacement |
true |
false |
Not set | None — improves perf |
Deprecations (with ignoreDeprecations: "6.0" escape hatch)
| Deprecation | Charon Uses? | Impact |
|---|---|---|
target: es5 |
No (ES2022) |
None |
--outFile |
No | None |
--downlevelIteration |
No | None |
--moduleResolution node/node10 |
No (bundler) |
None |
--moduleResolution classic |
No | None |
--baseUrl |
No | None |
module: amd/umd/systemjs |
No (ESNext) |
None |
esModuleInterop: false |
Not explicitly set | None |
allowSyntheticDefaultImports: false |
Not set (true in tsconfig.node) |
None |
alwaysStrict: false |
Not set (strict: true covers) |
None |
Legacy module keyword for namespaces |
No | None |
asserts keyword on imports |
No | None |
no-default-lib directives |
No | None |
New Features Available
| Feature | Relevance |
|---|---|
import defer syntax |
Future use — deferred module evaluation |
--module node20 |
Not needed — using bundler |
es2025 target/lib |
Can update target from ES2022 to ES2025 |
| Temporal types | Available via esnext lib |
dom.iterable included in dom |
Can simplify lib array |
--stableTypeOrdering |
Useful for TS 7.0 migration prep |
| Expandable hovers | Editor UX improvement |
Map.getOrInsert / getOrInsertComputed |
Available via esnext lib |
RegExp.escape |
Available via es2025 lib |
#/ subpath imports |
Available for future module aliasing |
lib.d.ts Changes — ArrayBuffer/Buffer Breaking Change
TypeScript 5.9 introduced a behavioral change where ArrayBuffer is no longer a supertype of several TypedArray types. This may cause errors like:
error TS2345: Argument of type 'ArrayBufferLike' is not assignable to parameter of type 'BufferSource'.
error TS2322: Type 'Buffer' is not assignable to type 'Uint8Array<ArrayBufferLike>'.
Mitigation: Ensure @types/node is at latest version. This is a 5.9 → 6.0 carryover that must be verified.
3.3 Vite 8 Breaking Changes
Status: Vite 8 does not exist. The latest major is Vite 7 (released June 24, 2025). Charon is already on Vite 7.3.1.
Monitoring targets:
- Vite GitHub:
https://github.com/vitejs/vite/releases - Vite Blog:
https://vite.dev/blog/ - Vitest compatibility (currently 4.0.18, compatible with Vite 7)
When Vite 8 is announced, revisit this plan with:
- Node.js minimum version
- Browser target defaults
- Plugin API changes (
@vitejs/plugin-reactcompat) - Vitest version compatibility
- Rolldown integration changes
4. Compatibility Matrix
ESLint v10 Plugin Compatibility Verification Matrix
Each plugin must be verified before the ESLint v10 upgrade. The agent performing PR-2 must run these checks:
# For each plugin, check peer dependency support
npm info eslint-plugin-react-hooks peerDependencies
npm info eslint-plugin-react-compiler peerDependencies
npm info eslint-plugin-jsx-a11y peerDependencies
npm info eslint-plugin-import-x peerDependencies
npm info eslint-plugin-security peerDependencies
npm info eslint-plugin-sonarjs peerDependencies
npm info eslint-plugin-unicorn peerDependencies
npm info eslint-plugin-promise peerDependencies
npm info eslint-plugin-unused-imports peerDependencies
npm info eslint-plugin-no-unsanitized peerDependencies
npm info eslint-plugin-testing-library peerDependencies
npm info eslint-plugin-react-refresh peerDependencies
npm info @vitest/eslint-plugin peerDependencies
npm info typescript-eslint peerDependencies
npm info @eslint/css peerDependencies
npm info @eslint/json peerDependencies
npm info @eslint/markdown peerDependencies
Decision Gate: If eslint-plugin-react-hooks does NOT support ESLint v10 in its peerDependencies, the ESLint v10 upgrade is BLOCKED. Do not use --legacy-peer-deps or --force as a workaround.
TypeScript 6.0 Ecosystem Compatibility
| Tool | TS 6.0 Compat | Notes |
|---|---|---|
typescript-eslint@8.57.0 |
Likely — tracks TS closely | Verify with npm install |
vite@7.3.1 |
Yes — Vite uses esbuild/swc, not tsc directly | Type-check is separate |
vitest@4.0.18 |
Yes — same reasoning | Type-check is separate |
@vitejs/plugin-react@5.1.4 |
Yes | No TS compiler dependency |
react@19.2.4 / @types/react |
Yes | Ensure @types/react latest |
@tanstack/react-query@5.90.21 |
Likely — popular library | TanStack already preparing for TS 6 |
knip@5.86.0 |
Verify | Uses TS programmatic API |
Node.js Compatibility
| Tool | Min Node.js | Charon Node.js | Status |
|---|---|---|---|
| ESLint v10 | 20.19 / 22.13 / 24+ | 24.14.0 | Compatible |
| TypeScript 6.0 | TBD (likely same as 5.9) | 24.14.0 | Compatible |
| Vite 7 | 20.19 / 22.12+ | 24.14.0 | Compatible |
5. .npmrc Configuration
No .npmrc file currently exists in the project. No changes needed for these upgrades.
If plugin compatibility issues arise during ESLint v10 upgrade, do NOT create an .npmrc with legacy-peer-deps=true. Instead, wait for plugin updates or use granular overrides in package.json:
// package.json — ONLY if a specific plugin ships a fix before updating peerDeps
{
"overrides": {
"eslint-plugin-EXAMPLE": {
"eslint": "^10.0.0"
}
}
}
6. Dockerfile Changes
No Dockerfile changes required for ESLint v10 or TypeScript 6.0.
Current Dockerfile state:
# Frontend builder stage
FROM node:24.14.0-alpine AS frontend-builder
# ...
RUN npm ci
RUN npm run build
- Node.js 24.14.0 meets all minimum requirements
npm ciwill install the upgraded versions frompackage-lock.json- No new environment variables or build args needed
- Rollup native skip flags (
npm_config_rollup_skip_nodejs_native=1) remain unchanged
Future (Vite 8): If Vite 8 requires a higher Node.js, upgrade the base image at that time.
7. Config File Changes
7.1 TypeScript 6.0 — frontend/tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
+ // Consider upgrading to "ES2025" (TS 6.0 new target)
"useDefineForClassFields": true,
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "lib": ["ES2022", "DOM"],
+ // DOM.Iterable is now included in DOM as of TS 6.0
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
+
+ /* TS 6.0 — explicit types to override new default of [] */
+ "types": []
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
Key changes:
"types": []— Explicitly set to[]. Charon usesnoEmit: trueand doesn't rely on global@typespackages in the main tsconfig. All types come from explicit imports."lib"simplification — Remove"DOM.Iterable"since TS 6.0 includes it in"DOM"automatically."target"consideration — Can optionally upgrade fromES2022toES2025to accessRegExp.escapeand other ES2025 types natively. Not required.
7.2 TypeScript 6.0 — frontend/tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
- "strict": true
+ "strict": true,
+ "types": []
},
"include": ["vite.config.ts"]
}
Note: allowSyntheticDefaultImports is fine — TS 6.0 deprecates setting it to false, not true. Setting it to true remains valid.
7.3 ESLint v10 — frontend/package.json Version Caps
"devDependencies": {
- "eslint": "^9.39.3 <10.0.0",
+ "eslint": "^10.0.0",
- "@eslint/js": "^9.39.3 <10.0.0",
+ "@eslint/js": "^10.0.0",
// ... all other ESLint plugins may need version bumps
}
7.4 ESLint v10 — frontend/eslint.config.js
Likely no structural changes needed since Charon already uses flat config. Potential changes:
- Remove any
/* eslint-env */comments found in source files - Handle new
eslint:recommendedrules (no-unassigned-vars,no-useless-assignment,preserve-caught-error) - Verify
tseslint.config()wrapper compatibility
7.5 ESLint v10 — lefthook.yml
+ # NOTE: ESLint v10 is supported — plugin compatibility verified on [DATE]
- # NOTE: ESLint pinned at v9.x.x — do not upgrade until react-hooks plugin supports v10.
7.6 TypeScript 6.0 — package.json (Root + Frontend)
"devDependencies": {
- "typescript": "^5.9.3",
+ "typescript": "^6.0.0",
}
8. Phase-by-Phase Implementation Plan
Phase 1: Pre-Upgrade Verification (Both PRs)
Owner: Frontend_Dev agent (or whoever picks up the PR)
-
Snapshot current state:
cd /projects/Charon && npm run lint 2>&1 | tee /tmp/eslint-v9-baseline.log cd /projects/Charon/frontend && npx tsc --noEmit 2>&1 | tee /tmp/tsc-v5-baseline.log -
Verify ESLint plugin compatibility (PR-2 gate):
for plugin in eslint-plugin-react-hooks eslint-plugin-react-compiler \ eslint-plugin-jsx-a11y eslint-plugin-import-x eslint-plugin-security \ eslint-plugin-sonarjs eslint-plugin-unicorn eslint-plugin-promise \ eslint-plugin-unused-imports eslint-plugin-no-unsanitized \ eslint-plugin-testing-library eslint-plugin-react-refresh \ @vitest/eslint-plugin typescript-eslint @eslint/css @eslint/json @eslint/markdown; do echo "=== $plugin ===" && npm info "$plugin" peerDependencies 2>/dev/null done -
Search for
eslint-envcomments:grep -r "eslint-env" frontend/src/ --include="*.ts" --include="*.tsx" --include="*.js"
Phase 2: TypeScript 6.0 Upgrade (PR-1)
Scope: TypeScript version bump + tsconfig adjustments
-
Update
typescriptversion in bothpackage.jsonfiles:- Root:
^5.9.3→^6.0.0 - Frontend:
^5.9.3→^6.0.0
- Root:
-
Apply tsconfig changes (Section 7.1 and 7.2 above):
- Add
"types": []totsconfig.jsonandtsconfig.node.json - Remove
"DOM.Iterable"fromlibarray (now included in"DOM")
- Add
-
Run
npm installto update lock file -
Run type-check and fix any new errors:
cd frontend && npx tsc --noEmit -
Common expected issues:
- Missing types from
@types/*packages (solved by"types": []since we don't use globals) ArrayBuffer/Buffertype narrowing (from TS 5.9 lib.d.ts changes)- Type argument inference changes (may need explicit type annotations)
- Missing types from
-
Run full test suite:
cd frontend && npx vitest run -
Run Playwright E2E tests to verify build works:
# The Dockerfile builds with npm ci && npm run build # Verify: cd frontend && npx vite build
Phase 3: ESLint v10 Upgrade (PR-2)
Prerequisite: Phase 1 plugin verification passes. eslint-plugin-react-hooks must declare ESLint v10 support.
-
Remove version cap and update ESLint packages:
cd frontend npm install -D eslint@^10.0.0 @eslint/js@^10.0.0 -
Update any plugins that need version bumps for ESLint v10 compat
-
Run ESLint and compare against baseline:
cd /projects/Charon && npm run lint 2>&1 | tee /tmp/eslint-v10-output.log diff /tmp/eslint-v9-baseline.log /tmp/eslint-v10-output.log -
Address new violations from updated
eslint:recommended:no-unassigned-vars— variables declared but never assignedno-useless-assignment— assignments that are immediately overwrittenpreserve-caught-error— catch clause variables that are declared but unused
-
Remove any
/* eslint-env */comments found in Phase 1 -
Update
lefthook.yml— remove the ESLint v9 pin note -
Run full test suite to confirm no regressions
Phase 4: Integration Testing
-
Full lint + type-check:
cd /projects/Charon && npm run lint && cd frontend && npx tsc --noEmit -
Frontend build:
cd frontend && npx vite build -
Unit tests:
cd frontend && npx vitest run -
Playwright E2E tests (all browsers):
npx playwright test --project=chromium npx playwright test --project=firefox npx playwright test --project=webkit -
Docker build verification:
docker build -t charon:upgrade-test .
Phase 5: Vite 8 (Deferred)
Action: No implementation. Monitor only.
- Subscribe to Vite releases:
https://github.com/vitejs/vite/releases - When Vite 8 is announced, create a new plan with breaking changes analysis
- Key areas to watch: Node.js minimum, browser target defaults, plugin API, Vitest compat, Rolldown integration
9. Rollback Strategy
TypeScript 6.0 Rollback (PR-1)
-
Revert
package.jsonchanges (both root and frontend):- "typescript": "^6.0.0" + "typescript": "^5.9.3" -
Revert
tsconfig.jsonchanges (remove"types": [], restore"DOM.Iterable") -
Run
npm installto restore lock file -
Verify:
cd frontend && npx tsc --noEmit && npx vitest run
Risk: Low — TypeScript version is a devDependency only. No runtime impact. git revert of the PR commit is sufficient.
ESLint v10 Rollback (PR-2)
-
Revert
package.jsonchanges:- "eslint": "^10.0.0" + "eslint": "^9.39.3 <10.0.0" - "@eslint/js": "^10.0.0" + "@eslint/js": "^9.39.3 <10.0.0" -
Revert any plugin version bumps
-
Revert
lefthook.ymlcomment change -
Run
npm installto restore lock file -
Verify:
cd /projects/Charon && npm run lint
Risk: Low — ESLint is a devDependency only. Code changes (fixing new rule violations) are harmless to keep even if ESLint is rolled back.
Vite 8 Rollback
N/A — no upgrade to perform.
10. Testing Strategy
Automated Test Coverage
| Test Layer | Tool | What It Validates |
|---|---|---|
| Type checking | tsc --noEmit |
TS 6.0 compatibility, tsconfig changes |
| Linting | eslint |
ESLint v10 config + plugin compat |
| Unit tests | vitest run |
No runtime regressions from TS changes |
| E2E tests | Playwright (Chromium, Firefox, WebKit) | Full app build + functionality |
| Docker build | docker build |
Dockerfile still works with new deps |
| Pre-commit hooks | lefthook |
All hooks pass with new versions |
Specific Test Scenarios for TS 6.0
-
Build output verification:
cd frontend && npx vite build # Verify dist/ output is correct, no new warnings -
Type-check with
--stableTypeOrdering(prep for TS 7.0):cd frontend && npx tsc --noEmit --stableTypeOrdering # Note any differences — these will be real in TS 7.0 -
Verify no
@typesresolution issues:# With types: [], ensure no global type errors appear cd frontend && npx tsc --noEmit 2>&1 | grep "Cannot find"
Specific Test Scenarios for ESLint v10
-
Verify all 18 plugins load without errors:
cd /projects/Charon && npx eslint --print-config frontend/src/App.tsx | head -20 -
Count new violations vs baseline:
npx eslint frontend/src/ --format json 2>/dev/null | jq '.[] | .errorCount' | paste -sd+ | bc -
Verify config lookup works correctly in monorepo:
# Lint a file from the root — should find root eslint.config.js npx eslint frontend/src/App.tsx
11. Commit Slicing Strategy
Decision: 2 Independent PRs + 1 Deferred
Trigger reasons:
- Cross-domain changes (TS and ESLint are independent tools)
- Risk isolation (if one breaks, the other can still merge)
- Review size (each PR is focused and reviewable)
- Plugin compatibility gate (ESLint v10 may be blocked)
PR-1: TypeScript 6.0 Upgrade
| Attribute | Detail |
|---|---|
| Scope | TypeScript ^5.9.3 → ^6.0.0, tsconfig changes, fix type errors |
| Files | package.json (root), frontend/package.json, package-lock.json, frontend/tsconfig.json, frontend/tsconfig.node.json, possibly source files with type fixes |
| Dependencies | None — can start immediately |
| Validation Gate | tsc --noEmit passes, vitest run passes, vite build succeeds, Docker build succeeds |
| Estimated Complexity | Medium — mostly defaults are already correct, types: [] is the main change |
| Rollback | git revert + npm install |
PR-2: ESLint v10 Upgrade
| Attribute | Detail |
|---|---|
| Scope | ESLint ^9.x → ^10.0.0, plugin updates, fix new violations, update lefthook |
| Files | frontend/package.json, package-lock.json, frontend/eslint.config.js (if needed), lefthook.yml, source files with new violations |
| Dependencies | BLOCKED until eslint-plugin-react-hooks declares ESLint v10 support |
| Validation Gate | npm run lint passes, all plugins load, no new unhandled violations |
| Estimated Complexity | Medium — depends on plugin ecosystem readiness |
| Rollback | git revert + npm install |
PR-3: Vite 8 (Deferred)
| Attribute | Detail |
|---|---|
| Scope | N/A — Vite 8 does not exist |
| Dependencies | Vite 8 release |
| Action | Monitor https://github.com/vitejs/vite/releases |
Contingency
- If TS 6.0 stable is delayed past RC, pin to
typescript@6.0.0-rctemporarily - If ESLint v10 plugin compat is blocked for >30 days, consider temporarily dropping the blocker plugin or using
--rulesdirworkaround - If a plugin is permanently abandoned, research replacement plugins
12. Known Issues & Gotchas
ESLint v10
-
react-hooks plugin blocker —
lefthook.ymlexplicitly states the upgrade is blocked untileslint-plugin-react-hookssupports v10. This is the #1 risk. -
Config file lookup change — ESLint v10 finds config files starting from the linted file and walking up. In Charon's monorepo setup (root
eslint.config.jsimportsfrontend/eslint.config.js), verify the root config is still discovered when lintingfrontend/src/**. -
Jiti dependency — ESLint v10 requires
jiti >= v2.2.0for loading config files. This is typically a transitive dependency but may need explicit installation if conflicts arise. -
Plugin API breakage — Plugins that use deprecated
context.getScope(),context.getAncestors(),context.parserOptions, orcontext.parserPathwill break. All 18 plugins must be verified.
TypeScript 6.0
-
types: []default — This is the highest-impact change for Charon. Without explicitly setting"types", TS 6.0 will not auto-load any@types/*packages. Since Charon usesnoEmit: trueand explicit imports, this should be fine, but test thoroughly. -
TS 6.0 is a transition release — It is explicitly designed as a bridge to TS 7.0 (native Go port). Adopting TS 6.0 now prepares us for TS 7.0 later. The
ignoreDeprecations: "6.0"escape hatch exists if needed. -
typescript-eslintcompatibility — Iftypescript-eslint@8.57.0doesn't support TS 6.0, we may need to update it. Check for a release that adds TS 6.0 support. -
knipcompatibility —knip(^5.86.0) uses TS programmatic API internally. Verify it works with TS 6.0. -
ArrayBuffer/Buffer types — TS 5.9 changes to
lib.d.tsaroundArrayBuffernot being a supertype ofTypedArraymay surface with TS 6.0. Ensure@types/nodeis at latest. -
ts5to6migration tool — The experimental ts5to6 tool can automatically adjustbaseUrlandrootDir. Charon doesn't usebaseUrl, so this is of limited value, but worth knowing about.
Vite 8
-
Does not exist — No action possible. The latest major is Vite 7.
-
Rolldown integration — Vite 7 introduced
rolldown-viteas an alternative bundler. Vite 8 may make Rolldown the default. Monitor this. -
inlineDynamicImports: trueworkaround —frontend/vite.config.tshas aTEMPORARYcomment oninlineDynamicImports: truefor a "React init issue". This should be investigated independently regardless of any Vite upgrade.
13. Risk Assessment
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
eslint-plugin-react-hooks doesn't support ESLint v10 |
Medium | High — blocks PR-2 entirely | Monitor npm for updates; check GitHub issues |
| Other ESLint plugins break on v10 | Low | Medium — individual plugins can be disabled | Verify all 18 plugins; have disable config ready |
TS 6.0 types: [] causes unexpected errors |
Medium | Low — easy to fix by adding types | Test with tsc --noEmit; add specific types |
typescript-eslint incompatible with TS 6.0 |
Low | Medium — blocks type-aware linting | Check releases; may need to update |
knip breaks with TS 6.0 |
Low | Low — knip is optional tooling |
Test separately; pin if needed |
| TS 6.0 stable delayed | Low | Low — RC already available | Use RC or pin beta |
| Vite 8 released with breaking changes | Unknown | Unknown | Create new plan when announced |
| Docker build fails after upgrades | Low | Medium — blocks CI/deployment | Test Docker build in PR CI |
| Playwright E2E failures from TS changes | Very Low | High — blocks merge | Run full E2E suite before merge |
Overall Risk: MEDIUM
- TypeScript 6.0 is well-characterized and Charon's tsconfig is well-aligned with the new defaults
- ESLint v10 is dependent on ecosystem readiness (plugin compatibility)
- Vite 8 is a non-issue (doesn't exist)
Acceptance Criteria
PR-1 (TypeScript 6.0)
typescriptupgraded to^6.0.0in root and frontendpackage.jsontsconfig.jsonupdated withtypes: []and simplifiedlibtsc --noEmitpasses with zero errorsvitest runpasses all testsvite buildproduces correct output- Docker build succeeds
- No new
ignoreDeprecationsusage (clean upgrade)
PR-2 (ESLint v10)
- Plugin compatibility verified for all 18 plugins
eslintand@eslint/jsupgraded to^10.0.0- Version cap (
<10.0.0) removed from both packages npm run lintpasses (new violations fixed)lefthook.ymlpin note removed/updated- All pre-commit hooks pass
PR-3 (Vite 8)
- Monitoring established for Vite releases
- Plan will be recreated when Vite 8 is announced