Skip to content

chore(deps): upgrade Next apps and TypeScript 6#5111

Draft
rschlaefli wants to merge 21 commits into
v3from
codex/next-16-upgrade
Draft

chore(deps): upgrade Next apps and TypeScript 6#5111
rschlaefli wants to merge 21 commits into
v3from
codex/next-16-upgrade

Conversation

@rschlaefli

@rschlaefli rschlaefli commented Jun 1, 2026

Copy link
Copy Markdown
Member

What This Adds

This PR upgrades the KlickerUZH frontend/runtime dependency baseline and then migrates the repo compiler baseline to TypeScript 6.

  1. Moves the five Next apps to Next 16.2.6, React 19.2.6, and policy-compliant next-intl@4.12.0.
  2. Keeps the PWA apps on the webpack path with @ducanh2912/next-pwa@10.2.9; Turbopack is deliberately deferred.
  3. Applies the required Next 16 migrations: middleware.ts -> proxy.ts, direct ESLint scripts instead of next lint, explicit image qualities, and remotePatterns.
  4. Adds supporting Rollup, Vitest, React Email, and direct security/maintenance bumps needed to keep builds and tests green after the framework upgrade.
  5. Stabilizes the upgraded E2E suite with Cypress-only helpers for Slate rich-text typing, Sonner toast dismissal, activity edit completion waits, manage login redirects, and local KaTeX CSS imports.
  6. Adds audit-remediation overrides for high-severity dependency ranges reported by pnpm audit --audit-level high.
  7. Migrates the workspace from TypeScript ~5.6.3 to ~6.0.3 and @types/node to the Node 24 line ^24.12.4.
  8. Updates the Office add-in TypeScript/ESLint lint tooling to TS6-compatible versions.
  9. Aligns repo tsconfigs with TS6 defaults and deprecations while keeping GraphQL/Pothos/Yoga on the current major stack.
  10. Fixes the TS6 Prisma/Pothos generated-type boundary without a broad GraphQL dependency upgrade.
  11. Adds the follow-up Capacitor mobile app plan for native app-store delivery, native push, and offline downloaded practice.

How It Works

  • Next app dev and build scripts use --webpack so the existing custom webpack condition handling and Workbox/PWA integration remain in place.
  • packages/next-config centralizes Next 16 image settings and only allows local-IP image optimization in development/test, not staging.
  • Vitest 4 configs replace the removed poolOptions.forks.singleFork shape with maxWorkers: 1 while preserving test-file isolation.
  • Rollup non-watch build scripts use --forceExit because Rollup 4.59 plus the TypeScript plugin keeps TypeScript filesystem watchers alive after successful one-shot builds.
  • Backend migration files import the generated GraphQL type surface from dist to avoid pulling both GraphQL src and dist PrismaJson globals into backend typechecking.
  • TS6 config cleanup removes deprecated baseUrl where the existing paths map can be made explicit, raises old ES5 frontend targets to ES2015, and uses ignoreDeprecations: "6.0" only for the Docusaurus inherited-config gap.
  • Prisma and GraphQL pure typechecks use tsconfig.check.json to disable declaration/composite emit during tsc --noEmit.
  • packages/prisma/scripts/patchPrismaNamespace.mjs runs after prisma generate and adds public runtime.ObjectEnumValue annotations to generated Prisma null sentinel exports so Prisma 6 declarations emit under TS6.
  • packages/prisma/src/client.ts now explicitly exports the generated Pothos PrismaTypes type, and packages/graphql/src/builder.ts imports that type instead of relying on ambient visibility.
  • PWA/manage rank SVG imports use relative public asset module paths so Next 16/webpack resolves them during production builds.
  • project/2026-06-07-capacitor-mobile-app-plan.md records the separate mobile-app follow-up strategy without changing runtime code in this PR.

