Next.js's loader-tree dynamic-segment tuple includes a `staticSiblings`
list (the static sibling segment names at the dynamic URL level) so the
client router can decide whether a cached prefetch of a dynamic route
can be reused when navigating to a static sibling URL. vinext was not
emitting this metadata, so the static-siblings e2e suite failed all four
substring assertions against the RSC payload.
This change:
- Adds `computeAppRouteStaticSiblings(allRoutes, matchedRoute)` to the
app route graph. Ported from Next.js's `getStaticSiblingSegments` in
the next-app-loader. For each dynamic URL level in the matched route,
it collects the names of routes whose corresponding segment is
static and whose preceding URL prefix matches literally.
- Pre-computes the result per route at entry-generator time
(`buildRouteEntries` in app-rsc-manifest) so the runtime carries a
static list instead of recomputing for every request.
- Threads it through `AppPageRouteWiringRoute` and emits it on the
wire as a new `__staticSiblings` metadata key when non-empty. The
Flight serializer already spreads the elements record into the
outgoing payload, so the key lands on the RSC response unchanged.
The new `tests/app-static-siblings.test.ts` covers the helper's
sibling-collection rules (cross-route-group, same-directory, deeply-
nested non-leak, dedup) and asserts `buildAppPageElements` emits
`__staticSiblings` on dynamic routes and omits it when empty — matching
the four sub-cases of Next.js's static-siblings e2e suite.
Ported from Next.js:
test/e2e/app-dir/static-siblings/static-siblings.test.ts
Refs cloudflare/vinext#1328