mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #402] [MERGED] fix: next/headers readonly semantics and legacy sync compatibility #545
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#545
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/402
Author: @JaredStowell
Created: 3/10/2026
Status: ✅ Merged
Merged: 3/10/2026
Merged by: @james-elicx
Base:
main← Head:jstowell/fix-request-api-readonly-compat📝 Commits (8)
1657d7eAdd headers/cookies legacy testsa76d206Fix headers sync error handling11ea525Fix headers sync guards5ec93e5bonk4bdd5e3Update packages/vinext/src/shims/headers.ts4a5ad63bonkb37311eClarify dynamic error comment66de12dMerge remote-tracking branch 'origin/main' into jstowell/fix-request-api-readonly-compat📊 Changes
16 files changed (+1224 additions, -374 deletions)
View changed files
📝
packages/vinext/src/entries/app-rsc-entry.ts(+44 -43)📝
packages/vinext/src/shims/headers.ts(+225 -12)📝
tests/__snapshots__/entry-templates.test.ts.snap(+264 -258)📝
tests/e2e/app-router/server-actions.spec.ts(+36 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/action-cookie-phase/actions.ts(+8 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/action-cookie-phase/page.tsx(+29 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/api/headers-readonly/route.ts(+18 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/api/request-api-repeat/route.ts(+29 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/api/request-api-sync/route.ts(+17 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/draft-mode-dynamic-error/page.tsx(+21 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/request-api-dynamic-error/page.tsx(+32 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/request-api-readonly/page.tsx(+33 -0)➕
tests/fixtures/app-basic/app/nextjs-compat/request-api-sync/page.tsx(+15 -0)📝
tests/nextjs-compat/draft-mode.test.ts(+10 -0)➕
tests/nextjs-compat/request-apis.test.ts(+117 -0)📝
tests/shims.test.ts(+326 -61)📄 Description
Fix
next/headerscompatibility gaps so vinext matches Next.js more closely for request APIs.This changes
headers()andcookies()to support the legacy sync access pattern while preserving their Promise-based API, makesheaders()read-only, and restrictscookies()mutation to route handlers and server actions instead of allowing writes during normal render paths.What changed
headers()andcookies()so legacy sync access likeheaders().get(...)andcookies().get(...)works.headers()result read-only and throw onset,append, anddelete.next/headersshim state.Tests
Added substantial regression coverage across unit, integration, and browser layers.
Unit / shim coverage
Expanded
tests/shims.test.tsto cover:headers()andcookies()headers()for sync and awaited accesscookies()during rendercookies()only in route-handler and action phasesHTTP integration coverage
Added
tests/nextjs-compat/request-apis.test.tsand new fixture routes/pages to verify:headers()andcookies()access in real App Router page requestscookies()headers()New fixtures:
tests/fixtures/app-basic/app/nextjs-compat/request-api-sync/page.tsxtests/fixtures/app-basic/app/nextjs-compat/request-api-readonly/page.tsxtests/fixtures/app-basic/app/nextjs-compat/api/request-api-sync/route.tstests/fixtures/app-basic/app/nextjs-compat/api/headers-readonly/route.tstests/fixtures/app-basic/app/nextjs-compat/api/request-api-repeat/route.tsBrowser / server-action coverage
Added a Playwright regression in
tests/e2e/app-router/server-actions.spec.tsplus a new fixture page/action:tests/fixtures/app-basic/app/nextjs-compat/action-cookie-phase/page.tsxtests/fixtures/app-basic/app/nextjs-compat/action-cookie-phase/actions.tsThis verifies that:
cookies()as read-onlyValidation
Ran:
pnpm test tests/shims.test.ts tests/nextjs-compat/request-apis.test.ts tests/nextjs-compat/set-cookies.test.ts tests/nextjs-compat/draft-mode.test.tspnpm test tests/nextjs-compat/request-apis.test.tsPLAYWRIGHT_PROJECT=app-router pnpm run test:e2e tests/e2e/app-router/server-actions.spec.tspnpm run typecheckpnpm run lintNotes
This preserves vinext’s internal lazy mutable request header optimization for middleware forwarding, but seals the public API so user code can no longer mutate request headers or write cookies from normal render contexts.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.