Important Details

  • This PR now includes TypeScript 6. The migration is kept as a separate documented slice inside the same PR because the user accepted landing it here after the Next 16 work.
  • This PR does not enable Turbopack. The PWA plugin and shared webpack customization need a dedicated follow-up migration.
  • This PR does not perform a large GraphQL stack modernization. GraphQL/Pothos/Codegen are intentionally kept on the current major line because GraphQL is planned to be replaced by tRPC.
  • The Capacitor/mobile plan is documentation for a future branch; it does not upgrade Capacitor or change app-store/native runtime behavior here.
  • next-intl@4.13.0 was skipped because it was published less than 14 days before 2026-06-01. 4.12.0 is the selected policy-compliant Next 16 bridge.
  • tmp@0.2.6 has an exact minimumReleaseAgeExclude because it was published on 2026-05-26 and is needed for the audit remediation.
  • The advisory patch versions jsonwebtoken@8.5.2 and lodash@4.17.24 are not published, so the overrides use jsonwebtoken@9.0.3 and lodash@4.18.1.
  • pnpm-workspace.yaml also overrides high-advisory ranges for Apollo Server, defu, effect, fast-xml-parser, flatted, immutable, jws, minimatch, node-forge, path-to-regexp, picomatch, sequelize, serialize-javascript, socket.io-parser, svgo, tar, tmp, underscore, undici, validator, vite, and the stale TS peer for prisma-json-types-generator@3.6.0.
  • Local live-quiz Cypress flows depend on apps/response-api on port 7078; pending /AddResponse requests indicate response-api needs to be verified/restarted before debugging PWA rendering.

Branch Coverage

  • Base: v3
  • Head: 84778e48b
  • Reviewed: 19 commits from bf5d081b0 through 84778e48b.
  • Diff: 171 files changed, 11884 insertions, 8791 deletions.
  • Covered: Next 16/React/package/lockfile changes, Next proxy and ESLint migrations, shared Next image configuration, webpack/PWA build path, Rollup/Vitest compatibility fixes, GraphQL Vitest alias fix, backend migration type import fix, Cypress E2E stabilization, validation report, browser screenshot evidence, high-advisory dependency override remediation, manage login redirect stabilization, local KaTeX CSS, live-quiz Cypress environment notes, external audit completion evidence, TypeScript 6 dependency/config migration, Prisma generated declaration patching, TS6 build/audit verification, and the Capacitor mobile app follow-up plan.

Commits:

  • bf5d081b0 docs(project): add next 16 upgrade plan
  • 74e1415f9 chore(deps): upgrade next apps to next 16
  • 1dbf6ef4b fix(next): resolve next 16 compatibility issues
  • f21e78da9 fix(next): restrict local image optimization to dev
  • 616940d8a docs(project): report next 16 upgrade findings
  • ca1aab4b1 docs(project): add next 16 browser evidence
  • dde327957 docs(project): update next 16 validation blockers
  • c24ccc1f3 fix(test): restore graphql vitest source alias
  • 6667f0cf7 test(next): stabilize next 16 e2e validation
  • 1d723a687 docs(project): update next 16 validation status
  • f5bd782ba docs(project): record playwright browser diagnosis
  • fc4a33583 fix(deps): remediate high audit findings
  • 86c54a2e1 fix(frontend): stabilize next 16 redirects and e2e
  • 7320867dd docs(project): record next 16 audit completion
  • 3ebddb7a8 docs(project): add TypeScript 6 migration plan
  • 39e6f164e chore(deps): migrate to TypeScript 6
  • d0d14a998 fix(frontend): resolve rank asset imports
  • 376de8eb2 docs(project): record TypeScript 6 migration completion
  • 84778e48b docs(project): add Capacitor mobile app plan

Screenshots

Built-app smoke screenshots are committed under project/2026-06-01-next-16-screenshots/:

Auth smoke
PWA smoke
Manage smoke
Control smoke
Chat smoke

Real local production-style test-stack screenshots were captured with npx agent-browser:

PWA login
PWA home
Auth delegated-login
Manage library
Control course selection

Browser verification was not rerun for the TS6 import-path-only rank SVG cleanup because no local PWA/manage/Traefik routes were running on ports 3001/3002 or *.klicker.com. The affected PWA/manage production builds were rerun and passed.

