Skip to content

[Backport] Fixes to support TypeScript 7 - #95831

Merged
lukesandberg merged 4 commits into
next-16-2from
backport-ts7-fixes-next-16-2
Jul 23, 2026
Merged

[Backport] Fixes to support TypeScript 7#95831
lukesandberg merged 4 commits into
next-16-2from
backport-ts7-fixes-next-16-2

Conversation

@lukesandberg

@lukesandberg lukesandberg commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Backports the TypeScript 7 support fixes to the 16.2.x release line to resolve #95801, where next build crashes with a silent SIGSEGV/SIGABRT when typescript@7 is installed (the legacy TypeScript JavaScript API is unavailable in TS7).

Cherry-picks the following, in order:

Together these add the opt-in experimental.useTypeScriptCli backend (runs the project-local tsc during next build, supporting TS7), preserve the TypeScript API backend as the default with actionable TS7 migration guidance instead of a crash, and fix worker termination and CLI spinner handling.

Prerequisite: #92277

The TypeScript CLI backend tests exercise a paths alias that is inherited from an extended tsconfig and defined without a baseUrl. Resolving that alias in the webpack builder relies on the load-jsconfig.ts change from #92277 (compute the effective base URL from pathsBasePath), which had not been backported to next-16-2. Only the source change from #92277 is included here — its test reorganization is not.

Test changes

The test/production/ci-missing-typescript-deps and test/production/next-server-nft suites were converted from createNext to nextTestSetup on canary in #93799, which was never backported to next-16-2. Because #95639's test diffs were authored against that refactored shape, the ci-missing-typescript-deps suite is adapted back to this branch's existing createNext / try‑finally style rather than pulling in the #93799 refactor.

Fixes

Fixes #95801

Verification

Automated (both bundlers):

  • pnpm --filter=next build
  • pnpm test-start-turbo and pnpm test-start-webpack for:
    • test/production/app-dir/typescript-cli/typescript-cli.test.ts
    • test/production/ci-missing-typescript-deps/index.test.ts
  • Unit: runTypeScriptCli.test.ts, test/unit/typescript-cli-config-origin/index.test.ts

