vinext 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +5 -2
  2. package/THIRD_PARTY_LICENSES.md +47 -0
  3. package/dist/_virtual/_rolldown/runtime.js +3 -2
  4. package/dist/build/prerender.js +1 -1
  5. package/dist/build/report.d.ts +0 -14
  6. package/dist/build/report.js +1 -51
  7. package/dist/check.js +1 -1
  8. package/dist/cli.js +3 -0
  9. package/dist/client/dev-error-overlay.js +1 -1
  10. package/dist/client/navigation-runtime.d.ts +13 -1
  11. package/dist/client/navigation-runtime.js +1 -1
  12. package/dist/config/next-config.d.ts +19 -0
  13. package/dist/config/next-config.js +64 -1
  14. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
  15. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
  16. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
  17. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
  18. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
  19. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
  20. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
  21. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
  22. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
  23. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
  24. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
  25. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
  26. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
  27. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
  28. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
  29. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
  30. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
  31. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
  32. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
  33. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
  34. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
  35. package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
  36. package/dist/entries/app-rsc-entry.js +17 -48
  37. package/dist/entries/app-rsc-manifest.js +3 -4
  38. package/dist/entries/app-ssr-entry.js +1 -0
  39. package/dist/entries/pages-server-entry.js +33 -8
  40. package/dist/index.js +83 -70
  41. package/dist/init-cloudflare.d.ts +1 -3
  42. package/dist/init-cloudflare.js +10 -48
  43. package/dist/init-platform.d.ts +2 -0
  44. package/dist/init-platform.js +4 -0
  45. package/dist/plugins/extensionless-dynamic-import.js +6 -2
  46. package/dist/plugins/next-intl-catalog.d.ts +12 -0
  47. package/dist/plugins/next-intl-catalog.js +85 -0
  48. package/dist/plugins/pages-node-externals.d.ts +1 -0
  49. package/dist/plugins/pages-node-externals.js +1 -1
  50. package/dist/plugins/use-cache-callable.d.ts +1 -1
  51. package/dist/plugins/use-cache-callable.js +136 -94
  52. package/dist/routing/app-route-graph.d.ts +6 -0
  53. package/dist/routing/app-route-graph.js +9 -1
  54. package/dist/server/api-handler.js +19 -4
  55. package/dist/server/app-bfcache-identity.js +1 -1
  56. package/dist/server/app-browser-entry.js +79 -63
  57. package/dist/server/app-browser-history-controller.d.ts +5 -4
  58. package/dist/server/app-browser-history-controller.js +93 -15
  59. package/dist/server/app-browser-navigation-controller.d.ts +2 -2
  60. package/dist/server/app-browser-navigation-controller.js +1 -2
  61. package/dist/server/app-browser-rsc-redirect.js +4 -4
  62. package/dist/server/app-browser-server-action-client.d.ts +2 -0
  63. package/dist/server/app-browser-server-action-client.js +4 -3
  64. package/dist/server/app-browser-state.d.ts +2 -4
  65. package/dist/server/app-browser-state.js +9 -4
  66. package/dist/server/app-browser-supplemental-refresh.js +16 -1
  67. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  68. package/dist/server/app-browser-visible-commit.js +2 -12
  69. package/dist/server/app-elements-wire.d.ts +6 -38
  70. package/dist/server/app-elements-wire.js +4 -41
  71. package/dist/server/app-elements.d.ts +2 -2
  72. package/dist/server/app-elements.js +2 -2
  73. package/dist/server/app-history-state.d.ts +2 -2
  74. package/dist/server/app-history-state.js +5 -2
  75. package/dist/server/app-mounted-layouts.d.ts +21 -0
  76. package/dist/server/app-mounted-layouts.js +67 -0
  77. package/dist/server/app-optimistic-routing.d.ts +19 -1
  78. package/dist/server/app-optimistic-routing.js +42 -2
  79. package/dist/server/app-page-boundary-render.js +7 -6
  80. package/dist/server/app-page-boundary.js +2 -2
  81. package/dist/server/app-page-cache-finalizer.d.ts +12 -1
  82. package/dist/server/app-page-cache-finalizer.js +70 -29
  83. package/dist/server/app-page-cache.d.ts +13 -1
  84. package/dist/server/app-page-cache.js +31 -9
  85. package/dist/server/app-page-dispatch.d.ts +5 -10
  86. package/dist/server/app-page-dispatch.js +84 -154
  87. package/dist/server/app-page-element-builder.d.ts +2 -2
  88. package/dist/server/app-page-element-builder.js +10 -9
  89. package/dist/server/app-page-execution.d.ts +17 -52
  90. package/dist/server/app-page-execution.js +99 -95
  91. package/dist/server/app-page-head.d.ts +13 -0
  92. package/dist/server/app-page-head.js +44 -16
  93. package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
  94. package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
  95. package/dist/server/app-page-layout-gate.d.ts +35 -0
  96. package/dist/server/app-page-layout-gate.js +50 -0
  97. package/dist/server/app-page-params.d.ts +0 -1
  98. package/dist/server/app-page-params.js +1 -14
  99. package/dist/server/app-page-probe.d.ts +3 -21
  100. package/dist/server/app-page-probe.js +4 -37
  101. package/dist/server/app-page-render.d.ts +2 -12
  102. package/dist/server/app-page-render.js +89 -220
  103. package/dist/server/app-page-request.d.ts +1 -3
  104. package/dist/server/app-page-request.js +1 -1
  105. package/dist/server/app-page-response.js +3 -3
  106. package/dist/server/app-page-route-wiring.d.ts +13 -6
  107. package/dist/server/app-page-route-wiring.js +67 -61
  108. package/dist/server/app-page-rsc-render-status.d.ts +27 -1
  109. package/dist/server/app-page-rsc-render-status.js +121 -13
  110. package/dist/server/app-page-stream.d.ts +2 -0
  111. package/dist/server/app-page-stream.js +2 -2
  112. package/dist/server/app-pages-bridge.d.ts +4 -0
  113. package/dist/server/app-pages-bridge.js +7 -3
  114. package/dist/server/app-render-dependency.d.ts +11 -4
  115. package/dist/server/app-render-dependency.js +86 -38
  116. package/dist/server/app-request-stage-dispatch.js +1 -1
  117. package/dist/server/app-route-handler-cache.js +2 -2
  118. package/dist/server/app-route-handler-dispatch.js +14 -9
  119. package/dist/server/app-route-handler-execution.js +8 -3
  120. package/dist/server/app-route-handler-policy.d.ts +1 -1
  121. package/dist/server/app-route-handler-policy.js +3 -3
  122. package/dist/server/app-route-handler-response.js +1 -1
  123. package/dist/server/app-route-handler-runtime.js +17 -4
  124. package/dist/server/app-rsc-cache-busting.d.ts +2 -2
  125. package/dist/server/app-rsc-cache-busting.js +4 -4
  126. package/dist/server/app-rsc-error-handler.d.ts +2 -1
  127. package/dist/server/app-rsc-error-handler.js +9 -1
  128. package/dist/server/app-rsc-errors.d.ts +8 -0
  129. package/dist/server/app-rsc-errors.js +8 -1
  130. package/dist/server/app-rsc-handler.d.ts +5 -5
  131. package/dist/server/app-rsc-handler.js +30 -24
  132. package/dist/server/app-rsc-request-normalization.d.ts +0 -4
  133. package/dist/server/app-rsc-request-normalization.js +1 -4
  134. package/dist/server/app-rsc-response-finalizer.js +2 -2
  135. package/dist/server/app-rsc-response-stage.js +5 -3
  136. package/dist/server/app-server-action-execution.d.ts +3 -1
  137. package/dist/server/app-server-action-execution.js +7 -4
  138. package/dist/server/app-ssr-entry.d.ts +2 -0
  139. package/dist/server/app-ssr-entry.js +9 -8
  140. package/dist/server/app-ssr-stream.js +1 -1
  141. package/dist/server/app-visited-response-cache.d.ts +36 -1
  142. package/dist/server/app-visited-response-cache.js +46 -5
  143. package/dist/server/app-worker-stages.d.ts +25 -3
  144. package/dist/server/app-worker-stages.js +45 -6
  145. package/dist/server/artifact-compatibility.d.ts +0 -1
  146. package/dist/server/artifact-compatibility.js +1 -10
  147. package/dist/server/cache-proof.d.ts +1 -115
  148. package/dist/server/cache-proof.js +1 -544
  149. package/dist/server/cacheability-request.js +13 -8
  150. package/dist/server/dev-server.js +4 -3
  151. package/dist/server/headers.d.ts +6 -3
  152. package/dist/server/headers.js +9 -5
  153. package/dist/server/isr-cache.d.ts +8 -2
  154. package/dist/server/isr-cache.js +26 -1
  155. package/dist/server/metadata-route-response.js +32 -15
  156. package/dist/server/multi-stage.d.ts +52 -11
  157. package/dist/server/multi-stage.js +13 -1
  158. package/dist/server/navigation-planner.js +1 -1
  159. package/dist/server/pages-api-route.js +28 -19
  160. package/dist/server/pages-media-type.d.ts +21 -1
  161. package/dist/server/pages-media-type.js +69 -5
  162. package/dist/server/pages-node-compat.js +52 -27
  163. package/dist/server/pages-page-handler.js +11 -20
  164. package/dist/server/pages-request-pipeline.d.ts +8 -0
  165. package/dist/server/pages-request-pipeline.js +2 -2
  166. package/dist/server/pages-request-stage-entry.js +14 -12
  167. package/dist/server/pages-response-stage-entry.js +9 -3
  168. package/dist/server/prod-server.js +5 -1
  169. package/dist/server/request-pipeline.d.ts +6 -0
  170. package/dist/server/request-pipeline.js +21 -1
  171. package/dist/server/shared-cache-identity.d.ts +23 -0
  172. package/dist/server/shared-cache-identity.js +36 -0
  173. package/dist/server/worker-stages.d.ts +16 -3
  174. package/dist/server/worker-stages.js +23 -4
  175. package/dist/shims/cache-handler.js +2 -2
  176. package/dist/shims/cache-request-state.d.ts +17 -20
  177. package/dist/shims/cache-request-state.js +16 -21
  178. package/dist/shims/cache-runtime.js +27 -11
  179. package/dist/shims/cache.d.ts +8 -7
  180. package/dist/shims/cache.js +17 -19
  181. package/dist/shims/cacheability-classification.d.ts +2 -0
  182. package/dist/shims/cdn-cache.d.ts +22 -5
  183. package/dist/shims/client-page-root.js +2 -2
  184. package/dist/shims/dynamic.js +9 -6
  185. package/dist/shims/error-boundary.js +2 -2
  186. package/dist/shims/fetch-cache-state.d.ts +5 -1
  187. package/dist/shims/fetch-cache-state.js +1 -3
  188. package/dist/shims/fetch-cache.d.ts +2 -1
  189. package/dist/shims/fetch-cache.js +34 -24
  190. package/dist/shims/form.js +2 -2
  191. package/dist/shims/headers.d.ts +8 -23
  192. package/dist/shims/headers.js +17 -67
  193. package/dist/shims/internal/navigation-untracked.js +1 -1
  194. package/dist/shims/link.js +3 -1
  195. package/dist/shims/metadata.d.ts +23 -21
  196. package/dist/shims/metadata.js +62 -24
  197. package/dist/shims/navigation-server.js +1 -1
  198. package/dist/shims/navigation.d.ts +74 -7
  199. package/dist/shims/navigation.js +183 -29
  200. package/dist/shims/navigation.react-server.js +2 -2
  201. package/dist/shims/request-state-types.d.ts +2 -2
  202. package/dist/shims/slot.d.ts +12 -0
  203. package/dist/shims/slot.js +37 -9
  204. package/dist/shims/unified-request-context.d.ts +1 -1
  205. package/dist/shims/unified-request-context.js +2 -3
  206. package/dist/utils/cache-control-metadata.d.ts +5 -0
  207. package/dist/utils/cache-control-metadata.js +9 -1
  208. package/dist/utils/project.d.ts +2 -2
  209. package/dist/utils/project.js +3 -16
  210. package/dist/utils/regex.d.ts +5 -0
  211. package/dist/utils/regex.js +11 -1
  212. package/dist/utils/text-stream.d.ts +10 -5
  213. package/dist/utils/text-stream.js +6 -6
  214. package/package.json +2 -1
  215. package/dist/build/layout-classification-types.d.ts +0 -60
  216. package/dist/build/layout-classification-types.js +0 -1
  217. package/dist/build/layout-classification.d.ts +0 -62
  218. package/dist/build/layout-classification.js +0 -98
  219. package/dist/build/route-classification-injector.d.ts +0 -33
  220. package/dist/build/route-classification-injector.js +0 -59
  221. package/dist/build/route-classification-manifest.d.ts +0 -54
  222. package/dist/build/route-classification-manifest.js +0 -143
  223. package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
  224. package/dist/server/app-browser-client-reuse-manifest.js +0 -101
  225. package/dist/server/app-layout-param-observation.d.ts +0 -42
  226. package/dist/server/app-layout-param-observation.js +0 -168
  227. package/dist/server/client-reuse-manifest.d.ts +0 -103
  228. package/dist/server/client-reuse-manifest.js +0 -209
  229. package/dist/server/skip-cache-proof.d.ts +0 -60
  230. package/dist/server/skip-cache-proof.js +0 -168
  231. package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
  232. package/dist/server/static-layout-client-reuse-proof.js +0 -33
  233. package/dist/utils/sorted-array.d.ts +0 -8
  234. package/dist/utils/sorted-array.js +0 -20
@@ -3,9 +3,7 @@ import { AppElements, AppElementsInterception, AppElementsSlotBinding } from "./
3
3
  import "./app-elements.js";
4
4
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
5
5
  import { AppPageParams } from "./app-page-boundary.js";
6
- import { ThenableParamsObserver } from "../shims/thenable-params.js";
7
6
  import { Metadata, Viewport } from "../shims/metadata.js";
8
- import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
9
7
  import { AppPageRenderDependency } from "./app-render-dependency.js";
10
8
  import { AppPageSemanticSegment, resolveAppPageChildSegments } from "./app-page-segment-state.js";
11
9
  import { AppPageRenderIdentity } from "./app-page-render-identity.js";
@@ -172,7 +170,6 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
172
170
  */
173
171
  renderElementWithMetadataOutlet?: ((metadataOutlet: ReactNode) => ReactNode) | null;
174
172
  globalErrorModule?: TErrorModule | null;
175
- layoutParamAccess?: AppLayoutParamAccessTracker;
176
173
  makeThenableParams: MakeThenableParams;
177
174
  matchedParams: AppPageParams;
178
175
  metadataPlacement?: "body" | "head";
@@ -211,7 +208,7 @@ export type AppPageRouteHead = {
211
208
  /** `null` when resolution failed: like Next.js, the head then has no viewport tags. */
212
209
  viewport: Promise<Viewport | null>;
213
210
  };
214
- type MakeThenableParams = (params: AppPageParams, observer?: ThenableParamsObserver) => unknown;
211
+ type MakeThenableParams = (params: AppPageParams) => unknown;
215
212
  type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule> = BuildAppPageRouteElementOptions<TModule, TErrorModule> & {
216
213
  interception?: AppElementsInterception | null;
217
214
  interceptionId?: string | null;
@@ -226,6 +223,13 @@ type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule,
226
223
  * still store the route tree, as a CDN would store Next.js's.
227
224
  */
228
225
  isUncacheableRender?: boolean;
226
+ /**
227
+ * Hashed segment identities of the layouts the navigating client holds (see
228
+ * app-mounted-layouts.ts). A render that can never be stored leaves out the
229
+ * outermost layouts it names, as Next.js renders only below where a
230
+ * navigation diverges from the client's router state.
231
+ */
232
+ mountedLayouts?: ReadonlySet<string> | null;
229
233
  mountedSlotIds?: ReadonlySet<string> | null;
230
234
  renderIdentity?: AppPageRenderIdentity;
231
235
  renderMode?: AppRscRenderMode;
@@ -246,9 +250,12 @@ export type AppPageTemplateEntry<TModule extends AppPageModule = AppPageModule>
246
250
  treePosition: number;
247
251
  };
248
252
  export declare function createAppPageTreePath(routeSegments: readonly string[] | null | undefined, treePosition: number): string;
249
- export declare function probeAppPageLayoutWithTracking<TModule extends AppPageModule>(options: {
253
+ /**
254
+ * Renders the layout at `layoutIndex` with a placeholder for its children, so
255
+ * whatever it or a component it renders throws comes out.
256
+ */
257
+ export declare function probeAppPageLayout<TModule extends AppPageModule>(options: {
250
258
  layoutIndex: number;
251
- layoutParamAccess: AppLayoutParamAccessTracker | undefined;
252
259
  makeThenableParams: MakeThenableParams;
253
260
  matchedParams: AppPageParams;
254
261
  route: Pick<AppPageRouteWiringRoute<TModule>, "layoutTreePositions" | "layouts" | "routeSegments">;
@@ -1,24 +1,26 @@
1
1
  import { APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "./app-rsc-render-mode.js";
2
2
  import { fnv1a64 } from "../utils/hash.js";
3
3
  import { createInlineScriptTag, escapeHtmlAttr } from "./html.js";
4
- import { createAppRenderDependency, invokeAppComponentMappingErrors, isReactOwnedAppComponent, registerAppElementRenderDependencies, renderAfterAppDependencies, renderAppComponentWithDependencyBarrier } from "./app-render-dependency.js";
5
- import { APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
4
+ import { APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
6
5
  import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX } from "./app-elements.js";
6
+ import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
7
+ import { hashMountedLayoutIdentity } from "./app-mounted-layouts.js";
8
+ import { BfcacheChildrenBoundary, BfcacheSegmentBoundary, Children as Children$1, ParallelSlot, Slot } from "../shims/slot.js";
9
+ import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPageSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
7
10
  import DefaultGlobalError from "../shims/default-global-error.js";
8
11
  import { ErrorBoundary, ForbiddenBoundary, GlobalErrorBoundary, HttpAccessFallbackPassthrough, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
9
- import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
10
- import DefaultForbidden from "../shims/default-forbidden.js";
11
- import DefaultNotFound from "../shims/default-not-found.js";
12
- import DefaultUnauthorized from "../shims/default-unauthorized.js";
13
12
  import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
14
13
  import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
15
14
  import { MetadataHead, ViewportHead, renderMetadataToHtml } from "../shims/metadata.js";
16
- import { BfcacheSegmentBoundary, Children as Children$1, ParallelSlot, Slot } from "../shims/slot.js";
15
+ import { APP_PAGE_NOT_FOUND_BOUNDARY_ID, tagAppPageLayoutError, tagAppPageSlotError } from "./app-page-execution.js";
16
+ import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
17
+ import DefaultForbidden from "../shims/default-forbidden.js";
18
+ import DefaultNotFound from "../shims/default-not-found.js";
19
+ import DefaultUnauthorized from "../shims/default-unauthorized.js";
17
20
  import { StreamedIconsInsertion } from "../shims/streamed-icons.js";
18
- import { APP_PAGE_NOT_FOUND_BOUNDARY_ID, tagAppPageSlotError } from "./app-page-execution.js";
19
- import { resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams } from "./app-page-params.js";
21
+ import { createAppRenderDependency, invokeAppComponentMappingErrors, isReactOwnedAppComponent, renderAfterAppDependencies, renderAppComponentWithDependencyBarrier } from "./app-render-dependency.js";
22
+ import { createAppPageLayoutGate, registerAppPageLayoutGate } from "./app-page-layout-gate.js";
20
23
  import { probeReactServerSubtree } from "./app-page-probe.js";
21
- import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPageSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
22
24
  import { createAppPageSegmentPlan } from "./app-page-segment-plan.js";
23
25
  import { resolveAppPageModuleTraceSegment, traceGetLayoutOrPageModule } from "./app-page-tracing.js";
24
26
  import { Fragment, Suspense } from "react";
@@ -44,6 +46,21 @@ function createSlotLayoutElement(LayoutComponent, props, slotLayoutIndex, notFou
44
46
  const SlotLayoutInvoker = () => invokeAppComponentMappingErrors(LayoutComponent, props, (error) => tagAppPageSlotError(error, slotLayoutIndex, notFoundBoundary));
45
47
  return /* @__PURE__ */ jsx(SlotLayoutInvoker, {});
46
48
  }
49
+ /**
50
+ * A route layout, whose notFound(), forbidden() and unauthorized() are caught
51
+ * above it: its own boundaries wrap only its `children`. The layout's index
52
+ * tags what it throws, so the response's fallback finds that boundary from the
53
+ * render. `onSettled` hears how the layout rendered.
54
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-component-tree.tsx
55
+ */
56
+ function createRouteLayoutElement(LayoutComponent, props, layoutIndex, dependency, onSettled) {
57
+ const mapError = (error) => tagAppPageLayoutError(error, layoutIndex);
58
+ if (dependency) return renderAppComponentWithDependencyBarrier(LayoutComponent, props, dependency, mapError, onSettled);
59
+ if (isReactOwnedAppComponent(LayoutComponent)) return /* @__PURE__ */ jsx(LayoutComponent, { ...props });
60
+ const RouteLayoutInvoker = () => invokeAppComponentMappingErrors(LayoutComponent, props, mapError, onSettled);
61
+ RouteLayoutInvoker.displayName = LayoutComponent.displayName ?? LayoutComponent.name;
62
+ return /* @__PURE__ */ jsx(RouteLayoutInvoker, {});
63
+ }
47
64
  function getDefaultExport(module) {
48
65
  return module?.default ?? null;
49
66
  }
@@ -55,37 +72,19 @@ function createAppPageTreePath(routeSegments, treePosition) {
55
72
  if (treePathSegments.length === 0) return "/";
56
73
  return `/${treePathSegments.join("/")}`;
57
74
  }
58
- function readFiniteRevalidateSeconds(module) {
59
- const revalidate = module?.revalidate;
60
- return typeof revalidate === "number" && Number.isFinite(revalidate) && revalidate > 0 ? revalidate : null;
61
- }
62
- function recordLayoutSkipObservationScope(options) {
63
- options.layoutParamAccess?.recordLayoutParamScope(options.layoutId, resolveAppPageSegmentParamScopeKeys(options.routeSegments, options.treePosition));
64
- const revalidateSeconds = readFiniteRevalidateSeconds(options.layoutModule);
65
- if (revalidateSeconds !== null) options.layoutParamAccess?.recordLayoutFiniteRevalidate(options.layoutId, revalidateSeconds);
66
- }
67
- function probeAppPageLayoutWithTracking(options) {
75
+ /**
76
+ * Renders the layout at `layoutIndex` with a placeholder for its children, so
77
+ * whatever it or a component it renders throws comes out.
78
+ */
79
+ function probeAppPageLayout(options) {
68
80
  const treePosition = options.route.layoutTreePositions?.[options.layoutIndex] ?? 0;
69
- const treePath = createAppPageTreePath(options.route.routeSegments, treePosition);
70
- const layoutId = AppElementsWire.encodeLayoutId(treePath);
71
- const probe = () => {
72
- const layoutModule = options.route.layouts[options.layoutIndex];
73
- const LayoutComponent = getDefaultExport(layoutModule);
74
- if (!LayoutComponent) return null;
75
- recordLayoutSkipObservationScope({
76
- layoutId,
77
- layoutModule,
78
- layoutParamAccess: options.layoutParamAccess,
79
- routeSegments: options.route.routeSegments,
80
- treePosition
81
- });
82
- const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, treePosition, options.matchedParams);
83
- return probeReactServerSubtree(/* @__PURE__ */ jsx(LayoutComponent, {
84
- ...withUseCacheLayoutMarker(LayoutComponent, { params: options.makeThenableParams(layoutParams, options.layoutParamAccess?.createThenableParamsObserver(layoutId)) }),
85
- children: APP_PAGE_LAYOUT_PROBE_CHILD
86
- }));
87
- };
88
- return options.layoutParamAccess ? options.layoutParamAccess.runLayoutProbe(layoutId, probe) : probe();
81
+ const LayoutComponent = getDefaultExport(options.route.layouts[options.layoutIndex]);
82
+ if (!LayoutComponent) return null;
83
+ const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, treePosition, options.matchedParams);
84
+ return probeReactServerSubtree(/* @__PURE__ */ jsx(LayoutComponent, {
85
+ ...withUseCacheLayoutMarker(LayoutComponent, { params: options.makeThenableParams(layoutParams) }),
86
+ children: APP_PAGE_LAYOUT_PROBE_CHILD
87
+ }));
89
88
  }
90
89
  function createAppPageLayoutEntries(route) {
91
90
  return route.layouts.map((layoutModule, index) => {
@@ -426,8 +425,8 @@ function buildAppPageElements(options) {
426
425
  const notFoundBoundaries = resolveAccessBoundaries(options.route.segmentNotFounds, options.route.segmentNotFoundTreePositions, (entry) => entry.notFoundModule, rootNotFoundModule ? null : DEFAULT_NOT_FOUND_COMPONENT);
427
426
  const forbiddenBoundaries = resolveAccessBoundaries(options.route.segmentForbiddens, options.route.segmentForbiddenTreePositions, (entry) => entry.forbiddenModule, rootForbiddenModule ? null : DEFAULT_FORBIDDEN_COMPONENT);
428
427
  const unauthorizedBoundaries = resolveAccessBoundaries(options.route.segmentUnauthorizeds, options.route.segmentUnauthorizedTreePositions, (entry) => entry.unauthorizedModule, rootUnauthorizedModule ? null : DEFAULT_UNAUTHORIZED_COMPONENT);
428
+ const layoutGate = createAppPageLayoutGate();
429
429
  const layoutDependenciesByIndex = /* @__PURE__ */ new Map();
430
- const renderDependenciesByElementId = /* @__PURE__ */ new Map();
431
430
  const layoutDependenciesBefore = [];
432
431
  const slotDependenciesByLayoutIndex = [];
433
432
  const templateDependenciesById = /* @__PURE__ */ new Map();
@@ -488,6 +487,13 @@ function buildAppPageElements(options) {
488
487
  templateEntries
489
488
  });
490
489
  const routeResetKey = segmentPlan.routeResetKey;
490
+ const skippedLayoutIds = /* @__PURE__ */ new Set();
491
+ if (options.mountedLayouts && options.isRscRequest === true && options.isUncacheableRender === true && renderMode === "navigation" && interception === null) for (const layoutEntry of layoutEntries) {
492
+ const identity = segmentPlan.bfcacheSegmentIdentities[layoutEntry.id];
493
+ if (identity === void 0) break;
494
+ if (!options.mountedLayouts.has(hashMountedLayoutIdentity(identity))) break;
495
+ skippedLayoutIds.add(layoutEntry.id);
496
+ }
491
497
  const slotPlansByKey = new Map(segmentPlan.slots.map((slot) => [slot.key, slot]));
492
498
  const resolveRouteSegmentResetKey = (treePosition) => resolveAppPageSegmentStateKey(routeSegments, treePosition, options.matchedParams);
493
499
  const metadataEntries = AppElementsWire.createMetadataEntries({
@@ -530,10 +536,9 @@ function buildAppPageElements(options) {
530
536
  if (layoutIndex !== void 0) {
531
537
  const layoutEntry = layoutEntries[layoutIndex];
532
538
  layoutDependenciesBefore[layoutIndex] = [...pageDependencies];
533
- if (getDefaultExport(layoutEntry.layoutModule)) {
539
+ if (!skippedLayoutIds.has(layoutEntry.id) && getDefaultExport(layoutEntry.layoutModule)) {
534
540
  const layoutDependency = createAppRenderDependency();
535
541
  layoutDependenciesByIndex.set(layoutIndex, layoutDependency);
536
- renderDependenciesByElementId.set(layoutEntry.id, layoutDependency);
537
542
  pageDependencies.push(layoutDependency);
538
543
  }
539
544
  slotDependenciesByLayoutIndex[layoutIndex] = [...pageDependencies];
@@ -581,33 +586,29 @@ function buildAppPageElements(options) {
581
586
  for (let index = 0; index < layoutEntries.length; index++) {
582
587
  const layoutEntry = layoutEntries[index];
583
588
  if (isPrefetchLoadingShell && !includesPrefetchTreePosition(layoutEntry.treePosition)) continue;
589
+ if (skippedLayoutIds.has(layoutEntry.id)) continue;
584
590
  if (!layoutEntry.layoutModule) continue;
585
591
  const layoutComponent = traceGetLayoutOrPageModule(resolveAppPageModuleTraceSegment(routeSegments, layoutEntry.treePosition), () => getDefaultExport(layoutEntry.layoutModule));
586
592
  if (!layoutComponent) continue;
587
593
  const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, layoutEntry.treePosition, options.matchedParams);
588
- recordLayoutSkipObservationScope({
589
- layoutId: layoutEntry.id,
590
- layoutModule: layoutEntry.layoutModule,
591
- layoutParamAccess: options.layoutParamAccess,
592
- routeSegments: options.route.routeSegments,
593
- treePosition: layoutEntry.treePosition
594
- });
595
- const layoutProps = { params: options.makeThenableParams(layoutParams, options.layoutParamAccess?.createThenableParamsObserver(layoutEntry.id)) };
594
+ const layoutProps = { params: options.makeThenableParams(layoutParams) };
596
595
  for (const slot of Object.values(options.route.slots ?? {})) {
597
596
  const slotName = slot.name;
598
597
  if ((slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1) !== index) continue;
599
598
  layoutProps[slotName] = /* @__PURE__ */ jsx(ParallelSlot, { name: slotName });
600
599
  }
601
600
  const LayoutComponent = layoutComponent;
602
- const layoutDependency = layoutDependenciesByIndex.get(index);
603
- let layoutElement = layoutDependency ? renderAppComponentWithDependencyBarrier(LayoutComponent, withUseCacheLayoutMarker(LayoutComponent, {
601
+ const ancestorLoadingEntry = findNearestAncestorLoadingEntry(layoutEntry.treePosition);
602
+ const holdsResponse = !ancestorLoadingEntry && !isReactOwnedAppComponent(LayoutComponent);
603
+ if (holdsResponse) layoutGate.hold(layoutEntry.id, index);
604
+ let layoutElement = createRouteLayoutElement(LayoutComponent, withUseCacheLayoutMarker(LayoutComponent, {
604
605
  ...layoutProps,
605
606
  children: /* @__PURE__ */ jsx(Children$1, {})
606
- }), layoutDependency) : /* @__PURE__ */ jsx(LayoutComponent, {
607
- ...withUseCacheLayoutMarker(LayoutComponent, layoutProps),
608
- children: /* @__PURE__ */ jsx(Children$1, {})
607
+ }), index, layoutDependenciesByIndex.get(index), holdsResponse ? (failure) => layoutGate.settle(layoutEntry.id, failure) : void 0);
608
+ layoutElement = /* @__PURE__ */ jsx(RedirectBoundary, {
609
+ resetKey: resolveRouteSegmentResetKey(layoutEntry.treePosition),
610
+ children: layoutElement
609
611
  });
610
- const ancestorLoadingEntry = findNearestAncestorLoadingEntry(layoutEntry.treePosition);
611
612
  const ancestorLoadingComponent = getDefaultExport(ancestorLoadingEntry?.loadingModule);
612
613
  if (ancestorLoadingComponent && ancestorLoadingEntry && isOutermostEntryBelowLoading(ancestorLoadingEntry.treePosition, layoutEntry.treePosition, "layout")) {
613
614
  const AncestorLoadingComponent = ancestorLoadingComponent;
@@ -876,6 +877,7 @@ function buildAppPageElements(options) {
876
877
  children: routeChildren
877
878
  });
878
879
  const renderedTreePositions = isPrefetchLoadingShell ? orderedTreePositions.filter(includesPrefetchTreePosition) : orderedTreePositions;
880
+ let childSegmentElementId = pageElementId;
879
881
  for (let index = renderedTreePositions.length - 1; index >= 0; index--) {
880
882
  const treePosition = renderedTreePositions[index];
881
883
  const segmentResetKey = resolveRouteSegmentResetKey(treePosition);
@@ -947,9 +949,13 @@ function buildAppPageElements(options) {
947
949
  children: layoutHasElement ? /* @__PURE__ */ jsx(Slot, {
948
950
  id: layoutEntry.id,
949
951
  parallelSlots: createAppPageParallelSlotEntries(layoutIndex, layoutEntries, options.route, getEffectiveSlotParams, resolveSlotOverride),
950
- children: segmentChildren
952
+ children: /* @__PURE__ */ jsx(BfcacheChildrenBoundary, {
953
+ id: childSegmentElementId,
954
+ children: segmentChildren
955
+ })
951
956
  }) : segmentChildren
952
957
  });
958
+ if (layoutHasElement) childSegmentElementId = layoutEntry.id;
953
959
  }
954
960
  const globalErrorComponent = getErrorBoundaryExport(options.globalErrorModule);
955
961
  routeChildren = /* @__PURE__ */ jsx(GlobalErrorBoundary, {
@@ -965,9 +971,9 @@ function buildAppPageElements(options) {
965
971
  createAppPageStreamingMetadataBody(streamingMetadataBodyId)
966
972
  ] });
967
973
  elements[routeId] = pageRenderDependency ? renderAfterAppDependencies(routeElement, [pageRenderDependency]) : routeElement;
968
- Object.assign(elements, metadataEntries, options.route.staticSiblings && options.route.staticSiblings.length > 0 ? { [APP_STATIC_SIBLINGS_KEY]: options.route.staticSiblings } : {}, shouldRenderPrefetchLoadingShell ? { [APP_PREFETCH_LOADING_SHELL_MARKER_KEY]: "LoadingBoundary" } : {});
969
- registerAppElementRenderDependencies(elements, renderDependenciesByElementId);
974
+ Object.assign(elements, metadataEntries, options.route.staticSiblings && options.route.staticSiblings.length > 0 ? { [APP_STATIC_SIBLINGS_KEY]: options.route.staticSiblings } : {}, shouldRenderPrefetchLoadingShell ? { [APP_PREFETCH_LOADING_SHELL_MARKER_KEY]: "LoadingBoundary" } : {}, skippedLayoutIds.size > 0 ? { [APP_SKIPPED_LAYOUT_IDS_KEY]: [...skippedLayoutIds] } : {});
975
+ registerAppPageLayoutGate(elements, layoutGate);
970
976
  return elements;
971
977
  }
972
978
  //#endregion
973
- export { buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath, probeAppPageLayoutWithTracking, resolveAppPageChildSegments, resolveAppPageLoadingModuleAtOrAbove };
979
+ export { buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath, probeAppPageLayout, resolveAppPageChildSegments, resolveAppPageLoadingModuleAtOrAbove };
@@ -1,7 +1,9 @@
1
1
  import { NavigationContext } from "../shims/navigation-context-state.js";
2
2
  import "../shims/navigation.js";
3
3
  import { RootParams } from "../shims/root-params.js";
4
- import { AppPageSsrHandler } from "./app-page-stream.js";
4
+ import { InitialNavigationCacheMetadata } from "./app-ssr-stream.js";
5
+ import { AppPageFontData, AppPageSsrHandler } from "./app-page-stream.js";
6
+ import { CdnAppPageDocument } from "../shims/cdn-cache.js";
5
7
  //#region src/server/app-page-rsc-render-status.d.ts
6
8
  /**
7
9
  * The status of a finished RSC render, as Next.js's static generation decides
@@ -10,6 +12,8 @@ import { AppPageSsrHandler } from "./app-page-stream.js";
10
12
  */
11
13
  export type AppPageRscRenderStatus = {
12
14
  kind: "page";
15
+ /** The page's document, when the resolver rendered one to store. */
16
+ document?: CdnAppPageDocument;
13
17
  } | {
14
18
  kind: "special-error";
15
19
  status: number;
@@ -22,9 +26,28 @@ export type AppPageRscRenderStatus = {
22
26
  {
23
27
  kind: "unstorable";
24
28
  };
29
+ /** What the page's document renders with, as an HTML request renders it. */
30
+ type AppPageRscRenderDocumentOptions = {
31
+ clientTraceMetadata?: readonly string[];
32
+ /**
33
+ * When the document's render is given up, as completed-response admission
34
+ * gives up a body it hasn't captured by its deadline.
35
+ */
36
+ deadlineAt?: number;
37
+ getFontData: () => AppPageFontData;
38
+ getInitialNavigationCacheMetadata: () => InitialNavigationCacheMetadata;
39
+ mirrorNextFlight: () => boolean;
40
+ onSsrError: (error: unknown) => unknown;
41
+ reactMaxHeadersLength?: number;
42
+ };
25
43
  type CreateAppPageRscRenderStatusResolverOptions = {
26
44
  basePath?: string;
27
45
  capturedRscData: Promise<ArrayBuffer>;
46
+ /**
47
+ * Render the page's document from the payload, to be stored beside it.
48
+ * Without it, only a render that threw a special error renders its shell.
49
+ */
50
+ document?: AppPageRscRenderDocumentOptions;
28
51
  getCapturedSpecialError: () => unknown;
29
52
  getCapturedSpecialErrors: (error: unknown) => readonly unknown[];
30
53
  isForceStatic: boolean;
@@ -39,6 +62,9 @@ type CreateAppPageRscRenderStatusResolverOptions = {
39
62
  * a render that threw one renders the document's shell from the same payload,
40
63
  * as Next.js's static generation renders HTML beside RSC. Its server
41
64
  * components don't run again. A render without a special error is a 200.
65
+ *
66
+ * With `document`, every render renders its document from the payload, as
67
+ * Next.js keeps a page's document and RSC payload in one entry.
42
68
  */
43
69
  export declare function createAppPageRscRenderStatusResolver(options: CreateAppPageRscRenderStatusResolverOptions): () => Promise<AppPageRscRenderStatus>;
44
70
  /**
@@ -1,5 +1,8 @@
1
- import { resolveAppPageShellSpecialError, resolveAppPageSpecialErrorStoredHeaders } from "./app-page-execution.js";
2
- import { isAppSsrRenderResult } from "./app-page-stream.js";
1
+ import { isRenderDynamicLatched } from "../shims/internal/headers-state.js";
2
+ import "../shims/headers.js";
3
+ import { readStreamAsText } from "../utils/text-stream.js";
4
+ import { buildAppPageFontLinkHeader, resolveAppPageShellSpecialError, resolveAppPageSpecialErrorStoredHeaders } from "./app-page-execution.js";
5
+ import { buildAppPageLinkHeader, isAppSsrRenderResult } from "./app-page-stream.js";
3
6
  //#region src/server/app-page-rsc-render-status.ts
4
7
  const PAGE_STATUS = { kind: "page" };
5
8
  /**
@@ -8,28 +11,109 @@ const PAGE_STATUS = { kind: "page" };
8
11
  * a render that threw one renders the document's shell from the same payload,
9
12
  * as Next.js's static generation renders HTML beside RSC. Its server
10
13
  * components don't run again. A render without a special error is a 200.
14
+ *
15
+ * With `document`, every render renders its document from the payload, as
16
+ * Next.js keeps a page's document and RSC payload in one entry.
11
17
  */
12
18
  function createAppPageRscRenderStatusResolver(options) {
13
19
  let status;
14
20
  return () => status ??= resolveAppPageRscRenderStatus(options);
15
21
  }
16
22
  async function resolveAppPageRscRenderStatus(options) {
23
+ const deadlineAt = options.document?.deadlineAt;
24
+ if (deadlineAt === void 0) return renderAppPageRscRenderStatus(options);
25
+ const expired = new AbortController();
26
+ const remaining = deadlineAt - Date.now();
27
+ const timer = remaining > 0 ? setTimeout(() => expired.abort(), remaining) : void 0;
28
+ if (timer === void 0) expired.abort();
29
+ try {
30
+ return await unlessExpired(renderAppPageRscRenderStatus(options, expired.signal), expired.signal, () => {}) ?? expiredDocumentStatus(options);
31
+ } finally {
32
+ clearTimeout(timer);
33
+ }
34
+ }
35
+ /** Settle with `promise`, or with `null` once `signal` aborts. */
36
+ function unlessExpired(promise, signal, discard) {
37
+ if (!signal) return promise;
38
+ if (signal.aborted) {
39
+ promise.then(discard, () => {});
40
+ return Promise.resolve(null);
41
+ }
42
+ return new Promise((resolve, reject) => {
43
+ const onAbort = () => {
44
+ promise.then(discard, () => {});
45
+ resolve(null);
46
+ };
47
+ signal.addEventListener("abort", onAbort, { once: true });
48
+ promise.then((value) => {
49
+ signal.removeEventListener("abort", onAbort);
50
+ if (signal.aborted) discard(value);
51
+ else resolve(value);
52
+ }, (error) => {
53
+ signal.removeEventListener("abort", onAbort);
54
+ reject(error);
55
+ });
56
+ });
57
+ }
58
+ /** Read the document, or cancel it and settle with `null` once `signal` aborts. */
59
+ async function readDocumentHtml(stream, signal) {
60
+ if (!signal) return readStreamAsText(stream);
61
+ const reader = stream.getReader();
62
+ const decoder = new TextDecoder();
63
+ const chunks = [];
64
+ for (;;) {
65
+ const result = await unlessExpired(reader.read(), signal, () => {});
66
+ if (result === null) {
67
+ reader.cancel().catch(() => {});
68
+ return null;
69
+ }
70
+ if (result.done) break;
71
+ chunks.push(decoder.decode(result.value, { stream: true }));
72
+ }
73
+ chunks.push(decoder.decode());
74
+ return chunks.join("");
75
+ }
76
+ /**
77
+ * A document given up at its deadline isn't stored. A render without a
78
+ * special error is still a 200, but one with a special error needs its shell.
79
+ */
80
+ function expiredDocumentStatus(options) {
81
+ return options.getCapturedSpecialError() === null ? PAGE_STATUS : { kind: "unstorable" };
82
+ }
83
+ async function renderAppPageRscRenderStatus(options, signal) {
17
84
  const rscData = await options.capturedRscData;
18
- if (options.getCapturedSpecialError() === null) return PAGE_STATUS;
85
+ const documentOptions = options.document;
86
+ if (!documentOptions && options.getCapturedSpecialError() === null) return PAGE_STATUS;
19
87
  const ssrHandler = await options.loadSsrHandler();
88
+ if (signal?.aborted) return expiredDocumentStatus(options);
89
+ const fontData = documentOptions?.getFontData() ?? {
90
+ links: [],
91
+ preloads: [],
92
+ styles: []
93
+ };
94
+ const clientTraceMetadataMarker = documentOptions?.clientTraceMetadata && documentOptions.clientTraceMetadata.length > 0 ? crypto.randomUUID() : void 0;
20
95
  let rendered;
21
96
  try {
22
- rendered = await ssrHandler.handleSsr(new Response(rscData).body, options.navigationContext, {
23
- links: [],
24
- preloads: [],
25
- styles: []
26
- }, {
97
+ rendered = await unlessExpired(ssrHandler.handleSsr(new Response(rscData).body, options.navigationContext, fontData, {
27
98
  basePath: options.basePath,
28
99
  isForceStatic: options.isForceStatic,
29
- isStaticGeneration: true,
30
- onSsrError: () => void 0,
31
100
  preloadRoutePattern: options.routePattern,
32
- rootParams: options.rootParams
101
+ rootParams: options.rootParams,
102
+ ...documentOptions ? {
103
+ clientTraceMetadata: documentOptions.clientTraceMetadata,
104
+ clientTraceMetadataMarker,
105
+ getInitialNavigationCacheMetadata: documentOptions.getInitialNavigationCacheMetadata,
106
+ isCacheCandidate: true,
107
+ mirrorNextFlight: documentOptions.mirrorNextFlight,
108
+ onSsrError: documentOptions.onSsrError,
109
+ reactMaxHeadersLength: documentOptions.reactMaxHeadersLength,
110
+ signal
111
+ } : {
112
+ isStaticGeneration: true,
113
+ onSsrError: () => void 0
114
+ }
115
+ }), signal, (late) => {
116
+ (isAppSsrRenderResult(late) ? late.htmlStream : late).cancel().catch(() => {});
33
117
  });
34
118
  } catch (error) {
35
119
  const specialError = resolveAppPageShellSpecialError(error, options.getCapturedSpecialErrors(error));
@@ -41,8 +125,32 @@ async function resolveAppPageRscRenderStatus(options) {
41
125
  ...headers ? { headers } : {}
42
126
  };
43
127
  }
44
- (isAppSsrRenderResult(rendered) ? rendered.htmlStream : rendered).cancel().catch(() => {});
45
- return PAGE_STATUS;
128
+ if (rendered === null) return expiredDocumentStatus(options);
129
+ const htmlStream = isAppSsrRenderResult(rendered) ? rendered.htmlStream : rendered;
130
+ if (!documentOptions) {
131
+ htmlStream.cancel().catch(() => {});
132
+ return PAGE_STATUS;
133
+ }
134
+ let html;
135
+ try {
136
+ html = await readDocumentHtml(htmlStream, signal);
137
+ } catch {
138
+ return PAGE_STATUS;
139
+ }
140
+ if (html === null) return expiredDocumentStatus(options);
141
+ if (isRenderDynamicLatched()) return PAGE_STATUS;
142
+ const linkHeader = buildAppPageLinkHeader(isAppSsrRenderResult(rendered) ? rendered.linkHeader : void 0, buildAppPageFontLinkHeader(fontData.preloads), documentOptions.reactMaxHeadersLength);
143
+ if (clientTraceMetadataMarker) {
144
+ const { stripClientTraceMetadataBlock } = await import("./client-trace-metadata.js");
145
+ html = stripClientTraceMetadataBlock(html, clientTraceMetadataMarker);
146
+ }
147
+ return {
148
+ kind: "page",
149
+ document: {
150
+ html,
151
+ ...linkHeader ? { linkHeader } : {}
152
+ }
153
+ };
46
154
  }
47
155
  /**
48
156
  * The status Next.js sends an RSC request for a render with this status. Its
@@ -77,6 +77,8 @@ export type AppPageSsrHandler = {
77
77
  };
78
78
  /** Abort signal for a build-time PPR fallback-shell static render. */
79
79
  pprFallbackShellSignal?: AbortSignal;
80
+ /** Aborts a streaming render whose document is given up. */
81
+ signal?: AbortSignal;
80
82
  /** Route whose client references load before the render; null for none. */
81
83
  preloadRoutePattern?: string | null;
82
84
  /** When true, wait for the full React tree before emitting bytes. */
@@ -1,9 +1,9 @@
1
1
  import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
2
2
  import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-vary.js";
3
3
  import { isNavigationSignalError } from "../utils/navigation-signal.js";
4
- import "./app-rsc-cache-busting.js";
5
- import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
6
4
  import { markFrameworkLinkHeaders } from "./app-response-header-provenance.js";
5
+ import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
6
+ import "./app-rsc-cache-busting.js";
7
7
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
8
8
  import { getNextErrorDigest } from "./next-error-digest.js";
9
9
  import { isAppRenderAbortError } from "./app-render-abort-error.js";
@@ -1,8 +1,10 @@
1
1
  import { AppMiddlewareContext } from "./app-middleware.js";
2
2
  import { MiddlewareResponseMergeOptions } from "./middleware-response-headers.js";
3
3
  import { EdgeApiExecutionRuntime } from "./edge-api-runtime.js";
4
+ import { RuntimePagesDataKind } from "./pages-route-data-kind.js";
4
5
  //#region src/server/app-pages-bridge.d.ts
5
6
  export type PagesEntry = {
7
+ getRuntimePageDataKind?: (url: string, request: Request) => RuntimePagesDataKind;
6
8
  handleApiRoute?: (request: Request, url: string, ctx: unknown, trustedRevalidateOrigin: string | undefined, edgeRuntime: EdgeApiExecutionRuntime, initialResponseHeaders?: Headers) => Promise<Response> | Response;
7
9
  matchApiRoute?: (url: string, request: Request) => PagesRouteMatch | null;
8
10
  matchPageRoute?: (url: string, request: Request) => PagesRouteMatch | null;
@@ -55,6 +57,8 @@ type RenderPagesFallbackOptions = {
55
57
  pathname?: string;
56
58
  pagesDataRequest?: Request | null;
57
59
  request: Request;
60
+ /** The shared cache entry answers every host; a request-time render is not stored. */
61
+ sharedAcrossHosts?: boolean;
58
62
  url: URL;
59
63
  };
60
64
  /**
@@ -1,6 +1,6 @@
1
1
  import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
- import { beginRouteCacheability } from "../shims/cacheability-classification.js";
3
+ import { beginRouteCacheability, markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
4
4
  import { mergeHeaders } from "./worker-utils.js";
5
5
  import { pagesRouteHasPriorityOverAppRoute } from "./hybrid-route-priority.js";
6
6
  //#region src/server/app-pages-bridge.ts
@@ -18,7 +18,7 @@ function applyPagesMiddlewareContext(response, middlewareContext) {
18
18
  * Fallback handler to route App Router requests to the Pages Router when no App Router route matches.
19
19
  */
20
20
  async function renderPagesFallback(options, dependencies) {
21
- const { allowRscDocumentFallback = false, appRouteMatch = null, isDataRequest = false, isRscRequest, initialResponseHeaders, matchKind, middlewareContext, pathname = options.url.pathname, pagesDataRequest = null, request, url } = options;
21
+ const { allowRscDocumentFallback = false, appRouteMatch = null, isDataRequest = false, isRscRequest, initialResponseHeaders, matchKind, middlewareContext, pathname = options.url.pathname, pagesDataRequest = null, request, sharedAcrossHosts = false, url } = options;
22
22
  const { loadPagesEntry, buildRequestHeaders, applyRouteHandlerMiddlewareContext, getDraftModeCookieHeader } = dependencies;
23
23
  if (isRscRequest && !allowRscDocumentFallback) return null;
24
24
  const pagesEntry = await loadPagesEntry();
@@ -61,7 +61,11 @@ async function renderPagesFallback(options, dependencies) {
61
61
  if (pageMatch !== null && matchKind === "static" && pageMatch.route.isDynamic) return null;
62
62
  if (pageMatch !== null && matchKind === "dynamic" && !pageMatch.route.isDynamic) return null;
63
63
  if (appRouteMatch !== null && (pageMatch === null || !pagesRouteHasPriorityOverAppRoute(pageMatch.route, appRouteMatch.route))) return null;
64
- if (pageMatch !== null) beginRouteCacheability("pages-page", pageMatch.route.pattern);
64
+ if (pageMatch !== null) {
65
+ beginRouteCacheability("pages-page", pageMatch.route.pattern);
66
+ const runtimeDataKind = sharedAcrossHosts ? pagesEntry.getRuntimePageDataKind?.(pagesUrl, matchRequest) : void 0;
67
+ if (runtimeDataKind === "server" || runtimeDataKind === "initial") markRouteCacheabilityDynamic("getInitialProps render shares a cache entry across hosts");
68
+ }
65
69
  const pagesRequest = claimPagesRequest();
66
70
  const renderArgs = [
67
71
  pagesDataRequest ? cloneRequestWithUrl(pagesRequest, pagesDataRequest.url) : pagesRequest,
@@ -17,16 +17,23 @@ export declare function isReactOwnedAppComponent(component: unknown): boolean;
17
17
  * errors this call throws or rejects with.
18
18
  */
19
19
  export declare function invokeAppComponent(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, mapError?: (error: unknown) => unknown): ReactNode | Promise<ReactNode>;
20
+ /**
21
+ * Reports how a component's own render ended: `failure` holds what it threw
22
+ * or rejected with, after `mapError`. A suspension isn't an end, as React
23
+ * renders the component again.
24
+ */
25
+ export type AppComponentSettledCallback = (failure?: {
26
+ error: unknown;
27
+ }) => void;
20
28
  /**
21
29
  * `invokeAppComponent()`, with every error the component throws or rejects
22
30
  * with replaced by `mapError(error)`, including its CSS-wrapped inner one's.
31
+ * `onSettled` hears once how the component, or that inner one, ended.
23
32
  */
24
- export declare function invokeAppComponentMappingErrors(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, mapError: (error: unknown) => unknown): ReactNode | Promise<ReactNode>;
25
- export declare function registerAppElementRenderDependencies(elements: Readonly<Record<string, unknown>>, dependenciesByElementId: ReadonlyMap<string, AppRenderDependency>): void;
26
- export declare function releaseAppElementRenderDependency(elements: Readonly<Record<string, unknown>>, elementId: string): void;
33
+ export declare function invokeAppComponentMappingErrors(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, mapError: (error: unknown) => unknown, onSettled?: AppComponentSettledCallback): ReactNode | Promise<ReactNode>;
27
34
  export declare function createAppRenderDependency(): AppRenderDependency;
28
35
  export declare function createAppPageRenderDependency(): AppPageRenderDependency;
29
36
  export declare function isAppRenderSuspension(error: unknown): boolean;
30
37
  export declare function renderAfterAppDependencies(children: ReactNode, dependencies: readonly AppRenderDependency[]): ReactNode;
31
- export declare function renderAppComponentWithDependencyBarrier(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, dependency: AppRenderDependency): ReactNode;
38
+ export declare function renderAppComponentWithDependencyBarrier(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, dependency: AppRenderDependency, mapError?: (error: unknown) => unknown, onSettled?: AppComponentSettledCallback): ReactNode;
32
39
  //#endregion