Review Notes

Pay particular attention to:

  • packages/next-config/index.js, especially image optimizer settings and remotePatterns.
  • PWA app build scripts and service-worker outputs.
  • Rollup --forceExit placement: it is intentionally limited to non-watch build scripts.
  • Vitest config migration in apps/chat, apps/olat-api, packages/grading, packages/graphql, and packages/util.
  • Cypress typeRichText usage in the element/activity specs; it is test-only and preserves literal braces via parseSpecialCharSequences: false.
  • Dependency overrides in pnpm-workspace.yaml, especially the major-version overrides for transitive vulnerable packages where no patched version exists in the old major line.
  • Manage /login server-side redirect handling and the Apollo/Layout unauthorized redirect paths.
  • packages/prisma/scripts/patchPrismaNamespace.mjs; it is intentionally narrow and fails closed if Prisma changes the generated null sentinel output.
  • packages/graphql/tsconfig.check.json and packages/prisma/tsconfig.check.json; they keep pure tsc --noEmit checks separate from declaration-producing Rollup builds.

Security Review

  • Final local security review on 2026-06-03 found no new high-confidence exploitable issue in the validation fixes or TS6 migration.
  • The shared Next image optimizer config keeps local-IP image optimization restricted to development/test.
  • Manage login redirects now fail closed to the configured manage origin before forwarding to auth.
  • The TS6 slice adds no new runtime auth, redirect, secret handling, network, or request parsing surface.
  • Secret-pattern scan across the new TS6 plan/patch files found no secret-like strings.
  • patchPrismaNamespace.mjs only mutates generated local Prisma TypeScript source after prisma generate; it does not execute generated runtime data or read external input.
  • pnpm audit --audit-level high ran after explicit user approval on 2026-06-03 before remediation and failed with 115 total advisories: 13 low, 56 moderate, 46 high, 0 critical.
  • The high-advisory dependency ranges from that audit were remediated through explicit overrides. A local lockfile range check after pnpm install --no-frozen-lockfile found no installed versions matching the checked high-advisory ranges.
  • The approved post-remediation and post-TS6 external pnpm audit --audit-level high reruns exited 0 with 48 remaining advisories below the requested threshold: 9 low and 39 moderate.

Verification

Passed locally before the audit-remediation commit:

  • CI=true pnpm install --frozen-lockfile
  • pnpm run check:syncpack
  • pnpm --filter @klicker-uzh/prisma generate
  • pnpm --filter @klicker-uzh/prisma build
  • pnpm --filter @klicker-uzh/prisma build:test
  • pnpm --filter @klicker-uzh/backend-docker check
  • pnpm run check
  • pnpm run lint
  • pnpm run build
  • pnpm run build:test
  • pnpm --filter @klicker-uzh/cypress exec tsc --noEmit
  • pnpm --filter @klicker-uzh/util test -> 46 tests passed
  • pnpm --filter @klicker-uzh/grading test -> 10 tests passed
  • pnpm --filter @klicker-uzh/chat test:run -> 40 tests passed
  • pnpm --filter @klicker-uzh/office-addin build:office
  • git diff --check

Passed locally after audit remediation:

  • pnpm install --no-frozen-lockfile
  • CI=true pnpm install --frozen-lockfile
  • Local lockfile high-advisory range check -> no installed versions matched the checked high-advisory ranges
  • pnpm run check:syncpack
  • pnpm run check
  • pnpm run lint
  • pnpm run build
  • pnpm --filter @klicker-uzh/util test -> 46 tests passed
  • pnpm --filter @klicker-uzh/grading test -> 10 tests passed
  • pnpm --filter @klicker-uzh/chat test:run -> 40 tests passed
  • pnpm --filter @klicker-uzh/cypress exec tsc --noEmit
  • pnpm exec prettier --check pnpm-workspace.yaml pnpm-lock.yaml project/2026-06-01-next-16-upgrade-plan.md project/2026-06-01-next-16-upgrade-report.md
  • git diff --check
  • Commit hook for fc4a33583: check, lint, staged Prettier, syncpack
  • Pre-push build hook for fc4a33583

