Skip to content

fix(app-router): match streaming metadata error responses#1794

Merged
james-elicx merged 5 commits into
cloudflare:mainfrom
NathanDrake2406:nathan/metadata-streaming
Jun 6, 2026
Merged

fix(app-router): match streaming metadata error responses#1794
james-elicx merged 5 commits into
cloudflare:mainfrom
NathanDrake2406:nathan/metadata-streaming

Conversation

@NathanDrake2406
Copy link
Copy Markdown
Contributor

Overview

Field Value
Goal Match Next.js streaming metadata error handling for redirects and not-found boundaries.
Core change Split metadata-originated redirects by request surface, and resolve fallback head metadata from the selected HTTP access boundary module.
Main boundary RSC requests, streaming document requests, and html-limited bot document requests must not share the same transport response.
Primary files app-page-execution.ts, app-page-dispatch.ts, app-page-boundary-render.ts
Expected impact The upstream metadata-streaming deploy-suite file now passes against vinext.

Why

Metadata errors are not a single response shape in Next.js. A redirect() thrown from generateMetadata() stays encoded as a Flight digest for RSC navigation, becomes an HTML refresh meta tag for streaming-capable document requests, and becomes an HTTP redirect when metadata is blocking for html-limited bots. notFound() from metadata also needs the selected not-found.tsx boundary module to participate in metadata resolution exactly once.

Area Principle / invariant What this PR changes
RSC navigation Client navigation consumes redirect digests from Flight. Keeps RSC metadata redirects in the Flight payload path.
Document streaming Streaming metadata errors are inserted into HTML, not serialized as a standalone Flight response. Emits the canonical __next-page-redirect refresh meta tag for streaming document redirects.
Html-limited bots Metadata blocks, so redirect/not-found errors affect the HTTP response status. Threads htmlLimitedBots into dispatch and falls through to HTTP 307/308 when streaming metadata is disabled.
Not-found metadata The chosen boundary file is part of the metadata contract. Passes the selected fallback boundary module into head resolution so the title is rendered once.

What changed

Scenario Before After
generateMetadata() redirect, RSC request 200 Flight redirect digest unchanged
generateMetadata() redirect, streaming document request 200 text/x-component Flight payload 200 HTML with Next-style refresh meta tag
generateMetadata() redirect, html-limited bot 200 response 307/308 HTTP redirect with Location
generateMetadata() not-found into a route boundary Boundary UI rendered but boundary metadata was omitted Boundary metadata contributes exactly once
Maintainer review path
  1. packages/vinext/src/server/app-page-execution.ts for the transport split in metadata redirect responses.
  2. packages/vinext/src/server/app-page-dispatch.ts and packages/vinext/src/entries/app-rsc-entry.ts for htmlLimitedBots propagation into the runtime decision.
  3. packages/vinext/src/server/app-page-boundary.ts and app-page-boundary-render.ts for resolving the selected HTTP access boundary module separately from its default component.
  4. tests/app-page-execution.test.ts, tests/app-page-boundary-render.test.ts, and tests/app-router-dev-server.test.ts for the ported behavioural contracts.
Validation
  • vp check
  • vp test run tests/app-page-execution.test.ts tests/app-page-boundary-render.test.ts
  • vp test run tests/app-router-dev-server.test.ts -t "redirect\\(\\) from generateMetadata"
  • Pre-commit hook ran entry-template checks, staged checks, staged tests, and knip.
  • vp env exec --node 24 ./scripts/run-nextjs-deploy-suite.sh /Users/nathan/Projects/vinext/.refs/nextjs-v16.2.6 --retries 0 -c 1 --debug test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts
Risk / compatibility
  • Public API impact: none.
  • Runtime impact: app-router metadata error handling only.
  • RSC compatibility: RSC navigation redirects remain encoded as Flight digests.
  • Browser compatibility: direct document visits now receive HTML, which lets the browser follow the refresh meta tag as in Next.js.
  • Bot compatibility: html-limited bots now get blocking redirect status for metadata redirects.
Non-goals
  • This does not change general page-level redirect() or notFound() semantics outside metadata.
  • This does not change global metadata resolution order beyond the selected HTTP access boundary module participating in fallback head rendering.

References

Reference Why it matters
Next.js metadata-streaming e2e test Source of the ported deploy-suite behaviours.
Next.js metadata component wiring Shows metadata errors are rethrown through the outlet while the metadata tree itself renders null for captured special errors.
Next.js server-inserted HTML metadata errors Defines the __next-page-redirect refresh meta tag emitted for streamed redirect errors.
Next.js app render error handling Shows blocking redirect/not-found status handling during non-streaming metadata.
Next.js streaming metadata bot decision Defines when metadata should stream versus block for html-limited bots.
Next.js metadata resolution for error conventions Shows not-found convention metadata is collected as part of the error render.
Next.js generateMetadata docs Documents streaming metadata behaviour and the html-limited bot exception.

Vinext currently serializes metadata-originated redirects into a Flight payload for document requests. That response is not an HTML page, so direct browser visits cannot follow the streamed redirect and html-limited bots receive 200 instead of the blocking redirect.

The dispatcher also renders HTTP access fallback head metadata from layouts only, so not-found boundary metadata is omitted when generateMetadata() throws notFound().

Use Next.js's split response model: RSC requests keep the Flight redirect digest, streaming-capable document requests receive the refresh meta tag HTML, and html-limited bots fall through to the HTTP redirect. Thread the selected HTTP access boundary module into fallback rendering so boundary metadata is resolved exactly once.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 6, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@1794
npm i https://pkg.pr.new/vinext@1794

commit: 75d91fb

@NathanDrake2406 NathanDrake2406 marked this pull request as draft June 6, 2026 11:33
The unit CI failure came from a strict dispatch test receiving optional fallback fields with undefined or null values. Those fields are only meaningful when a boundary module is actually selected.

Build fallback option objects without absent boundary fields, preserving the existing call shape for ordinary page-level HTTP access fallbacks.

Add focused coverage for fromMetadata redirects on RSC requests so metadata document refresh handling cannot accidentally consume the client navigation Flight path.
@NathanDrake2406 NathanDrake2406 marked this pull request as ready for review June 6, 2026 13:27
@james-elicx
Copy link
Copy Markdown
Member

/bigbonk review for issues

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the metadata streaming error split. The transport split (RSC → Flight digest, streaming document → HTML refresh meta tag, html-limited bot → blocking 307) is correctly threaded through dispatch and the boundary-module metadata resolution looks right (verified resolveAppPageHead now receives pageModule: boundaryModule, and the new renderAppPageHttpAccessFallback self-resolves the boundary module for the non-layout-aligned not-found.tsx case). Cookie/header handling on the new HTML response is consistent with the existing Flight and 307 paths.

One correctness-adjacent issue: a pre-existing docblock just above this hunk is now factually wrong after this change (it still claims metadata redirects never become a 307 and always ride in the flight payload). Since this PR is the thing that invalidates it, it should be updated here to avoid misleading future readers. Details inline. Two minor notes as well.

// 2. `generateMetadata()` redirects — metadata is suspended in Next.js,
// so the redirect rides inside the streamed flight payload even for
// full document SSR. The status line stays 200.
// Document requests that redirect from `generateMetadata()` are HTML
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docblock for APP_PAGE_METADATA_ERROR_MARKER (lines 39-50, just above this hunk, not shown in the diff) is now stale and contradicts this PR:

Metadata resolution is suspended/streamed in Next.js, so a redirect from metadata never becomes an HTTP-level 307 — it rides inside the flight payload with a 200 status, regardless of whether the request is RSC or a full document SSR.

After this change that is no longer true: document requests get an HTML refresh meta tag (not a flight payload), and html-limited bots get a blocking 307. Since this PR is what invalidates the comment, please update it (and the metadata-navigation test reference) in the same PR so the marker's documentation matches the new transport split.

const boundaryComponent =
options.boundaryComponent ??
getDefaultExport(boundaryModule) ??
resolveAppPageHttpAccessBoundaryComponent({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: when options.boundaryComponent and options.boundaryModule are both unset, getDefaultExport(boundaryModule) (line 310) and resolveAppPageHttpAccessBoundaryComponent(...) (line 311) compute the same component — boundaryModule is resolvedBoundaryModule, which resolveAppPageHttpAccessBoundaryComponent derives via the same resolveAppPageHttpAccessBoundaryModule call. The fallback to resolveAppPageHttpAccessBoundaryComponent is now effectively dead for the resolved-module path. Not a bug, but you could drop line 311's branch (or keep it only for the explicit-boundaryComponent case) to avoid the duplicate resolution.

}

const errorMetaTags = renderSsrErrorMetaTags([{ digest: options.digest }]);
return new Response(`<!DOCTYPE html><html><head>${errorMetaTags}</head><body></body></html>`, {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The streaming-redirect document is a minimal stub (<head> with only the refresh meta tag, empty <body>), whereas Next.js inserts the __next-page-redirect tag into the otherwise-rendered streamed document. For a redirect this is functionally fine (the browser follows the refresh regardless of body), but worth a one-line note here that this intentionally diverges from Next.js's full-document insertion, so a future reader doesn't assume page content was dropped by mistake.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Jun 6, 2026

Review submitted successfully. Here's a summary of my review of PR #1794:

Review Summary

The PR correctly implements the metadata streaming error transport split. I verified the core mechanics:

Correct:

  • The three-way split (RSC → Flight digest, streaming document → HTML refresh meta tag, html-limited bot → blocking 307) is properly threaded through app-page-dispatch.ts via serveStreamingMetadata/shouldServeStreamingMetadata.
  • htmlLimitedBots propagation from the RSC entry → dispatch options is wired correctly (build-time injected __htmlLimitedBots, so prod is covered too).
  • Boundary-module metadata fix: renderAppPageHttpAccessFallback now self-resolves the boundary module and passes it as pageModule to resolveAppPageHead, fixing the missing not-found boundary metadata. Verified Twitterbot is in the html-limited bot regex.
  • Cookie/header handling on the new HTML response (Set-Cookie, middleware headers, edge runtime) is consistent with the existing Flight and 307 paths.
  • serveStreamingMetadata === false correctly falls through to the 307 path; basePath is not double-applied (digest URL already prefixed, meta-tag renderer called without basePath).

Findings posted (1 main + 2 minor):

  1. Stale docblock (app-page-execution.ts:39-50) — the APP_PAGE_METADATA_ERROR_MARKER comment still claims metadata redirects "never become an HTTP-level 307" and "ride inside the flight payload regardless of RSC or document SSR." This PR invalidates that statement and should update it in the same change.
  2. Minor: redundant boundary-component resolution in app-page-boundary-render.ts (the resolveAppPageHttpAccessBoundaryComponent fallback is now effectively dead for the resolved-module path).
  3. Minor: the stub HTML redirect document diverges from Next.js's full-document insertion — fine for redirects, but worth a clarifying comment.

No blocking correctness bugs found.

github run

…ad boundary fallback

Address review feedback on the metadata streaming error split:
- Update the stale APP_PAGE_METADATA_ERROR_MARKER docblock to describe the
  new three-way transport split (flight digest / HTML refresh meta tag / 307).
- Note the intentional minimal-stub HTML divergence from Next.js's
  full-document insertion in buildMetadataRedirectHtmlResponse.
- Drop the redundant resolveAppPageHttpAccessBoundaryComponent fallback in
  renderAppPageHttpAccessFallback (boundaryModule already covers both paths).
@james-elicx
Copy link
Copy Markdown
Member

/bigbonk re-review for issues

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after f41090c. The two prior findings (the stale app-page-execution.ts docblock and the redundant boundary-component resolution) are resolved, and the divergence comment for the stub HTML redirect is now in place.

Verified correct:

  • Transport split (RSC → Flight digest, streaming document → HTML refresh meta tag, html-limited bot → blocking 307) is correctly threaded through dispatch via serveStreamingMetadata/shouldServeStreamingMetadata.
  • Build-time __htmlLimitedBots injection covers prod, not just dev.
  • basePath is applied exactly once: the digest URL is pre-prefixed via sameOriginPathOrAbsolute(prefixedLocation, …) and renderSsrErrorMetaTags is called without a basePath option, so no double-prefix.
  • escapeHtmlAttr guards the refresh URL in the meta tag.
  • serveStreamingMetadata !== false defaults to HTML refresh when unset, and both prod callers (renderLayoutSpecialError, renderPageSpecialError) pass the computed flag — consistent with app-page-element-builder.ts:206-213 placing metadata in head (blocking) for html-limited bots, which is what surfaces the redirect synchronously.
  • Not-found boundary metadata fix (pageModule: boundaryModule into resolveAppPageHead) renders the title exactly once; verified by the new test and that pageModule is a distinct metadata source from layoutModules.
  • resolveAppPageHttpAccessBoundaryComponent still exported/tested; refactor is functionally equivalent.
  • Cookie/middleware-header handling on the new HTML response matches the Flight and 307 paths.

Targeted tests pass locally (tests/app-page-execution.test.ts, tests/app-page-boundary-render.test.ts, tests/app-page-boundary.test.ts).

Two remaining doc nits (no inline anchor — the lines fall outside the diff hunks):

  1. (net-new — the prior review missed this file) packages/vinext/src/server/app-page-head.ts:22-26 — the resolveModuleMetadata docblock still asserts metadata redirects "ride inside the flight payload with a 200 status code even for document SSR." This PR invalidates that exact statement: document SSR now returns an HTML refresh meta tag, and html-limited bots return a blocking 307. This is the same factual error the prior review flagged in app-page-execution.ts, but in a file that review didn't examine. Suggested rewrite:
 * suspended/streamed in Next.js. Its redirects no longer become a plain
 * HTTP 307: RSC navigation rides inside the flight payload (200), streaming
 * document SSR gets an HTML refresh meta tag (200), and html-limited bots
 * get a blocking 307 — whereas page redirects still emit a 307 for SSR.
 * See https://github.com/cloudflare/vinext/issues/1347
 * and Next.js test/e2e/app-dir/metadata-streaming.
  1. packages/vinext/src/server/app-page-execution.ts:54-56 — the docblock body was correctly rewritten to describe the three transports, but the See Next.js test reference still points at metadata-navigation. Since the behavioural contracts here are ported from metadata-streaming, the reference should follow:
 * See Next.js test:
 *   test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts

Neither is a correctness bug — both are stale comments that will mislead future readers about the transport behavior this PR establishes. No blocking issues found.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Jun 6, 2026

Review submitted successfully.

Summary

I re-reviewed PR #1794 after the latest commit (f41090c) that addressed the prior review.

Resolved from prior review:

  • Stale app-page-execution.ts docblock body — rewritten correctly
  • Redundant boundary-component resolution — cleaned up
  • Divergence comment for the stub HTML redirect — added

Verified correct (no blocking bugs):

  • The three-way transport split (RSC → Flight digest, streaming document → HTML refresh meta tag, html-limited bot → blocking 307) is properly threaded through dispatch
  • __htmlLimitedBots is build-time injected, so prod is covered
  • basePath applied exactly once (no double-prefix)
  • escapeHtmlAttr guards the refresh URL
  • serveStreamingMetadata flag is consistent with head/body metadata placement in the element builder
  • Not-found boundary metadata fix renders the title exactly once
  • Cookie/middleware-header handling consistent across all three response paths
  • Targeted tests pass locally

New findings (2 doc nits, neither blocking):

  1. Net-newapp-page-head.ts:22-26 has the same stale docblock the prior review flagged in app-page-execution.ts, but in a file the previous review never examined. It still claims metadata redirects "ride inside the flight payload with a 200 status code even for document SSR," which this PR invalidates.
  2. app-page-execution.ts:54-56 — the docblock body was updated, but the See Next.js test reference still points at metadata-navigation instead of the metadata-streaming test this PR was ported from.

Both are stale comments that would mislead future readers. I posted suggested rewrites as a top-level review (inline anchoring failed with 422 because both docblocks fall outside the diff hunks).

github run

@james-elicx
Copy link
Copy Markdown
Member

/bigbonk

Addressed all three review findings in f41090c:

  1. Updated the stale APP_PAGE_METADATA_ERROR_MARKER docblock to describe the new three-way transport split (RSC flight digest / HTML refresh meta tag / blocking 307).
  2. Added a note in buildMetadataRedirectHtmlResponse documenting the intentional minimal-stub divergence from Next.js's full-document insertion.
  3. Dropped the dead resolveAppPageHttpAccessBoundaryComponent fallback in renderAppPageHttpAccessFallback (boundaryModule already covers both paths) and removed the now-unused import.

Please re-review.

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed f41090c. The three prior findings from the original review are correctly resolved:

  1. APP_PAGE_METADATA_ERROR_MARKER docblock (app-page-execution.ts:39-52) — rewritten to describe the three-way transport split accurately.
  2. buildMetadataRedirectHtmlResponse divergence note (app-page-execution.ts:320-324) — clear comment added explaining the intentional minimal-stub vs. Next.js full-document insertion.
  3. Dead resolveAppPageHttpAccessBoundaryComponent fallback (app-page-boundary-render.ts:306-312) — removed; boundaryComponent now derives from getDefaultExport(boundaryModule) as the single source of truth, and the unused import is gone.

Verified correct (no blocking bugs)

  • The transport split in buildAppPageSpecialErrorResponse is sound: fromMetadata && !isRscRequest && serveStreamingMetadata !== false -> HTML refresh meta tag; isRscRequest -> Flight digest; everything else (including serveStreamingMetadata === false) -> blocking 307. The early-return ordering means html-limited bots fall through to the 307 path correctly.
  • __htmlLimitedBots is build-time injected via JSON.stringify in app-rsc-entry.ts:511, so prod is covered, not just dev. It's threaded into both renderLayoutSpecialError and renderPageSpecialError.
  • shouldServeStreamingMetadata (used in dispatch) is consistent with app-page-element-builder.ts:206-213, which places metadata in head (blocking) for html-limited bots — that's what surfaces the redirect synchronously.
  • boundaryComponent/boundaryModule are always paired at every call site (both dispatch closures and both app-fallback-renderer.ts paths), so there's no risk of a mismatched component/module feeding the wrong metadata into resolveAppPageHead.
  • { digest } is consumed correctly by renderSsrErrorMetaTags -> getNextErrorDigest, and escapeHtmlAttr guards the refresh URL.
  • Cookie/middleware-header handling on the new HTML response matches the Flight and 307 paths.

Two remaining doc nits (non-blocking)

Both were flagged in the prior re-review and are still present in f41090c. Both fall outside the diff hunks, so I could not anchor them inline (the inline attempt returned 422). Neither blocks merge, but they are stale comments that will mislead future readers about the transport behavior this PR establishes.

1. packages/vinext/src/server/app-page-head.ts:23-26 — the resolveModuleMetadata docblock still asserts metadata redirects "ride inside the flight payload with a 200 status code even for document SSR." This PR invalidates that exact statement (document SSR now returns an HTML refresh meta tag; html-limited bots return a blocking 307). Same factual error that was fixed in app-page-execution.ts, just in a sibling file. Suggested rewrite:

 * suspended/streamed in Next.js. Its redirects no longer become a plain
 * HTTP 307: RSC navigation rides inside the flight payload (200), streaming
 * document SSR gets an HTML refresh meta tag (200), and html-limited bots
 * get a blocking 307 — whereas page redirects still emit a 307 for SSR.
 * See https://github.com/cloudflare/vinext/issues/1347
 * and Next.js test/e2e/app-dir/metadata-streaming.

2. packages/vinext/src/server/app-page-execution.ts:54-56 — the docblock body was correctly rewritten to describe all three transports, but the See Next.js test reference still points at metadata-navigation. The behavioural contracts here are ported from metadata-streaming (per the PR description and the new tests), so the reference should follow:

 * See Next.js test:
 *   test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts

No blocking issues found.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Jun 6, 2026

Review submitted successfully.

Summary

I re-reviewed PR #1794 after commit f41090c, which addressed the three findings from the prior review.

Resolved from prior review (verified):

  • APP_PAGE_METADATA_ERROR_MARKER docblock — rewritten to accurately describe the three-way transport split
  • buildMetadataRedirectHtmlResponse — divergence note added explaining the intentional minimal-stub vs. Next.js full-document insertion
  • Dead resolveAppPageHttpAccessBoundaryComponent fallback — removed; boundaryComponent now derives from getDefaultExport(boundaryModule) and the unused import is gone

Verified correct (no blocking bugs):

  • The transport split logic in buildAppPageSpecialErrorResponse is sound — html-limited bots correctly fall through to the 307 path via early-return ordering
  • __htmlLimitedBots is build-time injected, covering prod; threaded into both special-error renderers
  • shouldServeStreamingMetadata is consistent with the element builder's head/body metadata placement
  • boundaryComponent/boundaryModule are always paired at every call site, so no risk of feeding mismatched metadata into resolveAppPageHead
  • Cookie/middleware-header handling on the new HTML response matches the Flight and 307 paths

Two remaining non-blocking doc nits (both flagged in the prior re-review, both still present; they fall outside the diff hunks so inline anchoring returned 422):

  1. app-page-head.ts:23-26 — still claims metadata redirects "ride inside the flight payload with a 200 status code even for document SSR," which this PR invalidates
  2. app-page-execution.ts:54-56 — the See Next.js test reference still points at metadata-navigation instead of the metadata-streaming test this PR ports from

No blocking issues found.

github run

…nd test reference

Address remaining bonk re-review nits:
- Update resolveModuleMetadata docblock in app-page-head.ts to describe the
  three-way transport split (it still claimed redirects ride in the flight
  payload even for document SSR).
- Point the APP_PAGE_METADATA_ERROR_MARKER Next.js test reference at
  metadata-streaming, which is where the behavioural contracts are ported from.
@james-elicx
Copy link
Copy Markdown
Member

/bigbonk

Addressed the two remaining doc nits in a1e749c:

  1. Updated the resolveModuleMetadata docblock in app-page-head.ts to describe the three-way transport split (RSC flight digest / HTML refresh meta tag / blocking 307) instead of claiming redirects always ride in the flight payload for document SSR.
  2. Pointed the APP_PAGE_METADATA_ERROR_MARKER Next.js test reference at metadata-streaming instead of metadata-navigation.

Please re-review.

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed a1e749cd. Both remaining doc nits from the prior re-review are now resolved.

Resolved (verified):

  1. packages/vinext/src/server/app-page-head.ts:23-28 — the resolveModuleMetadata docblock no longer claims metadata redirects "ride inside the flight payload with a 200 status code even for document SSR." It now describes the three-way transport split accurately (RSC flight digest 200 / streaming document HTML refresh meta tag 200 / html-limited bot blocking 307) and the See reference points at metadata-streaming.
  2. packages/vinext/src/server/app-page-execution.ts:54-55 — the See Next.js test reference now points at test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts, matching the behavioural contracts this PR ports.

No blocking issues. The docblocks are now consistent with the transport split this PR establishes. LGTM.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented Jun 6, 2026

Re-review submitted. Both remaining doc nits from the prior review are resolved in a1e749cd:

  1. app-page-head.ts:23-28 — the resolveModuleMetadata docblock no longer claims metadata redirects ride inside the flight payload for document SSR. It now describes the three-way split (RSC flight digest 200 / streaming document HTML refresh meta tag 200 / html-limited bot blocking 307) and references metadata-streaming.

  2. app-page-execution.ts:54-55 — the See Next.js test reference now points at test/e2e/app-dir/metadata-streaming/metadata-streaming.test.ts.

No blocking issues. The docblocks are now consistent with the transport split the PR establishes. LGTM.

github run

@james-elicx james-elicx enabled auto-merge (squash) June 6, 2026 23:38
@james-elicx james-elicx merged commit bc31644 into cloudflare:main Jun 6, 2026
39 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants