mirror of
https://github.com/cloudflare/vinext.git
synced 2026-09-14 19:04:59 +08:00
v0.0.49
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3cfccd0bd4 |
fix(deploy): resolve wrangler .CMD shim on Windows (#1098)
* fix(deploy): resolve wrangler .CMD shim on Windows (#1095) `runWranglerDeploy` invoked the bare-name `node_modules/.bin/wrangler` file, which on Windows is a Unix shebang script that CreateProcess() cannot execute, surfacing as a misleading `spawnSync wrangler ENOENT`. Prefer the `.CMD` shim on win32, fall back to the bare name on other platforms (and as an error-message fallback when nothing is found). Extracted bin resolution into an exported, platform-injected `resolveWranglerBin` helper so the behavior is unit-testable without mutating `process.platform`. Fixes #1095 * Apply suggestion from @ask-bonk[bot] Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com> --------- Co-authored-by: James Anderson <james@eli.cx> Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com> |
||
|
|
b94650bcfb |
refactor(app-router): fence AppElements wire-key construction (#1088)
* refactor(app-router): fence AppElements wire-key construction AppElements transport keys could still be constructed or recognized through scattered raw string prefixes outside the wire codec. That kept the flat payload format acting as an informal semantic API and left legacy compatibility behavior covered only by indirect route tests. Make AppElementsWire the exported constructor and parser boundary for route, page, layout, template, slot, cache, metadata, and unmatched-slot wire values. Route graph semantic ID minting stays separate, while render wiring, layout classification, browser slot merging, and prefetch cache tests now consume the codec boundary. Tests cover canonical key construction and parsing, legacy metadata read/write behavior, unmatched-slot marker compatibility, and a source-boundary check that rejects new raw AppElements wire-key construction outside the codec and route graph. * refactor(app-router): address AppElements wire review Make slot-key recognition a cheap structural predicate, document the absolute tree-path parser contract, and broaden the boundary coverage to catch raw wire-key concatenation. Also route layout classification ids through AppElementsWire so raw layout-key construction stays fenced inside the codec boundary. |
||
|
|
15c8079604 |
feat(app-router): add artifact compatibility metadata (#1062)
* feat(app-router): add artifact compatibility envelope App Router payloads now carry a parsed compatibility envelope at the existing payload metadata boundary. Without this skeleton, future cache and skip work would have no typed place to record graph, deployment, schema, root-boundary, or render-epoch proof. Add a small constructor/parser pair, attach a default unknown-proof envelope to outgoing record payloads, and reject malformed envelope metadata when reading payload metadata. Tests cover explicit envelopes, legacy missing envelopes, malformed envelopes, and non-mutating payload writes. * test(app-router): cover future artifact schema rejection The review correctly identified that the envelope parser had malformed-field coverage but no direct test for the version guard path. Add the future-schema-version case and document why the Wave01 skeleton emits separate schema versions and an unknown-proof envelope without yet splitting mismatch from corruption behavior. * feat(app-router): attach artifact compatibility metadata App Router payloads previously carried only the COMPAT-01 unknown envelope unless a caller manually supplied metadata. That left COMPAT-02/03 without concrete graph, deployment, root-boundary, and fallback behavior in the PR. The render lifecycle now attaches compatibility metadata for record payloads from route/root/deployment facts, while renderEpoch remains unknown until an epoch owner exists. The compatibility evaluator returns explicit compatible, unknown, or incompatible decisions so unknown proof always falls back to render fresh instead of becoming reuse proof. Tests cover render-boundary metadata attachment and unknown graph, deployment, root-boundary, and render-epoch decisions. * fix(app-router): tolerate unused compatibility metadata parse failures App Router metadata parsing crashed when __artifactCompatibility was malformed or from a future schema, even though current render and navigation callers do not consume that field yet. The parser treated compatibility scaffolding like required route metadata. That made an unused proof capable of failing initial mount, SSR, and client navigation paths. Default invalid compatibility metadata to the unknown proof for Wave01, document the planned hard-fail point for #726-COMPAT-04/05, and cover malformed, future-version, and non-object payloads. |
||
|
|
e216dab483 |
refactor(app-router): introduce AppElementsWire boundary (#1059)
* refactor(app-router): introduce AppElementsWire boundary App Router payload ownership currently leaks through raw helper calls for route ids, cache keys, metadata writes, and decode paths. That makes the flat AppElements transport act like router semantics instead of a narrow wire boundary, which violates the #726-WIRE-01 ownership target. Introduce AppElementsWire as the single codec facade for AppElements wire encoding, decoding, metadata creation, and outgoing payload shaping. Route the current production encode/decode/write call sites through that facade while keeping the legacy helper names re-exported only where existing tests cover compatibility. * chore(app-router): address AppElementsWire review |
||
|
|
9791a63381 |
feat(app-router): emit per-layout flags in the RSC payload [2/6] (#839)
* feat(app-router): emit per-layout flags in the RSC payload Wire runtime layout classification through renderAppPageLifecycle and attach the resulting flags as __layoutFlags in the outgoing RSC payload via buildOutgoingAppPayload. Payload-shape helpers (withLayoutFlags, isAppElementsRecord, buildOutgoingAppPayload, AppOutgoingElements) live alongside the existing readAppElementsMetadata so the write and read boundaries sit next to each other. * fix(app-elements): widen isAppElementsRecord narrowing and drop redundant clone - isAppElementsRecord narrowed to Record<string, ReactNode>, but the outgoing payload legitimately carries heterogeneous values (ReactNode for the rendered tree plus LayoutFlags under __layoutFlags). Widen the predicate to Readonly<Record<string, unknown>> so the return type matches what the runtime check actually proves. - buildOutgoingAppPayload spread input.element into a new object before passing it to withLayoutFlags, which immediately spreads again. Drop the outer copy; withLayoutFlags already guarantees immutability. * fix(app-router): clear leaked dynamic usage on layout probe errors |
||
|
|
18237955fa |
feat: static/dynamic layout detection for skip-header optimization (#767)
* feat: add classifyLayoutSegmentConfig for layout segment config detection
Reads `export const dynamic` and `export const revalidate` from layout
source files to classify them as static or dynamic. Unlike page
classification, positive revalidate values return null (ISR is a page
concept), deferring to module graph analysis for layout skip decisions.
* feat: add module graph layout classification (Layer 2)
BFS traversal of each layout's dependency tree via Vite's module graph.
If no transitive dynamic shim import (headers, cache, server) is found,
the layout is provably static. Otherwise it needs a runtime probe.
classifyAllRouteLayouts combines Layer 1 (segment config, from prior
commit) with Layer 2 (module graph), deduplicating shared layouts.
* feat: per-layout dynamic detection in probe phase (Layer 3)
Extends probeAppPageLayouts to return per-layout flags ("s"/"d")
alongside the existing Response. Three paths per layout:
- Build-time classified: pass flag through, still probe for errors
- Needs probe: run with isolated dynamic scope, detect usage
- No classification: original behavior (backward compat)
probeAppPageBeforeRender propagates layoutFlags through the result.
renderAppPageLifecycle updated to destructure the new return type.
* feat: add __layoutFlags payload metadata and thread through router state
Adds APP_LAYOUT_FLAGS_KEY to the RSC payload metadata, carrying
per-layout static/dynamic flags ("s"/"d"). readAppElementsMetadata
now parses layoutFlags with a type predicate guard.
AppRouterState and AppRouterAction carry layoutFlags. Navigate merges
flags (preserving previously-seen layouts), replace replaces them.
All dispatchBrowserTree call sites updated to pass layoutFlags.
* refactor: group classification options into single LayoutClassificationOptions type
The three optional fields (buildTimeClassifications, getLayoutId,
runWithIsolatedDynamicScope) had an all-or-nothing invariant enforced
only at runtime. Grouping them into a single optional `classification`
object makes the constraint type-safe — you either provide the full
classification context or nothing.
Also deduplicates the LayoutFlags type: canonical definition lives in
app-elements.ts, re-exported from app-page-execution.ts.
* fix: default to dynamic flag when layout probe throws non-special error
When runWithIsolatedDynamicScope throws and the error is non-special
(onLayoutError returns null), the layout was silently omitted from
layoutFlags. Now conservatively defaults to "d" — if probing failed,
the layout cannot be proven static.
* refactor: replace parallel arrays with LayoutEntry struct, tighten names
- Introduce LayoutEntry (moduleId, treePosition, segmentConfig) in
layout-classification.ts, collapsing the three parallel arrays
(layouts/layoutTreePositions/layoutSegmentConfigs) in
RouteForClassification into a single struct. Switches the inner loop
to for...of, removing the ?? 0 fallback that masked index mismatches.
- Update all five classifyAllRouteLayouts test fixtures to the struct shape.
- Add a JSDoc on LayoutFlags clarifying that "s" = static, "d" = dynamic.
- Tighten the buildTimeClassifications comment to say "keyed by layout index".
https://claude.ai/code/session_01MDJzCNao3dX9tmmVtSqsw5
* style: fix prettier formatting
https://claude.ai/code/session_01MDJzCNao3dX9tmmVtSqsw5
* Revert "style: fix prettier formatting"
This reverts commit
|
||
|
|
b8c44fdd52 |
feat: encode interception context in App Router payload IDs and caches (#753)
* test: add E2E verification for layout persistence flat payload pipeline Prove the flat keyed map architecture works end-to-end: - Layout state persists across sibling navigation (counter survives) - Template remounts on segment boundary change, persists within segment - Error boundary clears on navigate-away-and-back - Back/forward preserves layout state through history - Parallel slots persist on soft nav, show default.tsx on hard nav Zero production code changes — test fixtures and Playwright specs only. * test: harden layout persistence hydration assertions * test: address layout-persistence spec gaps * test: tighten not.toBeAttached() assertions for absent elements * chore: trigger CI * feat: encode interception context in App Router payload IDs and caches * test: update App Router entry snapshots for interception encoding * fix: reuse committed interception context for soft navigations * chore: fix formatting in app-browser-entry after rebase * fix: update mounted-slot test helper calls for 4-arg createResolvedElements signature PR 3 added mounted-slot tests using createResolvedElements(routeId, root, extraEntries). PR 4 inserted interceptionContext as the 3rd param, shifting extraEntries to 4th. The object was being swallowed as interceptionContext, causing getMountedSlotIds to return []. Also add missing renderId to the interception context pending-commit test. * chore: document intentional interception context omission in HMR handler Add a comment to the HMR rsc:update handler noting that interception context is intentionally omitted, matching the existing documentation pattern in the server action handler. https://claude.ai/code/session_01EnvJuSwsZS9n862q7Veamo * fix: prefetch cache test now exercises interception-context partitioning The test was passing pre-computed cache keys as the rscUrl parameter to storePrefetchResponse(), which internally calls createAppPayloadCacheKey again. With the default interceptionContext=null the key passed through unchanged, so the test only verified Map key uniqueness rather than the actual partitioning logic. Pass raw RSC URLs with separate interception context parameters instead. Also add a comment clarifying that PendingNavigationCommit's top-level interceptionContext/rootLayoutTreePath/routeId are convenience aliases for the corresponding action fields. https://claude.ai/code/session_01EnvJuSwsZS9n862q7Veamo * fix: strip NUL bytes from interception context request header Defensively remove \0 from the incoming X-Vinext-Interception-Context header to prevent a malicious client from crafting cache keys that contain the internal NUL separator. https://claude.ai/code/session_01EnvJuSwsZS9n862q7Veamo * fix: resolve rebase conflicts in slot preservation tests After rebase onto upstream main, two fixes needed: - Pass extraEntries as 4th arg to createResolvedElements (3rd is now interceptionContext) - Add missing interceptionContext field to test action objects https://claude.ai/code/session_01EnvJuSwsZS9n862q7Veamo * test: update entry template snapshots for NUL-byte header sanitization https://claude.ai/code/session_01EnvJuSwsZS9n862q7Veamo --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
0dbfeff1af |
feat: flat keyed payload for App Router layout persistence (#750)
* Extract app page route wiring helpers
* Add slot client primitives
* Fix app page error boundary serialization
* Fix client error boundary pathname reset
* Document Next.js error boundary verification
* Implement flat App Router payload for layout persistence
* fix: address review findings in flat payload implementation
- Fix stale closure on readBrowserRouterState by using a useRef updated
synchronously during render instead of a closure captured in
useLayoutEffect. External callers (navigate, server actions, HMR) now
always read the current router state.
- Restore GlobalErrorBoundary wrapping that was dropped when switching
from buildPageElement to buildAppPageElements. Apps with
app/global-error.tsx now get their global error boundary back.
- Add exhaustive default case to routerReducer so new action types
produce a compile error and a runtime throw instead of silent undefined.
- Remove dead code: createRouteNodeSnapshot, AppRouteNodeSnapshot,
AppRouteNodeValue were defined but never imported.
- Remove deprecated buildAppPageRouteElement and its test — no
production callers remain after the flat payload cutover.
- Short-circuit normalizeAppElements when no slot keys need rewriting
to avoid unnecessary allocation on every payload.
- Align test data in error boundary RSC payload test (matchedParams
slug: "post" -> "missing" to match requestUrl /posts/missing).
* fix: normalize flat payload after use(), not before
createFromReadableStream() returns a React thenable whose .then()
returns undefined (not a Promise). Chaining .then(normalizeAppElements)
broke SSR by assigning undefined to flightRoot.
Fix: call use() on the raw thenable, then normalize synchronously
after resolution. Also widen renderAppPageLifecycle element type to
accept flat map payloads.
* fix: produce flat RSC payload on all rendering paths
The SSR entry always expects a flat Record<string, ReactNode> with
__route and __rootLayout metadata from the RSC stream. Three paths
were still producing bare ReactNode payloads:
1. renderAppPageBoundaryElementResponse only created the flat map for
isRscRequest=true, but HTML requests also flow through RSC→SSR
2. buildPageElements "no default export" early return
3. Server action "Page not found" fallback
All three now produce the flat keyed element map, fixing 17 test
failures across 404/not-found, forbidden/unauthorized, error boundary,
production build, rewrite, and encoded-slash paths.
* test: update unit tests for flat RSC payload on all paths
- Update renderElementToStream mock to extract the route element from
the flat map before rendering to HTML (mirrors real SSR entry flow)
- Update entry template snapshots for the buildPageElements changes
* fix: wrap Flight thenable in Promise.resolve() before chaining .then()
createFromReadableStream() returns a React Flight thenable whose
.then() returns undefined instead of a new Promise. The browser
entry's normalizeAppElementsPromise chained .then() on this raw
thenable, producing undefined — which crashed use() during hydration
with "An unsupported type was passed to use(): undefined".
Wrapping in Promise.resolve() first converts the Flight thenable
into a real Promise, making .then() chains work correctly.
The same fix was already applied to the SSR entry in
|