Passed locally after the redirect/Cypress stabilization commit 86c54a2e1:

  • pnpm --filter @klicker-uzh/frontend-manage check
  • pnpm --filter @klicker-uzh/frontend-pwa check
  • pnpm --filter @klicker-uzh/frontend-manage lint -> pass with pre-existing hook warnings only
  • pnpm --filter @klicker-uzh/frontend-pwa lint -> pass with pre-existing hook warnings only
  • pnpm --store-dir /Users/roland/Library/pnpm/store/v11 install --frozen-lockfile
  • pnpm run check:syncpack
  • pnpm run check
  • pnpm run lint
  • pnpm exec prettier --check AGENTS.md apps/frontend-manage/package.json apps/frontend-manage/src/components/Layout.tsx apps/frontend-manage/src/lib/apollo.ts apps/frontend-manage/src/pages/_app.tsx apps/frontend-manage/src/pages/_document.tsx apps/frontend-manage/src/pages/login.tsx apps/frontend-pwa/package.json apps/frontend-pwa/src/pages/_app.tsx apps/frontend-pwa/src/pages/_document.tsx cypress/cypress/e2e/MB-instance-updates-workflow.cy.ts pnpm-lock.yaml
  • git diff --check
  • Commit hook for 86c54a2e1: check, lint, staged Prettier, syncpack
  • Pre-push build hook for 86c54a2e1: pnpm run build -> pass

Passed locally after the final Next 16 audit completion commit 7320867dd:

  • pnpm audit --audit-level high -> pass at the high threshold; 48 advisories remain below threshold (9 low, 39 moderate)
  • pnpm exec prettier --check project/2026-06-01-next-16-upgrade-plan.md project/2026-06-01-next-16-upgrade-report.md
  • git diff --check
  • Commit hook for 7320867dd: check, lint, staged Prettier, syncpack
  • Pre-push build hook for 7320867dd: pnpm run build -> pass

Passed locally for the TypeScript 6 slice:

  • pnpm install
  • pnpm install --frozen-lockfile
  • pnpm run check:syncpack
  • pnpm peers check -> failed only on pre-existing non-TS peer mismatches; TS-specific peer failures removed
  • pnpm --filter @klicker-uzh/frontend-pwa check
  • pnpm --filter @klicker-uzh/frontend-manage check
  • pnpm --filter @klicker-uzh/frontend-control check
  • pnpm --filter @klicker-uzh/office-addin check
  • pnpm --filter @klicker-uzh/graphql check
  • pnpm --filter @klicker-uzh/prisma check
  • pnpm --filter @klicker-uzh/backend-docker check
  • pnpm --filter @klicker-uzh/prisma build
  • pnpm run check
  • pnpm run lint
  • pnpm --filter @klicker-uzh/frontend-pwa build
  • pnpm --filter @klicker-uzh/frontend-manage build
  • pnpm -w build -> 19/19 tasks successful
  • pnpm audit --audit-level high -> pass at the high threshold; 48 advisories remain below threshold (9 low, 39 moderate)
  • pnpm exec prettier --check apps/frontend-manage/src/components/evaluation/ActivityEvaluation.tsx apps/frontend-pwa/src/components/course/SuspendedGroupView.tsx apps/frontend-pwa/src/pages/course/[courseId]/index.tsx project/2026-06-03-pr-5111-typescript-6-migration-plan.md
  • git diff --check 7320867dd..HEAD
  • Commit hook for 39e6f164e: check, staged-file Prettier, lint, syncpack
  • Commit hook for d0d14a998: check, staged-file Prettier, lint, syncpack
  • Commit hook for 376de8eb2: check, staged-file Prettier, lint, syncpack
  • Pre-push build hook for 376de8eb2: pnpm run build -> 19/19 tasks successful