Against a typescript@7.0.2 reproduction project, next build no longer crashes with an error about how "id" should be a string`. It now exits cleanly with actionable guidance:

▲ Next.js 16.2.10 (Turbopack)

  Creating an optimized production build ...
✓ Compiled successfully in 785ms
  Running TypeScript  .TypeScript 7.0.2 does not provide the compiler API required by Next.js. Enable experimental.useTypeScriptCli in your Next.js config to use the TypeScript CLI, or install TypeScript 6 instead.
Next.js build worker exited with code: 1 and signal: null

The same clean error is produced under CI=1 (previously the crash path). Enabling the new opt-in:

experimental: {
  useTypeScriptCli: true,
},

makes the build succeed with TypeScript 7 installed.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Tests Passed

Commit: 273a85a

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Stats skipped

Commit: 273a85a
View workflow run

lukesandberg and others added 4 commits July 23, 2026 12:47
….baseUrl` (#92277)

Backport the load-jsconfig source fix from #92277 so path aliases defined
via `paths` (without `baseUrl`, e.g. inherited from an extended tsconfig)
resolve correctly in webpack. Required by the TypeScript CLI backend tests
which use an inherited `@fixture/*` path alias.

(cherry picked from commit ba33b4e)
## Summary

- add `experimental.useTypeScriptCli` so projects can explicitly run
their local `tsc` during `next build`, including TypeScript 7 while the
legacy JavaScript API is unavailable
- preserve the TypeScript API backend as the default, with TypeScript
6-compatible dependency installation and actionable TypeScript 7
migration guidance
- load effective compiler metadata through `tsc --showConfig`, preserve
inherited path origins, stream native diagnostics, redirect incremental
state, and forward worker termination to the compiler process tree
- document the experimental behavior and cover TypeScript 6/7, both
bundlers, raw diagnostics, full-project checking, dependency selection,
and cleanup

## Demo

```
pnpm build

> cna@0.1.0 build /Users/timneutkens/projects/sandbox/cna
> next build

▲ Next.js 16.3.0-canary.81 (Turbopack)
✓ Running next.config.ts took 23ms
- Cache Components enabled
- Experiments (use with caution):
  ✓ useTypeScriptCli

  Creating an optimized production build ...
✓ Compiled successfully in 3.9s
  Running TypeScript ...
app/page.tsx:8:3 - error TS2322: Type 'string' is not assignable to type 'number'.

8   return count++ + "abc";
    ~~~~~~

Found 1 error in app/page.tsx:8

Failed to type check.

Next.js build worker exited with code: 1 and signal: null
 ELIFECYCLE  Command failed with exit code 1.
```

## Verification

- `pnpm test-start-turbo
test/production/app-dir/typescript-cli/typescript-cli.test.ts`
- `pnpm test-start-webpack
test/production/app-dir/typescript-cli/typescript-cli.test.ts`
- `pnpm test-start-turbo
test/production/ci-missing-typescript-deps/index.test.ts`
- `pnpm test-dev-turbo
test/development/typescript-native-preview/index.test.ts`
- `pnpm test-start-turbo test/production/typescript-basic/index.test.ts`

<!-- NEXT_JS_LLM_PR -->

(cherry picked from commit a249dcb)
## Follow-ups for the experimental TypeScript CLI checker

Two independent improvements to the `experimental.useTypeScriptCli`
build path.

### 1. Make `tsc` responsive to interruption

When `next build` is interrupted (Ctrl-C / `SIGTERM`), the TypeScript 7
native compiler could keep running to completion instead of stopping —
leaving a CPU-heavy process alive after the build was abandoned.

The teardown already handled termination signals and killed the whole
process group; the problem was the signal it sent. The native compiler
ignores `SIGTERM`/`SIGINT`, so the graceful signal never stopped it. We
now escalate to `SIGKILL` (Windows: `taskkill /T /F`), which reaps the
compiler on interrupt (measured ~200ms vs. running to completion).

The compiler's signal handling may be improved upstream — see
[microsoft/typescript-go#4592](microsoft/typescript-go#4592),
which threads an interruption `context` through `tsc build`. That work
is still in progress; until it lands and ships, this escalation is what
makes interruption reliable.

### 2. Skip the jest worker for the CLI checker

The type-check runs in a jest worker to isolate the TypeScript
compiler-API heap so it can be freed after checking. In CLI mode the
compiler runs in a separate `tsc` process, so there is no heap to
isolate and the worker adds nothing but an extra process and
indirection. CLI mode now runs the setup/config path in-process and
spawns `tsc` directly. The TypeScript-API checker is unchanged and still
uses the worker.

### Testing

- Unit tests for `runTypeScriptCli` (spawn options, group-SIGKILL
teardown, signal handling, listener cleanup, captured-output decoding).
- Existing `test/production/app-dir/typescript-cli` integration suite
passes (TS 6, TS 7, opt-in-required, `ignoreBuildErrors`,
`--debug-build-paths`).
- Manually verified against a TypeScript 7 project large enough to
distinguish a real kill from natural completion: the native compiler is
reaped ~200ms after interrupt.

<!-- NEXT_JS_LLM_PR -->

(cherry picked from commit 63375cd)
Currently if you enable `useTscCli` we render a `Running Typescript ...`
but then never remove it. This is simply because our normal approach of
pausing/resuming the spinner doesn't work with the subprocess.

Instead run the spinner in the normal way and stop it as soon as the
subprocess produces any output. TSC produces all output in a small
sequence of writes at the end, so this works as expected. If it changes
to start streaming data this will also work but the spinner will never
restart, but this is fine.

(cherry picked from commit 501f347)
@lukesandberg
lukesandberg force-pushed the backport-ts7-fixes-next-16-2 branch from ce9ab0c to 273a85a Compare July 23, 2026 20:05
@lukesandberg
lukesandberg marked this pull request as ready for review July 23, 2026 20:06
@lukesandberg
lukesandberg enabled auto-merge (squash) July 23, 2026 20:06
@lukesandberg
lukesandberg requested a review from bgw July 23, 2026 20:07
@lukesandberg
lukesandberg merged commit 957f5ed into next-16-2 Jul 23, 2026
243 of 250 checks passed
@lukesandberg
lukesandberg deleted the backport-ts7-fixes-next-16-2 branch July 23, 2026 20:42
lukesandberg added a commit that referenced this pull request Jul 24, 2026
## Summary

A minimal mitigation for the TypeScript 7 problem on the `15.5.x` line,
ported from the `next-16-2` mitigation (#95837).

TypeScript 7's native compiler no longer ships the JavaScript compiler
API (`typescript/lib/typescript.js`) that Next.js loads via
`require('typescript')`, so an installed TS7 produces surprising
failures with no actionable message. This was reported against 16.2 in
#95801.

## What it does

- Because the missing compiler-API file makes an installed TS7 look like
a *missing* dependency, `hasNecessaryDependencies` now also exposes the
resolved `typescript/package.json` path. `verifyTypeScriptSetup` reads
that version up front and, if it's `>= 7.0.0` (including prereleases —
`7.0.0-beta`/`-rc`, nightly `7.0.0-dev.*`, via the `7.0.0-0` sentinel
with `includePrerelease`), throws a `CompileError` with guidance to
install TypeScript 6 or upgrade Next.js, before the `require()` runs.

Unlike the 16.2 mitigation, no install-specifier change is needed here:
the `15.5` line already pins TypeScript auto-installs via
`getTypeScriptPackageSpec` (`typescript@5.8.2`) rather than pulling
`latest`.

Applies to both `next dev` and `next build`.

## Notes

- This is the minimal fix for `15.5`; the full
`experimental.useTypeScriptCli` backend (real TS7 support) is a
separate, larger effort and was considered overkill for this stable
line.
- Related: `next-16-2` mitigation #95837, and full backport #95831.

## Verification

- `pnpm --filter=next build`
- Boundary verified against the compiled semver: `5.8.2` / `6.x` (incl.
`6.0.0-beta`) are not rejected; `7.0.0-dev.*` / `7.0.0-beta` /
`7.0.0-rc` / `7.0.0` / `7.0.2` are rejected.
- Manual repro with `typescript@7` + `next@15.5`: `next build` and `CI=1
next build` exit non-zero with the actionable error instead of the
opaque failure.
vkumar04 added a commit to vkumar04/tydei-next that referenced this pull request Jul 26, 2026
)

* chore(deps): bump 28 packages, hold TypeScript at 6.x

Routine `ncu -u` maintenance. Every bump is patch or minor — no majors —
with `typescript` deliberately rejected (see below).

Notable version distance, release notes checked:
  ai                7.0.15 -> 7.0.37   repairToolCall promoted to stable
                                       (deprecated experimental_ alias);
                                       we don't use either.
  @ai-sdk/react     4.0.16 -> 4.0.40
  prisma/@prisma/*   7.8.0 -> 7.9.0    adapter-pg no longer emits Node's
                                       DEP0005 on Bytes reads; Studio
                                       migrations view. Nothing breaking.
  lucide-react      1.23.0 -> 1.27.0
  recharts           3.9.2 -> 3.10.1
  next            16.2.10 -> 16.2.12   <- see below
  oxlint            1.72.0 -> 1.75.0   verified 0 new warnings (58 before,
                                       58 after) — lint-neutral.

── TypeScript stays on 6.x, but the reason changed ──────────────────

next 16.2.12 backported TypeScript 7 support to the stable 16.2 line
(vercel/next.js#95831, merged 2026-07-23), cherry-picking the
`experimental.useTypeScriptCli` backend from canary. Confirmed present in
the installed package: node_modules/next/dist/server/config-schema.js
carries the flag.

So the blocker recorded three days ago is GONE — TS 7 no longer requires
next 16.3. The guard test asserted `next >= 16.3`, which is now wrong and
would have blocked a legitimate upgrade, so its threshold moves to
16.2.12 with boundary cases either side (16.2.12 accepted, 16.2.11 still
rejected). The header comment is updated to match.

TypeScript itself is NOT bumped here — that's a deliberate, separately
verifiable change, not something to bury in a 28-package maintenance
commit. The repo typechecks clean under TS 7 (0 errors, 2.5s vs 13.9s)
and the path is now open whenever we want it.

Verified: tsc 0 errors; 3754 tests passing; `rm -rf .next && bun run
build` succeeds end to end including the standalone postbuild; production
server smoked on /, /login, /api/health — all 200, no server errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(admin): create users without signing anyone in or blocking on email

Reported: on /admin/users the Add-user modal closes on its own and the page
navigates away. Reproduced locally against a seeded DB — the cause is the
`auth.api.signUpEmail` call I introduced in #155.

signUpEmail is the obvious API and the wrong one here. Two problems, both
observed directly:

1. It sends the verification email INSIDE the call and AFTER the user row
   is committed (better-auth sign-up.mjs:246). A mail failure therefore
   throws out of a half-finished create. The local repro shows it exactly:

     error: Email delivery is not configured
       at lib/auth-server.ts:275          <- our sendVerificationEmail
       at better-auth/.../sign-up.mjs:246 <- called INSIDE signUpEmail
     { ms: 119, sessions: 0, accounts: 1, row: { role: "facility" } }

   The user and credential are already written, so the follow-up
   `prisma.user.update` that applies the ROLE never runs. The admin sees a
   failure, the account exists as a plain `facility` user, and the retry is
   then blocked by "already exists".

2. It creates a Session and calls setSessionCookie for the NEW user
   (sign-up.mjs:256-261). That is inert today only because the
   `nextCookies()` integration isn't installed — adding it, which is the
   standard Next setup better-auth documents, would silently swap the
   admin's own session for the account they just provisioned.

Creation now goes through better-auth's internal context
(`auth.$context` -> `password.hash` + `internalAdapter.createUser` /
`createAccount`): a real hashed credential, normalized email, and NO
session. The verification email is sent afterwards, best-effort — the
account is complete before it runs, so a Resend outage logs and moves on
instead of stranding a half-created user.

Verified end-to-end against a local DB with the email deliberately failing:

    { emailThrew: true, user: { role: "admin" }, credentials: 1, sessions: 0 }
    findUserByEmail(UPPERCASE) -> FOUND

Role applied despite the mail failure, credential present, no session, and
the account reachable case-insensitively.

Tests rewritten around the new path (10 cases), including ordering
(credential before email), survival of a failing send, no-session, and
duplicate rejection before better-auth is touched.

Note on the reported symptom: `requireRole` calls `redirect()` on any auth
mismatch, and per the Next docs a redirect from a Server Action "navigates
the router" — so an action failing mid-flight is what routes the page away.
Next also dispatches Server Actions one at a time per client, so a slow
action stalls the other three queries this page fires. Both are why the
failure surfaced as "modal closes, page routes out" rather than an error
toast. Worth revisiting separately; this commit removes the trigger.

Verified: tsc 0 errors, 3758 tests passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
cloudexible added a commit to cloudexible-org/turbostack that referenced this pull request Jul 28, 2026
Squashes five unpushed commits into one release. Version is 4.3.0 across the
root and every workspace package; docs/changelog.md consolidates what were
separate [Unreleased] and [4.3.0] sections into a single dated entry.

Added
- docs/e2e-architecture.md: reference for the apps/e2e Playwright suite —
  scope, web server lifecycle, POM discipline, DOM-reading technique, locator
  pitfalls, and parallel safety against the shared Convex deployment. Writing it
  surfaced five defects in §2, all of which are fixed below rather than left
  open as they originally were.

Changed
- TypeScript 6 -> 7 (the Go-native compiler), with experimental.useTypeScriptCli
  on apps/www. TS 7 ships without lib/typescript.js, the JS Compiler API Next
  uses to detect the install, so next build reported typescript as missing and
  crashed. Next backported a fix to the 16.2 line (vercel/next.js#95831,
  available from 16.2.10) that shells out to the tsc binary. It is opt-in, so
  that flag is load-bearing until Next flips the default. turbo typecheck went
  3.1s -> 1.4s; Next's type-check step inside next build 1552ms -> 336ms.
- Dependency refresh across the workspace — every remaining package moved to its
  latest release, all semver-compatible minors and patches. The next bump to
  16.2.12 is what makes the TypeScript 7 upgrade possible.
- Vercel preview deployments disabled for every branch except main, via
  git.deploymentEnabled in both apps' vercel.json.

Fixed
- The apps/e2e suite is green and now actually runs. It asserted a heading from
  apps/www while booting apps/app; it now asserts what apps/app renders. The
  webServer command ran pnpm -> portless -> vite, so Playwright killed the
  wrapper while vite survived on PID 1 holding 5173 and teardown hung after
  every test had passed — vite is now a direct child. reuseExistingServer is
  false unconditionally, and the html reporter no longer blocks on open.
- Added a root test:e2e script and a dedicated CI job, so the suite runs on
  every push and PR. Nothing executed it before, which is why the red spec went
  unnoticed. e2e#test is cache:false because e2e does not depend on app in the
  workspace graph, so a cached pass would outlive a UI regression.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
waleedlatif1 added a commit to simstudioai/sim that referenced this pull request Jul 30, 2026
16.2.12 is the current stable (published 2026-07-25) and its entire
changelog is two PRs: a docs backport and vercel/next.js#95831, "Fixes to
support TypeScript 7".

That second one matters here. `apps/sim` declares `typescript: ^7.0.2` and
the lockfile resolves 7.0.2, while 16.2.11 predates any TS7 handling — not
even the actionable-error guard (#95837), which was never merged. The
upstream symptom is `next build` dying with a silent SIGSEGV during its
type-check step, because the legacy TypeScript JS API that Next called is
gone in TS7. Builds pass today only because Next detects
@typescript/native-preview as the compiler and takes a different path, so
we are accidentally-working rather than supported. 16.2.12 adds the
`experimental.useTypeScriptCli` backend that makes this configuration
official.

Zero build-performance content in the patch, so this is not a speed change.

Bumps all eight pins in lockstep — next, @next/env and the four
@next/swc-* binaries at the root, plus the three app/package copies. The
swc binaries must move with next: they are platform-gated
optionalDependencies, so a version skew or a gate exclusion leaves them out
of bun.lock entirely and `bun install --frozen-lockfile` installs no
compiler at all (the #5945 failure).

Also re-dates the bunfig.toml gate note, which said to drop the next
entries on 2026-07-28 — yesterday. 16.2.12 is inside the 7-day window until
2026-08-01, so following that instruction would have blocked this bump and
re-triggered the missing-compiler failure. Re-date on future bumps rather
than deleting the entries early.
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.

3 participants