Skip to content

feat: accept Next.js 16.4.4 on the native Node path - #437

Open
soleil-colza wants to merge 10 commits into
mainfrom
feat/native-next-16-4-4-20261102
Open

soleil-colza wants to merge 10 commits into
mainfrom
feat/native-next-16-4-4-20261102

Conversation

@soleil-colza

@soleil-colza soleil-colza commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #436. Native Node Functions accept Next.js 16.4.4 as well as 16.4.3.

Why

The native Node path qualified exact next@16.4.3 bytes and refused anything else. Since the scaffolder asks for ^16.4.x, a new native app now installs 16.4.4. Projects pinned to 16.4.3 must keep building, so both releases are supported.

What 16.4.4 changes for this path

Of every source the path pins, 16.4.4 changes only these:

  • package.json.
  • The twelve next-server runtimes. They require next/dist/compiled/fast-jwt where 16.4.3 required jsonwebtoken (#100885).
  • build/templates/app-page-runtime.js. The resume now emits the Turbopack bootstrap (#100907).

Every other reviewed source is byte-identical between the two releases, which I checked against both installed packages: the route modules, route-module.js, load-components.js, the evaluator, the templates, request-meta.js, route-kind.js, pages-handler.js, require-hook.js and the ws bundle.

Two more changes affect the path:

  • The Turbopack production runtime no longer installs a chunk's leading strict factory table (#100866).
  • The JWT library is now fast-jwt, which needs a profile of its own.

Changes

  • Per-release pins (node-next-release.ts).
    • Each release carries its package.json, runtime and template bytes. Lookups accept the reviewed bytes of either release.
    • Where the package is known, the bytes must be that package's own release. The Pages proof refuses a package that holds another release's copy of a runtime or of the template. The cache-policy rewrite, the app-page factory and the cache-write proof each check the release that package.json names.
    • The ws and require-hook profiles accept either release's package, since their bytes are the same in both.
  • Turbopack runtime.
    • 16.4.4's three body fingerprints are computed from the release's own snapshot. Running the same computation on 16.4.3's snapshot reproduces the existing three fingerprints exactly.
    • A runtime proof now reports whether the runtime installs strict factory tables. Next to a runtime that does not, a chunk that leads with such a table is refused.
  • fast-jwt profile.
    • The bundle has no eval and no Function.
    • Its one Node loader read is safer-buffer's process.binding("buffer"), guarded by !o.kStringMaxLength. Node 24 and 26 export kStringMaxLength, so that read never runs.
    • That one site is the only exemption granted to the closure walker. A test confirms the walker refuses nothing else in the bundle.
    • The bootstrap guard accepts the record, answers the node: builtins, and seals the crypto functions fast-jwt captures at load.
    • A CI-only test signs and verifies preview data through the guard.
  • Producer per release. The independent Pages handler producer compiles with 16.4.4 under --next=16.4.4. Its workflow now takes its pnpm version from the fixture: action-setup was refusing the pinned 12.15.0 next to the repository's packageManager, so no producer job had been running.
  • CI and fixtures.
    • tools/native-addon-next-ci.mts builds the official fixtures with a reviewed release named by UPWIND_NATIVE_NEXT (16.4.3 by default).
    • fixtures/next-native moves to 16.4.4.

Still to come in this PR

  • The Pages "proved" mode needs the 16.4.4 getHandler whole-factory references. They come from the producer's 16.4.4 artifacts, which cannot run until pnpm's one-day release-age default lets the fixture install 16.4.4 (after 2026-11-03 10:49 UTC).
    • Until those references land, a Pages-only native build on 16.4.4 is still refused.
    • App Router native Functions (the whole server output) build on 16.4.4 with this change.
  • Once the references land, I'll add the 16.4.4 leg to the native fixture matrix.

Checks run locally

  • 183 adapter and runtime suites around the native path pass, apart from three macOS-only environment failures (sharp's libvips and /var vs /private/var).
  • The fast-jwt guard integration test passes on Node 24.22.1.
  • tsc, ESLint and oxfmt pass on every changed file, and so do knip and check:vocabulary.

Review notes

  • Real fast-jwt qualification (Greptile, cubic). The unit suites never reach a positive JWT qualification, for jsonwebtoken either: that requires a completed route closure, which only a real native build produces. The official native fixture CI exercises it for 16.4.3, building prerender-native-module in the Pages "proved" mode with jsonwebtoken retained. The 16.4.4 leg of the same job will do it for fast-jwt once the getHandler references are in. Until then, the unit test refuses a fast-jwt route approval the same way it refuses a jsonwebtoken one, and the closure test shows the binding read is the bundle's only refusal.
  • Taken in ddfcad9.
    • The Pages proof's package.json must match the release's exact bytes, not just its version.
    • The nested-table probe is total, and the cohort reads the chunks for it once.
    • The JWT builtin lists are frozen.
    • The lock comparison allows integrity changes only in Next.js's own entries.
    • The docs state the pending Pages-only limitation and the 16.4.3 CI fixture.
    • The producer README is updated.

Summary by CodeRabbit

  • New Features
    • Added support for Next.js 16.4.4 alongside 16.4.3 in native integrations and Pages handler profiles.
    • Pages handler profiles can be generated with server minification enabled or disabled, and can target either supported Next.js version.
    • Added support for validating fast-jwt evaluation in the native integration environment.
  • Documentation
    • Updated compatibility and profile guidance for Next.js 16.4.4 and its JWT handling.

The independent producer compiles its fixed public Pages fixture with
Next.js 16.4.3 by default, as before, and with 16.4.4 under --next=16.4.4.
A 16.4.4 run replaces only the manifest and lock, from fixture-16.4.4/,
which differ from 16.4.3's in the release and its integrities alone; the
published getHandler source is the same in both. The workflow runs default
and off for each release, with the 16.4.4 artifacts named apart.
pnpm/action-setup refused the pinned 12.15.0 beside the repository's
packageManager, 12.16.1, so no job of the producer ran. It reads the
fixture's packageManager instead, the same 12.15.0 the producer checks.
….4.3

The native Node path pinned next@16.4.3 alone. Of what it pins, 16.4.4
changes only package.json, the twelve server runtimes and the page
template factory; every other reviewed source is the same bytes.

Each release now carries those, by exact bytes (node-next-release.ts),
and a lookup accepts the reviewed bytes of either. Where the package is
known, the bytes must be its own release's: the Pages proof refuses a
package holding another release's copy of a runtime or the template, and
the cache policy rewrite, the template factory and the cache write check
the release the package.json names. The WebSocket and require-hook
bundles are the same in both releases, so their profiles accept either
package.
16.4.4 reverts the strict module factory chunks, so its Node runtime no
longer installs a chunk's leading strict factory table. Its three body
fingerprints, from the release's snapshot, join 16.4.3's, and a runtime
proof says whether it installs such a table. Beside one that does not, a
chunk leading with one is refused rather than read as strict.
… Functions

Next.js 16.4.4 compiles in fast-jwt where 16.4.3 had jsonwebtoken. Each
release now has its own fixed-source profile (node-jwt-compiler-profiles.ts),
chosen by the release the package is. fast-jwt names no code compiler;
its one Node loader read is the process.binding("buffer") its copy of
safer-buffer guards with !o.kStringMaxLength, which Node.js 24 and 26
never reach, and that read alone is exempt from the closure walker. It
has no semver dependency, and loads buffer, node:crypto, node:util and
util by those exact names.

The bootstrap guard accepts the fast-jwt record, answers the node:
builtins, and seals the crypto functions fast-jwt takes as it loads. A
CI-only test signs and verifies preview data through the guard.
The official fixtures build with 16.4.3 unless UPWIND_NATIVE_NEXT names
another reviewed release, and fixtures/next-native, which builds through
the whole server output, moves to 16.4.4.
@arkor-deploy

arkor-deploy Bot commented Nov 2, 2026

Copy link
Copy Markdown

Arkor — Preview deployments for arkorlab-upwind

Use the checkbox below to choose whether this pull request gets preview deployments.

  • Build and deploy previews for this pull request

Checking this builds the latest commit and future pushes. Unchecking stops queued and future builds; a running build can finish and an existing preview stays available.

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

CodeRabbit ASCII loading animation

Currently processing new changes in this PR. This may take a few minutes, please wait...

Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: eb69cd4d-ec3a-4c5a-92a4-a38616e944d6
Commits

Reviewing files that changed from the base of the PR and between ead498e and ddfcad9.

Files ignored due to path filters: 1
  • tools/native-pages-handler-profile/fixture-16.4.4/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing: 56
  • .github/workflows/native-addon-functions.yaml
  • .github/workflows/native-pages-handler-profile.yaml
  • docs/native-functions.md
  • docs/node26.md
  • fixtures/next-native/package.json
  • packages/adapter/src/node-closure-proof.ts
  • packages/adapter/src/node-jwt-compiler-profiles.ts
  • packages/adapter/src/node-jwt-compiler-proof.ts
  • packages/adapter/src/node-jwt-fast-sites.ts
  • packages/adapter/src/node-manifest-app-page-factory.ts
  • packages/adapter/src/node-manifest-coalesced-pages.ts
  • packages/adapter/src/node-manifest-consumers.ts
  • packages/adapter/src/node-manifest-framework.ts
  • packages/adapter/src/node-manifest-graph.ts
  • packages/adapter/src/node-manifest-proof.ts
  • packages/adapter/src/node-manifest-runtime-cohort.ts
  • packages/adapter/src/node-manifest-turbopack-runtime.ts
  • packages/adapter/src/node-manifest-turbopack.ts
  • packages/adapter/src/node-next-cache-write-proof.ts
  • packages/adapter/src/node-next-pinned-rewrite.ts
  • packages/adapter/src/node-next-release.ts
  • packages/adapter/src/node-next-require-hook-proof.ts
  • packages/adapter/src/node-next-rewrite-proof.ts
  • packages/adapter/src/node-turbopack-selector.ts
  • packages/adapter/src/node-ws-loader-proof.ts
  • packages/adapter/test/fixtures/node-manifest-bound-batch.ts
  • packages/adapter/test/fixtures/node-manifest-template-graph.ts
  • packages/adapter/test/fixtures/node-manifest-turbopack-proof.ts
  • packages/adapter/test/fixtures/node-runtime-16.4.4/LICENSE.txt
  • packages/adapter/test/fixtures/node-runtime-16.4.4/README.md
  • packages/adapter/test/fixtures/node-runtime-16.4.4/production.txt
  • packages/adapter/test/fixtures/pinned-next.ts
  • packages/adapter/test/node-fast-jwt-guard-integration.test.ts
  • packages/adapter/test/node-jwt-compiler-proof.test.ts
  • packages/adapter/test/node-jwt-fast-sites.test.ts
  • packages/adapter/test/node-manifest-proof.test.ts
  • packages/adapter/test/node-manifest-turbopack-registration.test.ts
  • packages/adapter/test/node-manifest-turbopack-runtime.test.ts
  • packages/adapter/test/node-next-release.test.ts
  • packages/adapter/test/node-pages-handler-inputs.test.ts
  • packages/adapter/test/node-proof.test.ts
  • packages/adapter/test/node-route-rewrite-approvals.test.ts
  • packages/adapter/test/node-turbopack-selector-integration.test.ts
  • packages/runtime/src/node-initialization-builtins.ts
  • packages/runtime/src/node-jwt-guard.ts
  • packages/runtime/src/node-jwt-realm-fields.ts
  • packages/runtime/src/node-jwt-realm.ts
  • packages/runtime/test/node-jwt-realm.test.ts
  • packages/runtime/test/node-next-hooks.test.ts
  • packages/runtime/test/node-ws-realm.test.ts
  • tools/native-addon-next-ci.mts
  • tools/native-pages-handler-profile-ci.mts
  • tools/native-pages-handler-profile/README.md
  • tools/native-pages-handler-profile/fixture-16.4.4/package.json
  • tools/native-pages-handler-profile/inputs.mts
  • tools/native-pages-handler-profile/options.mts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

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

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@soleil-colza

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T19:44:31.586449Z ddfcad9 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 05c7de0caf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps

greptile-apps Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the remaining test-coverage finding is non-blocking.

Fix All in Claude CodeFindings

  1. P2 Fast-jwt tests bypass real qualification ▶
Fix with agent prompt
### Issue 1
packages/adapter/test/node-jwt-fast-sites.test.ts:15-20
This test mocks `nodeJwtCompilerSite` and supplies an empty proof, so it skips the new profile’s real package, dependency and caller checks in `qualifyNodeJwtCompiler`. The guard integration test supplies its record by hand too. Both can pass while the adapter refuses fast-jwt builds.

Add a test that qualifies a real fast-jwt graph, uses the returned proof in the closure check, and checks the resulting guard record.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds native Node support for Next.js 16.4.4 while keeping 16.4.3 support.

  • Native builds match each Next.js release to its own reviewed source bytes.
  • Next.js 16.4.4 fast-jwt runs under its own guarded source profile.
  • Turbopack proofs match each runtime to the factory-table shape it installs.
  • CI can build separate native and Pages fixtures with Next.js 16.4.4.

Reviews (3) · Last reviewed commit: "fix(adapter): hold the native Next.js pa..." · Reviewed by Greptile

Comment on lines +15 to +20
vi.mock(import('../src/node-jwt-compiler-proof.ts'), async () => {
const sites = await import('../src/node-jwt-fast-sites.ts');
return {
nodeJwtCompilerSite: (proof: unknown, _file: string, _code: string, program: unknown) => {
const node = proof === undefined ? undefined : sites.nodeFastJwtBindingSite(program);
return node === undefined ? undefined : { kind: 'loader', node };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Fast-jwt tests bypass real qualification

This test mocks nodeJwtCompilerSite and supplies an empty proof, so it skips the new profile’s real package, dependency and caller checks in qualifyNodeJwtCompiler. The guard integration test supplies its record by hand too. Both can pass while the adapter refuses fast-jwt builds.

Add a test that qualifies a real fast-jwt graph, uses the returned proof in the closure check, and checks the resulting guard record.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/adapter/test/node-jwt-fast-sites.test.ts
Line: 15-20

Comment:
**Fast-jwt tests bypass real qualification**

This test mocks `nodeJwtCompilerSite` and supplies an empty proof, so it skips the new profile’s real package, dependency and caller checks in `qualifyNodeJwtCompiler`. The guard integration test supplies its record by hand too. Both can pass while the adapter refuses fast-jwt builds.

Add a test that qualifies a real fast-jwt graph, uses the returned proof in the closure check, and checks the resulting guard record.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 49 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/adapter/src/node-manifest-turbopack.ts">

<violation number="1" location="packages/adapter/src/node-manifest-turbopack.ts:241">
P2: This classifier throws for a valid registration whose first element is an ordinary zero-argument call, instead of returning `false` as its contract says. Because `flatTables` applies it to every source without a catch, one such chunk aborts runtime-cohort certification; keep the `strictWrapper` probe inside the existing `try` or make that probe non-throwing.</violation>
</file>

<file name="packages/adapter/test/node-jwt-fast-sites.test.ts">

<violation number="1" location="packages/adapter/test/node-jwt-fast-sites.test.ts:15">
P2: This mock reduces the closure test to a synthetic site and `{}` proof, so it cannot catch fast-jwt qualification failures. Add a test that qualifies a real fast-jwt graph and checks the returned proof and guard record.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread docs/native-functions.md Resolved
Comment thread docs/native-functions.md Resolved
}
const first = listOf(table, 'elements')[0];
return (
isNode(first) && (first.type === 'ArrayExpression' || strictWrapper(first, true) !== undefined)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This classifier throws for a valid registration whose first element is an ordinary zero-argument call, instead of returning false as its contract says. Because flatTables applies it to every source without a catch, one such chunk aborts runtime-cohort certification; keep the strictWrapper probe inside the existing try or make that probe non-throwing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/adapter/src/node-manifest-turbopack.ts, line 241:

<comment>This classifier throws for a valid registration whose first element is an ordinary zero-argument call, instead of returning `false` as its contract says. Because `flatTables` applies it to every source without a catch, one such chunk aborts runtime-cohort certification; keep the `strictWrapper` probe inside the existing `try` or make that probe non-throwing.</comment>

<file context>
@@ -228,6 +228,20 @@ function checkedTurbopackProgram(source: NodeManifestTurbopackSource): Node {
+  }
+  const first = listOf(table, 'elements')[0];
+  return (
+    isNode(first) && (first.type === 'ArrayExpression' || strictWrapper(first, true) !== undefined)
+  );
+}
</file context>
Suggested change
isNode(first) && (first.type === 'ArrayExpression' || strictWrapper(first, true) !== undefined)
isNode(first) &&
(first.type === 'ArrayExpression' ||
(() => {
try {
return strictWrapper(first, true) !== undefined;
} catch {
return false;
}
})())

import { nodeFastJwtBindingSite } from '../src/node-jwt-fast-sites.ts';

// The proof itself needs a whole qualified graph; here it stands for one that reads fast-jwt's site.
vi.mock(import('../src/node-jwt-compiler-proof.ts'), async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This mock reduces the closure test to a synthetic site and {} proof, so it cannot catch fast-jwt qualification failures. Add a test that qualifies a real fast-jwt graph and checks the returned proof and guard record.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/adapter/test/node-jwt-fast-sites.test.ts, line 15:

<comment>This mock reduces the closure test to a synthetic site and `{}` proof, so it cannot catch fast-jwt qualification failures. Add a test that qualifies a real fast-jwt graph and checks the returned proof and guard record.</comment>

<file context>
@@ -0,0 +1,84 @@
+import { nodeFastJwtBindingSite } from '../src/node-jwt-fast-sites.ts';
+
+// The proof itself needs a whole qualified graph; here it stands for one that reads fast-jwt's site.
+vi.mock(import('../src/node-jwt-compiler-proof.ts'), async () => {
+  const sites = await import('../src/node-jwt-fast-sites.ts');
+  return {
</file context>

Review of the 16.4.4 support:

- The Pages proof selects the release by the package.json's exact
  bytes as well as its version, as the other fixed-source proofs do; the
  suites copy the published 16.4.3 package.json instead of writing one.
- The nested strict-table probe answers false for any program it cannot
  read, and the runtime cohort reads the chunks for it once.
- A JWT profile's builtins are a frozen list, not a mutable Set.
- The 16.4.4 producer lock may differ from 16.4.3's only in versions and
  in the integrities of the packages Next.js publishes.
- The route-approval refusal is checked for fast-jwt too, and the docs
  say a Pages-only native build on 16.4.4 waits for its getHandler
  references.
@soleil-colza

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: ddfcad9408

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Base automatically changed from chore/next-16.4.4-20261102 to main November 3, 2026 02:16

This branch has not been deployed

No deployments
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.

1 participant