Passed locally for the docs-only Capacitor plan commit:

  • pnpm exec prettier --check project/2026-06-07-capacitor-mobile-app-plan.md
  • git diff --cached --check
  • Commit hook for 84778e48b: check, staged-file Prettier, lint, syncpack
  • Pre-push build hook for 84778e48b: pnpm run build -> 19/19 tasks successful from cache

Build verification for changed apps:

  • APP_ORIGIN_* ... pnpm --filter @klicker-uzh/frontend-manage build:test -> pass
  • APP_ORIGIN_* ... pnpm --filter @klicker-uzh/frontend-pwa build:test -> pass
  • Known warnings remained: next-intl App Router migration warning, large page data warnings, and existing missing-message warnings.

E2E/browser verification:

  • Focused Cypress D/H/I/O reruns passed after the rich-text and toast helper fixes.
  • CYPRESS_FAIL_FAST=false ... pnpm --filter @klicker-uzh/cypress exec cypress run --spec cypress/e2e/A-login-workflow.cy.ts -> 7/7 passing after the login redirect and local KaTeX CSS fixes.
  • Raw Cypress production-style coverage was completed in partitions after restoring the local stack:
    • First raw run passed specs 0-baseline through L-elements-case-study; it later failed when backend port 3000 was down.
    • MA-elements-operations-workflow.cy.ts rerun after backend restart -> 71/71 passing.
    • Remaining batch MB through X passed all non-live-quiz/non-MB specs: N, P, Q, R, S, T, U, W, X.
    • O-live-quiz-workflow.cy.ts + V-template-workflow.cy.ts rerun after response-api restart -> 111/111 passing.
    • MB-instance-updates-workflow.cy.ts rerun after the save-completion wait patch -> 6/6 passing.
  • Playwright Chromium login smoke passed after a clean DB reset and seed: PLAYWRIGHT_BASE_URL=http://127.0.0.1:3001 ... playwright test --project=chromium -> 1 passed. Firefox/WebKit coverage was not required for this PR after Chromium was accepted as sufficient.
  • npx agent-browser verified PWA login/home, auth delegated-login, manage library, and control course selection against the real local test stack.

GitHub for prior Next 16 head 7320867dd:

GitHub for TS6 head 376de8eb2:

GitHub for current docs-only head 84778e48b:

  • GitGuardian Security Checks -> pass
  • CodeQL analysis jobs for Java/Kotlin, JavaScript/TypeScript, and Python -> pass

Remaining Follow-Up

  • Triage the remaining low/moderate pnpm audit advisories in a dedicated security dependency slice if they are in production-relevant paths.
  • Keep Turbopack and PWA modernization or replacement as separate follow-up work.
  • Use project/2026-06-07-capacitor-mobile-app-plan.md as the starting point for a separate Capacitor/native app-store branch.
  • Clean up Pages Router next-intl warnings, stale Browserslist/caniuse-lite warnings, and GraphQL Rollup TS warning noise after the main framework/compiler upgrade is merged.

ClickUp Links

This was generated by AI during triage.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9e98c3a8-0219-4822-8bdf-8c8b6787bc61

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 1, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

Safe to merge with the redirect-cookie lifetime fix applied first — the rest of the upgrade is well-structured and verified.

The auth proxy sets redirect cookies with maxAge: REDIRECT_COOKIE_TTL_MS (= 10 000) where the HTTP Max-Age attribute is measured in seconds, not milliseconds. The cookies survive ~2.77 hours instead of the intended 10 seconds, widening the window where a stale or replayed redirect cookie can influence the callback flow. This issue was raised in the previous review round and remains unaddressed in the current head commit.

apps/auth/src/proxy.ts — the REDIRECT_COOKIE_TTL_MS constant and every maxAge usage site need to be reconciled (rename to seconds or divide at call sites).

Important Files Changed

Filename Overview
apps/auth/src/proxy.ts New Next 16 proxy (replaces middleware.ts); contains an unaddressed P1 — REDIRECT_COOKIE_TTL_MS=10000 is used directly as HTTP Max-Age (seconds), making cookies live ~2.77 hours instead of 10 s, plus production console.log that exposes full URLs and referer headers.
apps/frontend-manage/src/pages/login.tsx Converted from client-side useEffect redirect to getServerSideProps with server-side redirect; origin validation correctly prevents open redirect.
apps/frontend-manage/src/lib/apollo.ts Replaced Router.push with window.location.assign and a module-level de-dup flag; safe because assign triggers a full page reload that resets the flag.
apps/frontend-manage/src/components/Layout.tsx Moved render-time router.push to useEffect with a derived boolean; correct fix for Next 16's stricter render-phase side-effect checks.
packages/next-config/index.js Centralised image config with dangerouslyAllowLocalIP gated to dev/test, remotePatterns replaces deprecated domains, getHostname helper correctly extracts hostname from full URL or falls back to raw value.
pnpm-workspace.yaml ~20 new high-advisory overrides; notable major-version jump for jsonwebtoken (8.x → 9.x) and lodash (4.17.x → 4.18.1) where no patched minor existed — acknowledged in PR description but could silently break transitive consumers using the callback API.
apps/chat/src/proxy.ts New Next 16 proxy for chat app; JWT verification via jose, frame-ancestors CSP applied on all responses, correct pass-through for static/API paths.
packages/graphql/vitest.config.ts Migrated poolOptions.forks.singleFork to maxWorkers:1 for Vitest 4; added explicit src alias so package-local base-url imports resolve correctly in CI.
cypress/cypress/support/commands.ts Added typeRichText and dismissToasts Cypress commands; typeRichText correctly disables parseSpecialCharSequences to preserve literal braces in Slate editor input.
cypress/cypress/e2e/MB-instance-updates-workflow.cy.ts Replaced bare click + cy.wait(1000) with saveActivityEditAndOpenOverview helper that waits for the overview button to be visible before clicking, eliminating a timing race.

Sequence Diagram

sequenceDiagram
    participant B as Browser
    participant M as Manage (Next 16)
    participant L as /login (GSP)
    participant A as Auth proxy.ts
    participant N as NextAuth

    B->>M: GET /some-page
    M->>M: Apollo query (cache-and-network)
    alt Session expired — Apollo error
        M->>M: "onError: message==Unauthorized"
        M->>M: redirectToLogin() [module-level dedup]
        M->>B: "window.location.assign(/login?expired=true&redirect_to=/some-page)"
    else "Layout: !dataUser && !loadingUser"
        M->>M: "useEffect: redirectToLogin = true"
        M->>B: "window.location.assign(/login?expired=true&redirect_to=/some-page)"
    end

    B->>L: "GET /login?redirect_to=/some-page"
    Note over L: getServerSideProps validates origin
    L-->>B: "307 to auth.host?redirectTo=https://manage.host/some-page"

    B->>A: "GET / ?redirectTo=https://manage.host/some-page"
    A->>A: isValidLecturerRedirectUrl(redirectTo) check passes
    A->>A: "Set LECTURER_REDIRECT_COOKIE (maxAge=REDIRECT_COOKIE_TTL_MS)"
    A->>B: NextResponse.next() show auth UI

    B->>N: "POST /api/auth/signin?callbackUrl=..."
    A->>A: /api/auth/signin: set cookie with callbackUrl
    B->>N: GET /api/auth/callback/...
    A->>A: /api/auth/callback: read cookie inject callbackUrl param
    A->>A: clearAllRedirectCookies()
    N-->>B: 302 to manage.host/some-page
Loading

Fix All in Codex Fix All in Claude Code

Reviews (9): Last reviewed commit: "docs(project): record next 16 audit comp..." | Re-trigger Greptile

@rschlaefli rschlaefli changed the title chore(deps): upgrade Next apps to Next 16 chore(deps): upgrade Next apps and TypeScript 6 Jun 3, 2026
Base automatically changed from codex/dependency-refresh-lts to v3 June 18, 2026 05:20
@greptile-apps

greptile-apps Bot commented Jun 18, 2026

Copy link
Copy Markdown

Too many files changed for review. (172 files found, 100 file limit)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant