* test(app-router): reproduce deployed optimistic search navigation stall
Add a production-shaped provider filter that combines useOptimistic with same-path search navigation and streamed server results. Cover local controls and run a bounded provider cycle against the deployed Workers example, where the intermittent commit failure occurs.\n\nRefs #2865.
* test(app-router): reproduce local optimistic navigation stall
* fix(app-router): settle optimistic search navigations
* fix(app-router): preserve streaming during optimistic recovery
---------
Co-authored-by: Nathan Nguyen <146415969+NathanDrake2406@users.noreply.github.com>
* test(app-router): reproduce shared layout teardown on soft navigation
Add a `/layout-identity` fixture to the app-router-cloudflare example and
e2e coverage showing that a shared `[slug]` layout is discarded during a
soft navigation that only changes segments below it.
The fixture pairs the shared layout with a `loading.tsx` boundary above
it, a parallel slot beside `children`, and a nested dynamic segment with
its own layout, matching the shape a real app has. Removing the
`loading.tsx` boundary makes every assertion pass, which isolates it as
the trigger.
The five layout-identity assertions fail on main; the soft-navigation
control passes, so the teardown is the router discarding a layout it
should have retained rather than a full document load.
* fix(app-router): retain shared layouts across loading shells
* fix(app-router): preserve omitted slot segment identity
* test(app-router): follow shared param canonicalizer
* fix(build): preserve server conditions on Workers
* fix(build): filter browser from all server graphs
* refactor(build): rename server conditions plugin
* fix(pages): keep charset first in custom document heads
* fix(pages): preserve complete head ordering parity
* test(pages): assert dev document head ordering
* fix(pages): preserve head order across Fast Refresh
* fix(pages): align trace metadata head ordering in dev
* fix(pages): match Next head manager updates
* fix(pages): order unknown head tags last
---------
Co-authored-by: James <james@eli.cx>
* fix(app-router): preserve request.cf in route handlers
Cloudflare Workers attaches request.cf at the inbound request boundary, but App Router dispatch rebuilt Route Handler requests with the standard Request constructor and discarded that runtime metadata.\n\nUse the existing metadata-preserving URL clone boundary so both Node and Edge Route Handlers retain cf while keeping their current URL normalization semantics.
* fix(app-router): preserve request.cf through runtime wrapping
Route Handler request tracking can rebuild an already-normalized request when restoring basePath or applying middleware header overrides. Those reconstructions discarded Cloudflare metadata before the final NextRequest reached user code.\n\nPreserve cf at both reconstruction points while retaining the existing body-transfer and RequestInit behavior, with runtime-level coverage for each path.
* fix(app-router): treat request.cf as dynamic state
Preserving Cloudflare request metadata makes request.cf observable to Route Handlers, but the request proxy did not classify reads as dynamic. Geo-dependent responses could therefore enter the route-wide ISR cache, while static route modes exposed request-specific metadata.\n\nApply the existing ip and geo policy to cf: track reads in automatic mode, hide it under force-static, and reject it under dynamic error mode.
* fix(app-router): preserve request.cf across clones
Tracked Route Handler requests inherit the standard Request clone implementation, which omits Cloudflare request metadata. A handler that cloned before reading cf therefore lost the metadata even though the original tracked request retained it.\n\nCentralize tracked request cloning so cf is reattached before the clone is recursively wrapped with the same dynamic request policy.
* fix(app-router): track reflective request.cf access
Tracked Route Handler requests enforced dynamic policy only through the Proxy get trap. Descriptor, membership, and key-enumeration reads could expose Cloudflare metadata without marking the handler dynamic or respecting static modes.
Route explicit cf reflection through the same policy, filtering configurable cf keys under force-static and rejecting reflective access under dynamic error mode.
* fix(app-router): retain request proxy through valueOf
Binding every Request method to the underlying NextRequest let valueOf return the raw target. Subsequent request.cf reads could then bypass dynamic tracking and static-mode policy.
Bind valueOf to the proxy receiver while leaving branded Request methods on the underlying target, and cover the escape in all three request modes.
* fix(app-router): bind reflection to request proxy
Inherited Object reflection helpers were still bound to the raw NextRequest, allowing ownership checks to bypass request.cf dynamic policy.
Bind exact Object.prototype methods to the proxy receiver while preserving the branded target for Web Request methods, and cover ownership and enumerability checks in every request mode.
* fix(app-router): preserve proxy for request extensions
Binding unknown request properties to the raw NextRequest let user-defined methods and getters bypass request.cf policy.
Snapshot the runtime's built-in Request surface for branded target access while keeping own and unknown extensions on the proxy receiver. Cover both method and accessor escapes in every request mode.
* fix(app-router): hide cf before locking requests
Force-static proxies filtered request.cf from reflective operations, but a non-extensible target made that omission violate Proxy invariants.
Remove the configurable metadata before preventing extensions, and cover preventExtensions, seal, and freeze while preserving force-static policy.
* fix(app-router): bind Worker request members correctly
Cloudflare may expose Web IDL Request members as own properties, so classifying every own member as a user extension caused illegal invocation errors in Workers.
Use the captured built-in API surface regardless of property placement, while keeping unknown extension names on the proxy receiver. Add coverage for an own branded accessor.
* fix(app-router): distinguish request member shadows
Name-only branded member detection fixed Workers own-property layouts but treated post-wrap user shadows as runtime Web IDL members, allowing their this-based reads to escape the proxy.
Snapshot runtime-owned descriptors before route code receives the request and bind only unchanged implementations to the target. Later shadows retain the proxy receiver in every request mode.
* fix(app-router): detect request prototype shadows
Own-descriptor snapshots still treated replaced inherited Request members as branded, allowing prototype getters to bypass request.cf policy.
Snapshot each resolved built-in implementation and compare the currently resolved descriptor before selecting the raw target. Own and prototype shadows now retain the tracked receiver.
* fix(app-router): snapshot request built-ins before routes
* fix(app-router): preserve branded Worker request methods
* fix(app-router): preserve reflected cf after locking
* refactor(app-router): contain request.cf policy on its target
Route handlers need Workers metadata to follow static-generation policy without changing the semantics of every Request property. Use the configurable cf accessor copied onto NextRequest as the single policy boundary, and delegate request reconstruction to the canonical clone helpers.
* fix(app-router): avoid synthesizing absent request.cf
Ordinary requests should not gain an own cf property merely because route-handler dynamic tracking is active. Install the target accessor only when Workers metadata exists, while keeping direct absent reads subject to automatic, force-static, and error policy.
* fix(app-router): harden request.cf tracking
* chore(test): register worker route fixtures
* chore(app-router): deduplicate request.cf descriptor
---------
Co-authored-by: James <james@eli.cx>