Commit Graph

1635 Commits

Author SHA1 Message Date
github-actions[bot] 7eccf8e898 chore: version packages (beta) (#2616)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@vinext/cloudflare@1.0.0-beta.2 @vinext/types@1.0.0-beta.2 create-vinext-app@1.0.0-beta.1 vinext@1.0.0-beta.2
2026-07-16 12:37:23 +00:00
Nathan Nguyen 0252ea1d8a fix(check): exclude test-runner files from app compatibility scans (#2596)
* fix(check): exclude test-runner files from app compatibility scans

vinext check scans test modules and test-runner configuration as though they are bundled into the migrated application. Apps using CommonJS globals only in Vitest files therefore receive unsupported migration issues even when the vinext build succeeds.

Separate the application compatibility candidate set from the general recursive file finder. Exclude test and spec modules plus conventional Jest, Playwright, and Vitest config files, while keeping ordinary runtime config modules visible to import and convention checks.

* ci: rerun performance benchmarks

---------

Co-authored-by: James Anderson <james@eli.cx>
2026-07-15 22:48:49 +00:00
Nathan Nguyen c6f2a877d0 fix(app-router): stream generated metadata after the document shell (#2619)
* fix(app-router): stream generated metadata after the document shell

Dynamic App Router document renders currently await generateMetadata before constructing the page element tree. This delays response headers and the first HTML chunk for streaming-capable clients.

Head resolution coupled metadata and viewport into one awaited result, so the renderer could not suspend only metadata. Start the branches independently, keep blocking callers unchanged, and expose metadata through paired Suspense tag and error outlets. The hidden host wrapper preserves React's shell flush in the presence of hoistable metadata tags.

The focused head test verifies metadata remains pending while viewport resolution completes.

* test(app-router): verify generated metadata follows the production shell

Production coverage only established that HTML eventually arrived, so delaying the first byte until generateMetadata completed remained undetected.

Read the production response incrementally and require the page shell to precede delayed metadata while still asserting the final tags.

* test(app-router): align metadata error coverage with streamed responses

Streaming generateMetadata errors return a recoverable 200 shell before local or global boundaries render after hydration. The compatibility suite incorrectly expected those boundaries and 500 statuses in raw server HTML, which conflicts with Next.js 16.2.7 and fails the integration shard.

Update raw-response assertions to cover shell behavior and add browser coverage for page and layout metadata errors with and without local boundaries.

* fix(app-router): stream metadata during navigation

* fix(app-router): isolate connection probes from streaming metadata

Dynamic metadata prefetches can leave Flight responses open indefinitely when generateMetadata calls connection(). Streaming starts metadata in parallel with page classification, but the speculative probe mutated shared request state and captured the sibling metadata branch.

Run probes in a nested request scope, then propagate dynamic usage and new diagnostic errors back with concurrency-safe rules. This preserves classification while allowing sibling metadata work to complete.

* refactor(app-router): isolate fallback metadata planning

Streamed metadata fallbacks previously configured the general head resolver with traversal flags for boundary repetition, leaf ordering, and viewport suppression. That made fallback policy part of normal metadata resolution and obscured the RSC navigation transport contract.

Build an explicit HTTP-access fallback metadata source plan, then resolve it through the shared ordered metadata merger. Add focused planner coverage and pin delayed navigation redirects to HTTP 200 Flight digest transport.

* fix(app-router): preserve not-found metadata search params

Page-local not-found metadata lost searchParams after deferred metadata called notFound(), so query-derived tags were wrong and search access was invisible to dynamic-usage tracking. Terminal fallback rendering also recomputed the boundary head without the normalized query.

Classify not-found ownership from module identity and tree position, attach query state and its observer only for page-owned conventions, and thread normalized search params through terminal fallback rendering. Cover repeated fallback leaves, observer access, and a production page-local not-found route.

* fix(app-router): release completed connection probes

Async work created inside a speculative connection probe retained the child request store after the probe returned. Because that store still referenced the completed probe, a later connection() call suspended forever.

Restore the child store's currently inherited probe during deterministic cleanup. This preserves nested probe ownership while allowing late continuations to observe the completed scope, with a real AsyncLocalStorage regression covering the lifecycle.

* fix(app-router): preserve deferred metadata cache signals

Deferred metadata dynamic usage can overlap a speculative layout probe. The probe cleared and later consumed the shared request flag, allowing an RSC cache entry to be written even though the completed response was marked no-store.

The layout classifier treated save-and-restore mutation as async isolation. Run probe classification in a child dynamic-usage scope so sibling metadata retains the parent request state, and cover the overlap through the dispatch cache boundary.

* fix(app-router): preserve fallback metadata parity

---------

Co-authored-by: James <james@eli.cx>
2026-07-15 23:13:04 +01:00
James Anderson 0b6faab89d fix(cache): isolate draft route responses (#2591)
* fix(cache): isolate draft route handler responses

* fix(cache): enforce draft policy on route errors

* fix(cache): privatize draft mode transitions

* fix(cache): respect live draft transitions

* fix(cache): discard route cookies on failed handlers

* Reviewed PR #2591: solid fix, no blocks

Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>

* test(cloudflare): use public CDN adapter export

* fix(ci): align Cloudflare fixture lock entry

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
2026-07-15 14:06:00 +01:00
James Anderson 29e6230212 fix(middleware): align unsafe matcher validation (#2599)
* fix(middleware): support mixed and repeating matchers

* fix(middleware): harden matcher validation

* fix(middleware): close matcher parity gaps

* fix(middleware): make matcher analysis deterministic

* fix(middleware): bound matcher sequence ambiguity

* fix(middleware): model matcher shorthand classes

* fix(middleware): reject quadratic matcher sequences

* fix(middleware): flatten matcher sequence wrappers

* fix(middleware): unwrap exact-one matcher repeats

* perf(runtime): lazy-load config matchers

* fix(navigation): preserve rewrite prefetch reuse

* PR #2599 reviewed: no blockers

Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>

* fix(middleware): avoid matcher chunk initialization race

---------

Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
2026-07-15 14:01:43 +01:00
James Anderson 8e55df80ec fix(ci): keep Vite+ installs from dirtying the lockfile (#2631) 2026-07-15 09:57:36 +01:00
James Anderson 82ef911dfd fix(pages): match encoded string static paths (#2629) 2026-07-15 00:26:45 +00:00
James Anderson bda1fb1353 fix(dev): refresh routes after server restarts (#2588)
* fix(dev): refresh routes after server restarts

* fix(dev): stabilize route cache invalidation
2026-07-15 00:44:55 +01:00
Andrew 106398d494 fix(cache): guard 'use cache' key against Cloudflare KV's 512-byte limit (#2606)
* fix(cache): guard 'use cache' KV key against Cloudflare's 512-byte limit

A long dynamic-route slug flows into the 'use cache' KV key via the
serialized args. When the assembled key exceeded Cloudflare KV's 512-byte
key limit, handler.get threw a 414 *before* the wrapped render reached
notFound()/redirect(), masking those control-flow signals and surfacing a
catch-all not-found as a 200 error boundary instead of a 404 (soft-404).

- buildUseCacheKey now hashes the oversized parts (fnv1a64), mirroring the
  ISR cache's guard in isr-cache.ts (buildCacheKey); the readable
  function-scoped prefix is preserved when it fits so distinct cached
  functions never collide.
- handler.get is wrapped so any cache-store failure falls through to fresh
  execution, letting the function's own thrown digest propagate.

Regression tests added in tests/shims.test.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cache): enforce Cloudflare KV key limits

* refactor(cache): keep key hashing in KV adapter

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: James <james@eli.cx>
2026-07-15 00:37:21 +01:00
James Anderson 50ac8fe039 fix(pages): isolate static render router state (#2583)
* fix(pages): isolate static render query context

* fix(pages): preserve serialized router hydration state

* fix(pages): stabilize ISR router readiness

* fix(pages): normalize localized hydration pathname

* fix(pages): restore router hydration parity

* fix(pages): align fallback router hydration state

* fix(pages): preserve live fallback browser path
2026-07-15 00:37:06 +01:00
James Anderson eacd44a223 fix(pages): validate redirect destinations consistently (#2586)
* fix(pages): block executable redirect schemes

* fix(pages): keep redirect safety within bundle budget

* test(pages): exercise middleware data redirect blocking
2026-07-15 00:29:28 +01:00
yyh 388144d660 fix(config): keep page extensions out of module resolution (#2594)
* fix(config): keep page extensions out of module resolution

* fix(config): preserve default extension priority
2026-07-15 00:19:51 +01:00
Sakamoto, Kazunori d61ace5bc0 fix(navigation): avoid rewriting URL for history metadata (#2615)
* fix(navigation): tolerate history state writes rejected by the browser

history.pushState/replaceState can throw a SecurityError when document.URL
still contains userinfo credentials (e.g. behind HTTP Basic auth Chromium
strips them from location.href but not from document.URL), in sandboxed or
opaque-origin documents, or when the per-origin call quota is exceeded.

The notify-suppressed history primitives only persist vinext navigation
metadata, so an unguarded call let a hydration-time replaceState failure
escalate to the global error boundary and blank the whole page. Wrap both
primitives in try/catch and log a warning so metadata-write failures degrade
gracefully.

Fixes #2614

* fix(navigation): avoid rewriting URL for history metadata

---------

Co-authored-by: James <james@eli.cx>
2026-07-15 00:04:54 +01:00
Andrew 121290f1e9 fix(og): resolve dot-hash wasm fallbacks (#2608) 2026-07-14 23:57:57 +01:00
James Anderson 8b4b608bd0 docs(router): clarify static param case matching (#2628)
* docs(router): clarify static param case matching

* fix(pages): preserve raw production request paths
2026-07-14 22:38:51 +01:00
James Anderson 4f7eec967e fix(router): avoid repeated App path decoding (#2556)
* fix(router): avoid repeated App path decoding

* test(router): align encoded middleware pathname

* fix(router): match Next encoded path semantics

* fix(prerender): accept canonical encoded app params

* fix(router): preserve encoded interception params

* test(build): tolerate watch output replacement

* test(router): cover repeatedly encoded production paths

* fix(router): preserve action request route identity

* refactor(middleware): remove stale pathname argument

* refactor(router): align fallback interception paths

* refactor(router): derive request path identity from value

* fix(router): preserve encoded route parity

* fix(router): preserve raw config path matching

* fix(router): preserve raw encoded route identity

* fix(router): canonicalize encoded dot segments

* fix(router): restore encoded path parity after main merge

* fix(app-router): exact-match generated params

* fix(app-router): chain generated parent params

* fix(app-router): preserve generated param ownership

* fix(app-router): preserve per-result param ownership

* fix(app-router): preserve params after empty parallel generation

* fix(app-router): chain parallel static params by branch
2026-07-14 22:09:29 +01:00
James Anderson 8c2e4bb119 fix(pages): preserve data route path identity (#2580)
* fix(server): reject ignored controls in Pages paths

* fix(pages): align data path guards across runtimes

* fix(pages): preserve encoded data route params
2026-07-14 21:28:34 +01:00
James Anderson b62f9afa8d fix(benchmarks): isolate Next.js TypeScript dependency (#2627) 2026-07-14 21:21:08 +01:00
James Anderson 7ec9b2201e fix(app-router): preserve Flight stream framing (#2579)
* fix(app-router): preserve Flight row framing

* fix(app-router): harden Flight framing fallback
2026-07-14 21:20:27 +01:00
James Anderson 329af14409 fix(pages): populate route in app initial props router (#2623) 2026-07-14 20:45:17 +01:00
James Anderson 8091a2ec80 fix(release): require package-specific publish tags (#2624) 2026-07-14 20:26:18 +01:00
James Anderson 645d1a1c74 fix(create): make create-vinext-app work with npm and npx (#2618)
* fix(create): make create-vinext-app work with npx

* fix(ci): run packed creator directly with npx

* fix(cloudflare): support vinext prerelease peers
2026-07-14 20:25:39 +01:00
James Anderson 9655db6009 build(types): register package tasks with Vite+ (#2626) 2026-07-14 19:25:16 +00:00
James Anderson 4543212bb2 chore(types): remove obsolete font type generator (#2625) 2026-07-14 20:24:31 +01:00
James Anderson de94652a1d fix(shims): align public API with vendored Next types (#2617)
* fix(shims): align public API with vendored Next types

* fix(shims): preserve revalidation and runtime behavior

* test(shims): align cache revalidation expectations

* fix(ci): package types for deploy suite
2026-07-14 19:32:33 +01:00
James Anderson b859a03bbd feat(types): ship Next-compatible types without Next.js (#2612)
* feat(types): add vendored Next.js declarations

* feat(types): expose fallback types through vinext

* fix(types): support readonly Node environment declarations

* fix(ci): install vendored types before vinext tarballs

* test(types): avoid brittle packed consumer pins

* fix(ci): configure pnpm 11 local type overrides

* test(types): avoid registry metadata in packed install

* test(types): isolate packed declaration install

* feat(init): add standard script aliases for new apps

* fix(create-vinext-app): run typegen portably

* fix(typegen): report next env updates

* fix(create-vinext-app): use standard scripts only

* refactor(create-vinext-app): use exhaustive package manager return

* fix(create-vinext-app): fall back for unknown package managers
@vinext/types@1.0.0-beta.1
2026-07-14 13:27:20 +01:00
github-actions[bot] 8d0a18d440 chore: version packages (beta) (#2549)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@vinext/cloudflare@1.0.0-beta.1 vinext@1.0.0-beta.1
2026-07-10 08:44:13 +00:00
James Anderson 4c8399d504 fix(release): publish betas as latest (#2535)
* fix(release): publish betas as latest

* fix(release): promote beta github releases
2026-07-10 09:39:51 +01:00
Lubomir Georgiev (Любомир Георгиев) bbec971d8f fix(app-router): preserve streamed metadata placement parity (#2572)
* fix(app-router): hoist streamed metadata into <head> instead of body

Async generateMetadata was serialized via dangerouslySetInnerHTML into a
hidden <div> in the body, which React cannot hoist. For JS-capable clients
(browsers, Googlebot) the tags stayed in <body>, where Google ignores
rel=canonical, hreflang and robots.

Render the resolved metadata as real <title>/<meta>/<link> elements through
MetadataHead so React 19 hoists them into <head>, matching Next.js. Remove
the now-unused renderMetadataToHtml string serializer.

* Fix tests

* fix(app-router): harden metadata hoisting coverage

* fix(app-router): restore streamed metadata placement

* fix(app-router): preserve static metadata placement

---------

Co-authored-by: James <james@eli.cx>
2026-07-10 09:17:32 +01:00
James Anderson 132d351ed7 chore(deps): upgrade TypeScript to 7.0 (#2577)
* chore(deps): upgrade TypeScript to 7.0

* fix(build): resolve native TypeScript executable
2026-07-09 22:57:23 +01:00
Nathan Nguyen 2c3c0b7d57 fix(app-router): delay dynamic SSR stream pulls (#2575)
Dynamic App SSR currently pipes React's edge stream as soon as the shell resolves. That first pull can flush a Suspense fallback even when the boundary resolves in the next React render task, producing fallback HTML that Next avoids.

The SSR entry now marks successful dynamic streams and awaits one React render task before wiring them through the HTML transform. waitForAllReady, PPR fallback-shell, and recovered shell-error paths keep their existing behavior.

Add a stream-boundary regression that proves immediate consumption leaks the fallback marker while delayed consumption emits only the resolved content.
2026-07-09 22:41:00 +01:00
James Anderson 04850ddb8d ci: restrict compatibility ingest to scheduled Next.js version (#2576) 2026-07-09 18:09:04 +01:00
James Anderson 6734371a59 fix(pages): preserve missing page props on errors (#2568)
* fix(pages): preserve missing page props on errors

* fix(pages): complete default error props contract

* fix(pages): match default error component contract

* fix(pages): complete next error parity

* fix(pages): make next error subclassable

* fix(pages): align next error context types

* fix(pages): isolate error context types

* test(pages): cover default error production hydration

* test(pages): cover default error hydration in dev

* fix(pages): hydrate dev error responses

* fix(pages): set dev error router context

* fix(pages): isolate dev error router state

* fix(pages): align dev error router hydration

* fix(pages): keep error router ready during hydration

* fix(pages): clean up error fallback handling

* fix(pages): load custom error page on navigation

* refactor(pages): share dev hydration entry
2026-07-09 16:23:18 +01:00
James Anderson 555481714c fix(pages): align preview mode behavior (#2561)
* fix(pages): align preview mode behavior

* fix(pages): secure preview mode boundaries

* fix(pages): isolate preview credentials

* fix(pages): unify draft mode credentials

* fix(build): isolate preview credentials per build

* fix(api): align pages draft mode helpers

* fix(pages): address preview review findings

* fix(pages): align preview request types

* fix(pages): export preview data type

* fix(types): align pages API declarations

* fix(types): preserve NextApiRequest augmentation

* fix(pages): align API redirect responses

* fix(types): align API request env runtime

* fix(types): preserve API request env parity

* fix(pages): align dev preview fallback behavior

* fix(pages): scope preview state to data pages

* fix(pages): preserve cookies when clearing preview

* fix(pages): scope preview clear cookie dedupe
2026-07-09 14:41:49 +00:00
James Anderson 7dc85d87ec fix(pages): mark auto exports in next data (#2569)
* fix(pages): mark auto exports in next data

* fix(pages): preserve inherited app optimization
2026-07-09 14:52:11 +01:00
James Anderson 2afe4b6ee6 fix(pages): normalize i18n router URLs (#2565)
* fix(pages): normalize i18n router URLs

* fix(pages): preserve i18n hash link context

* fix(pages): resolve string hash links from asPath

* fix(pages): retain query-only link interpolation

* fix(config): validate i18n default locale

* fix(config): validate i18n before callbacks

* test(config): cover i18n domain validation
2026-07-09 14:50:28 +01:00
James Anderson c265852222 fix(build): gate native typeof window folding (#2574)
* fix(build): gate native typeof window folding

* test(build): share Vite folding version predicate

* fix(build): detect bundled Rolldown folding support

* test(build): prefer bundled Rolldown capability
2026-07-09 11:05:00 +01:00
James Anderson 617bffa95e test(deploy): skip suites that stall deploy shards (#2573)
* test(deploy): skip segment cache memory pressure suite

* test(deploy): skip instant navigation suite
2026-07-09 08:20:55 +00:00
James Anderson b6571ce5f3 perf(build): use native typeof window folding (#2564)
* perf(build): use native typeof window folding

* test(build): tighten typeof window scan plugin
2026-07-08 19:05:23 +01:00
Nathan Nguyen aa1b6663b0 fix(app-router): handle redirects in route-miss fallbacks (#2553)
* fix(app-router): handle redirects in route-miss fallbacks

* test(app-router): fix frozen-lockfile break in not-found-redirect fixture

The route-miss redirect fixture shipped a package.json declaring six
"latest" dependencies (@vitejs/plugin-react, typescript, @types/react*,
vinext, vite) with no matching pnpm-lock.yaml importer. CI runs
frozen-lockfile installs, so every job died at the shared setup step with
ERR_PNPM_OUTDATED_LOCKFILE, turning the whole suite red before a single
test ran.

The fixture never needs those dependencies: dev tests load it via
createServer({ configFile: false }) with the plugin built in code, and
the production test copies it through createIsolatedFixture, which
symlinks the workspace root node_modules. The only file the build
actually reads is package.json's "type": "module" (for ESM output), so
the deps, vite.config.ts, tsconfig.json, and next-env.d.ts were all dead
scaffolding.

Trim package.json to name/private/type, add the empty lockfile importer
so frozen install is satisfied, and delete the unused config files. Also
drop app/result/page.tsx, which .gitignore's bare "result" rule silently
excluded from the commit anyway; the tests only assert the redirect
Location header, never render /result.

* fix(app-router): encode async route-miss redirects in the RSC flight

A redirect() thrown by an async root layout (one that `await headers()`
before redirecting) during a route-miss not-found render was lost on RSC
navigations. renderAppPageBoundaryResponse returns the RSC stream without
consuming it, so the async redirect only surfaced through React's onError
once the stream was pulled — after the synchronous captured-special-error
check had already run and found nothing. The request fell through to a raw
404 flight instead of the 200 flight-encoded redirect the client router
expects. The document path was unaffected because createHtmlResponse
consumes the stream, surfacing the redirect before the same check.

Drain a tee'd copy of the RSC boundary stream to force the render to
settle before the capture check, then hand the buffered copy back as the
body. Boundary responses are small terminal documents, so buffering them
is an acceptable cost for correct redirect handling; the document path is
untouched. Mirrors app-page-render.ts's pre-flush special-error capture.

Also:
- Extract the duplicated redirect-flight encoding (digest format, throwing
  error, stream builder) from app-page-dispatch and app-page-boundary-render
  into app-rsc-redirect-flight.ts as a single owner, with focused unit tests.
- Replace the `new Error(...) as Error & { digest }` cast with a typed
  RscRedirectFlightError subclass, and read the metadata-error marker via
  Reflect.get instead of an `as Record<symbol, unknown>` cast.
- Document that renderBoundarySpecialErrorResponse deliberately omits
  renderFallbackPage: redirects are fully handled, but a notFound()/
  forbidden()/unauthorized() re-thrown inside boundary rendering has no
  parent boundary and terminates with a plain status-text response. Pin
  that terminal behavior with a test.
- Add route-miss RSC redirect coverage (dev + production) asserting the
  200 flight response, text/x-component, and X-Vinext-Rsc-Redirect header.

* test(app-router): prove RSC redirect drain covers matched-route fallbacks

The RSC special-error drain in the HTTP-access fallback path was described
as route-miss-only, but it runs for every http-access fallback: a matched
route's notFound()/forbidden()/unauthorized() renders its boundary through
the same path, where a layout can also async-redirect. Narrowing the drain
to route misses would leave that matched-route case with the original
lazy-stream bug, so the broad behavior is intentional.

Add a matched-route fixture page (`/gated` calls notFound()) and dev +
production coverage: with the redirect trigger the matched-route not-found's
async layout redirect is encoded as a 200 flight; without it the response is
a normal 404 flight, proving the pre-response buffering neither drops nor
corrupts the matched-route payload. Broaden the drain comment to state the
behavior spans route-miss and matched-route fallbacks and why.

* fix(app-router): honor html-limited bots for fallback metadata redirects

A redirect() thrown from generateMetadata() while rendering an HTTP-access
fallback boundary always rode as a 200 streaming response (HTML meta-refresh
/ RSC flight), even for html-limited bots that Next.js serves a blocking 307.
renderBoundarySpecialErrorResponse never passed serveStreamingMetadata, so
buildAppPageSpecialErrorResponse defaulted `serveStreamingMetadata !== false`
to streaming. Matched-page dispatch already threads
shouldServeStreamingMetadata(userAgent, htmlLimitedBots); the fallback path
did not.

Thread htmlLimitedBots into the fallback renderer, compute the same
per-request decision there, and pass serveStreamingMetadata through the
boundary options into the special-error responder. Hoist the entry's
__htmlLimitedBots declaration above __createAppFallbackRenderer (it runs at
module init) to avoid a temporal-dead-zone reference. Cover both branches:
streaming document → 200 meta-refresh, Bingbot → 307 + Location.

Also fix the matched-route drain test so it actually exercises the new path.
The prior test redirected from the root layout, which fires during the
matched-route layout probe and is caught by the layout special-error path
before the fallback renders — so it passed without touching the boundary
drain. Redirect from the route's own not-found boundary instead (on its own
header, so the root layout renders normally and the fallback is reached),
which surfaces through the RSC drain in renderAppPageBoundaryElementResponse.

* fix(app-router): prefix basePath on global-not-found fallback redirects

The global-not-found branch of renderHttpAccessFallback did not pass
basePath/trailingSlash into renderAppPageHttpAccessFallback, while the normal
fallback branch did. renderBoundarySpecialErrorResponse forwards
options.basePath into buildAppPageSpecialErrorResponse, which prefixes
app-internal redirect Locations with the configured base path. So a redirect()
thrown from app/global-not-found.tsx or its generateMetadata() produced an
unprefixed Location under basePath, unlike every other fallback boundary.

Pass basePath and trailingSlash in the global-not-found branch too, matching
the sibling branch. Also refresh the stale renderBoundarySpecialErrorResponse
comment: it described a route-miss-only path and a "root not-found or error
boundary", but the responder now covers matched-route HTTP-access fallbacks
and no longer claims error-boundary handling.

* fix(app-router): preserve fallback redirect semantics

* fix(app-router): preserve push redirect history

---------

Co-authored-by: James <james@eli.cx>
2026-07-08 12:07:22 +01:00
James Anderson 75b9d1a6d8 perf(pages): reuse dev stylesheet dependency analysis (#2550)
* perf(pages): reuse dev stylesheet dependency graph

* perf(build): filter dynamic request transforms natively

* test(pages): harden dependency analysis caching

* refactor(pages): keep dependency cache internal
2026-07-08 11:05:07 +01:00
Nathan Nguyen 7e721b3e53 fix(app-router): preserve semicolons in redirect digests (#2487)
* fix(app-router): preserve raw redirect digest URLs

Redirect digests can carry raw URLs, and raw URLs can contain semicolons. Treating semicolon-delimited URL content as digest structure can truncate or misclassify the redirect target.

Keep redirect digest parsing strict about the final status segment while preserving semicolons in the URL. The server parser stays self-contained so App Router startup does not import the navigation shim.

* fix: simplify malformed redirect digest fallback

* fix: simplify malformed redirect digest fallback

* test: cover malformed redirect digest tails consistently

* fix: restore unstable rethrow cause handling

* fix: guard decodeURIComponent throw and comment status allowlist

- Wrap decodeURIComponent in try/catch for malformed lone % in raw URLs
- Add clarifying comment that only canonical 303/307/308 are extracted
- Both address ask-bonk review feedback from PR #2487

* fix(app-router): preserve raw redirect digest URLs

* fix(app-router): support empty redirect destinations

* docs(app-router): explain redirect digest formats

* docs(app-router): clarify redirect digest parsing

* test(app-router): cover redirect digest re-emission

* docs(app-router): document redirect parser invariants

---------

Co-authored-by: James <james@eli.cx>
2026-07-08 10:55:33 +01:00
Ching Wei Kang 2efac2c02b fix: pass server externals to Nitro traceDeps (#2521)
* fix: pass server externals to Nitro traceDeps

* fix: propagate Nitro externals in dev

---------

Co-authored-by: James <james@eli.cx>
2026-07-07 00:10:41 +01:00
Jerry Zhao 1860632d87 refactor: migrate path handling from node:path to pathslash (#2502)
* refactor: migrate the CLI cluster path handling to pathslash

* refactor(routing): migrate the routing cluster path handling to pathslash

* refactor(plugins): migrate the plugins cluster path handling to pathslash

* refactor(server): migrate the server cluster path handling to pathslash

* refactor(build): migrate the build cluster path handling to pathslash

* refactor(core): migrate entries, config, and shared utils to pathslash

* refactor(plugin): migrate index.ts path handling to pathslash

* refactor: finish the pathslash migration — test sweep, stragglers, lint guard

* refactor: address final-review findings on the pathslash migration

* docs(agents): document the pathslash path-handling convention

* fix(build): emit inlined dependencies outside dist/node_modules

* fix: normalize wire- and bundler-shaped ids unconditionally

* docs(agents): document the unconditional-normalization exception

* fix: gate Windows-shaped path fixtures to Windows

* docs(agents): gate Windows-shaped fixtures with runIf

* refactor: migrate upstream prerender path discovery to pathslash

* fix(create-vinext-app): bundle pathslash into the scaffolder dist

---------

Co-authored-by: James <james@eli.cx>
2026-07-06 23:49:04 +01:00
James Anderson 60ad0b1650 fix(pages): preserve fast refresh state (#2544)
* fix(pages): preserve fast refresh state

* fix(pages): preload transformed dev styles
2026-07-06 23:29:47 +01:00
James Anderson 753c229ef8 fix(build): honor inline next config for static export (#2543)
* fix(build): honor inline next config for static export

* fix(build): reuse resolved config during prerender

* fix(config): resolve promised plugin metadata

* refactor(config): share plugin option flattening

* test(deploy): codify eager config loading

* refactor(deploy): use resolved cache metadata

* refactor(config): remove unused inline loader

* test(config): preserve internal metadata loaders

* refactor(build): keep hybrid plugin extraction unchanged

* refactor(prerender): use resolved next config
2026-07-06 23:15:29 +01:00
Ching Wei Kang d7635d34a6 fix(routing): discover dot-directory routes (#2531) 2026-07-06 23:13:16 +01:00
dependabot[bot] 0862df37ec chore(deps): bump voidzero-dev/setup-vp from 1.13.0 to 1.15.0 (#2548)
Bumps [voidzero-dev/setup-vp](https://github.com/voidzero-dev/setup-vp) from 1.13.0 to 1.15.0.
- [Release notes](https://github.com/voidzero-dev/setup-vp/releases)
- [Commits](https://github.com/voidzero-dev/setup-vp/compare/35171c92dd08b67d5a9d3f2a4327800e58396f2a...250f29ce396baf5e8f24498e17c0dfdebabc26eb)

---
updated-dependencies:
- dependency-name: voidzero-dev/setup-vp
  dependency-version: 1.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-06 19:53:02 +00:00
MK (fengmk2) 2bf68e906b chore(deps): bump vite-plus to v0.2.2 (#2524)
Vite+ is now in beta.
https://voidzero.dev/posts/announcing-vite-plus-beta
2026-07-06 20:49:17 +01:00
Angus Hawkings 7e1ff083da docs(cloudflare): update agent skill deploy commands (#2545) 2026-07-06 14:00:18 +01:00