vinext 0.1.2 → 0.1.3

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 (199) hide show
  1. package/dist/build/prerender.d.ts +9 -1
  2. package/dist/build/prerender.js +41 -12
  3. package/dist/build/run-prerender.d.ts +10 -2
  4. package/dist/build/run-prerender.js +15 -1
  5. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  6. package/dist/client/app-nav-failure-handler.js +44 -0
  7. package/dist/client/vinext-next-data.d.ts +18 -1
  8. package/dist/client/window-next.d.ts +2 -1
  9. package/dist/client/window-next.js +12 -1
  10. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  11. package/dist/config/config-matchers.js +73 -14
  12. package/dist/config/next-config.d.ts +46 -4
  13. package/dist/config/next-config.js +147 -48
  14. package/dist/deploy.d.ts +30 -11
  15. package/dist/deploy.js +180 -99
  16. package/dist/entries/app-browser-entry.d.ts +9 -3
  17. package/dist/entries/app-browser-entry.js +21 -3
  18. package/dist/entries/app-rsc-entry.d.ts +2 -0
  19. package/dist/entries/app-rsc-entry.js +64 -5
  20. package/dist/entries/app-rsc-manifest.js +2 -0
  21. package/dist/entries/app-ssr-entry.js +1 -1
  22. package/dist/entries/pages-client-entry.js +53 -8
  23. package/dist/entries/pages-server-entry.js +41 -5
  24. package/dist/index.js +200 -62
  25. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  26. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  27. package/dist/plugins/optimize-imports.d.ts +2 -1
  28. package/dist/plugins/optimize-imports.js +11 -9
  29. package/dist/plugins/postcss.js +7 -7
  30. package/dist/plugins/typeof-window.d.ts +14 -0
  31. package/dist/plugins/typeof-window.js +150 -0
  32. package/dist/routing/app-route-graph.d.ts +2 -1
  33. package/dist/routing/app-route-graph.js +44 -14
  34. package/dist/routing/file-matcher.d.ts +10 -1
  35. package/dist/routing/file-matcher.js +22 -1
  36. package/dist/routing/pages-router.js +3 -3
  37. package/dist/routing/utils.d.ts +35 -6
  38. package/dist/routing/utils.js +59 -7
  39. package/dist/server/api-handler.d.ts +6 -1
  40. package/dist/server/api-handler.js +21 -15
  41. package/dist/server/app-browser-action-result.d.ts +19 -6
  42. package/dist/server/app-browser-action-result.js +19 -10
  43. package/dist/server/app-browser-entry.js +167 -90
  44. package/dist/server/app-browser-error.d.ts +10 -6
  45. package/dist/server/app-browser-error.js +43 -8
  46. package/dist/server/app-browser-hydration.d.ts +2 -0
  47. package/dist/server/app-browser-hydration.js +1 -0
  48. package/dist/server/app-browser-navigation-controller.d.ts +4 -2
  49. package/dist/server/app-browser-navigation-controller.js +23 -2
  50. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  51. package/dist/server/app-browser-server-action-navigation.js +9 -0
  52. package/dist/server/app-browser-stream.js +86 -43
  53. package/dist/server/app-elements-wire.d.ts +6 -1
  54. package/dist/server/app-elements-wire.js +14 -4
  55. package/dist/server/app-elements.d.ts +2 -2
  56. package/dist/server/app-elements.js +2 -2
  57. package/dist/server/app-fallback-renderer.d.ts +1 -0
  58. package/dist/server/app-fallback-renderer.js +3 -1
  59. package/dist/server/app-optimistic-routing.js +2 -2
  60. package/dist/server/app-page-boundary-render.d.ts +1 -0
  61. package/dist/server/app-page-boundary-render.js +27 -14
  62. package/dist/server/app-page-cache-render.d.ts +53 -0
  63. package/dist/server/app-page-cache-render.js +91 -0
  64. package/dist/server/app-page-cache.d.ts +16 -2
  65. package/dist/server/app-page-cache.js +62 -1
  66. package/dist/server/app-page-dispatch.d.ts +26 -0
  67. package/dist/server/app-page-dispatch.js +149 -92
  68. package/dist/server/app-page-element-builder.d.ts +1 -0
  69. package/dist/server/app-page-element-builder.js +5 -2
  70. package/dist/server/app-page-execution.d.ts +6 -1
  71. package/dist/server/app-page-execution.js +21 -1
  72. package/dist/server/app-page-probe.d.ts +1 -0
  73. package/dist/server/app-page-probe.js +4 -0
  74. package/dist/server/app-page-render-observation.d.ts +3 -1
  75. package/dist/server/app-page-render-observation.js +17 -1
  76. package/dist/server/app-page-render.d.ts +12 -1
  77. package/dist/server/app-page-render.js +42 -4
  78. package/dist/server/app-page-request.d.ts +2 -0
  79. package/dist/server/app-page-request.js +2 -1
  80. package/dist/server/app-page-route-wiring.d.ts +3 -1
  81. package/dist/server/app-page-route-wiring.js +14 -5
  82. package/dist/server/app-page-stream.d.ts +15 -3
  83. package/dist/server/app-page-stream.js +11 -5
  84. package/dist/server/app-pages-bridge.d.ts +18 -0
  85. package/dist/server/app-pages-bridge.js +22 -5
  86. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  87. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  88. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  89. package/dist/server/app-ppr-fallback-shell.js +8 -1
  90. package/dist/server/app-route-handler-dispatch.js +9 -2
  91. package/dist/server/app-route-handler-policy.d.ts +1 -0
  92. package/dist/server/app-router-entry.js +5 -0
  93. package/dist/server/app-rsc-cache-busting.js +2 -0
  94. package/dist/server/app-rsc-handler.d.ts +25 -0
  95. package/dist/server/app-rsc-handler.js +154 -54
  96. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  97. package/dist/server/app-rsc-route-matching.js +2 -0
  98. package/dist/server/app-segment-config.d.ts +9 -1
  99. package/dist/server/app-segment-config.js +12 -3
  100. package/dist/server/app-server-action-execution.d.ts +1 -0
  101. package/dist/server/app-server-action-execution.js +42 -13
  102. package/dist/server/app-ssr-entry.d.ts +2 -0
  103. package/dist/server/app-ssr-entry.js +83 -10
  104. package/dist/server/cache-control.js +4 -0
  105. package/dist/server/dev-server.d.ts +2 -2
  106. package/dist/server/dev-server.js +244 -51
  107. package/dist/server/hybrid-route-priority.d.ts +22 -0
  108. package/dist/server/hybrid-route-priority.js +33 -0
  109. package/dist/server/image-optimization.d.ts +18 -9
  110. package/dist/server/image-optimization.js +37 -23
  111. package/dist/server/implicit-tags.d.ts +2 -1
  112. package/dist/server/implicit-tags.js +4 -1
  113. package/dist/server/navigation-planner.d.ts +133 -30
  114. package/dist/server/navigation-planner.js +114 -0
  115. package/dist/server/navigation-trace.d.ts +8 -1
  116. package/dist/server/navigation-trace.js +8 -1
  117. package/dist/server/pages-api-route.d.ts +6 -0
  118. package/dist/server/pages-api-route.js +13 -2
  119. package/dist/server/pages-asset-tags.d.ts +2 -1
  120. package/dist/server/pages-asset-tags.js +6 -2
  121. package/dist/server/pages-data-route.d.ts +8 -1
  122. package/dist/server/pages-data-route.js +11 -2
  123. package/dist/server/pages-get-initial-props.d.ts +54 -4
  124. package/dist/server/pages-get-initial-props.js +43 -1
  125. package/dist/server/pages-node-compat.js +2 -2
  126. package/dist/server/pages-page-data.d.ts +11 -2
  127. package/dist/server/pages-page-data.js +204 -33
  128. package/dist/server/pages-page-handler.d.ts +4 -2
  129. package/dist/server/pages-page-handler.js +59 -22
  130. package/dist/server/pages-page-response.d.ts +2 -1
  131. package/dist/server/pages-page-response.js +7 -4
  132. package/dist/server/pages-request-pipeline.d.ts +1 -0
  133. package/dist/server/pages-request-pipeline.js +73 -36
  134. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  135. package/dist/server/pregenerated-concrete-paths.js +2 -19
  136. package/dist/server/prerender-manifest.d.ts +33 -0
  137. package/dist/server/prerender-manifest.js +54 -0
  138. package/dist/server/prerender-route-params.d.ts +1 -2
  139. package/dist/server/prod-server.js +9 -3
  140. package/dist/server/request-pipeline.d.ts +3 -15
  141. package/dist/server/request-pipeline.js +58 -47
  142. package/dist/server/rsc-stream-hints.d.ts +5 -1
  143. package/dist/server/rsc-stream-hints.js +6 -1
  144. package/dist/server/seed-cache.js +10 -18
  145. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  146. package/dist/shims/app-router-scroll-state.js +14 -2
  147. package/dist/shims/app-router-scroll.d.ts +3 -0
  148. package/dist/shims/app-router-scroll.js +28 -18
  149. package/dist/shims/cache-runtime.js +3 -2
  150. package/dist/shims/cache.d.ts +1 -0
  151. package/dist/shims/cache.js +1 -1
  152. package/dist/shims/cdn-cache.d.ts +5 -5
  153. package/dist/shims/dynamic-preload-chunks.js +6 -4
  154. package/dist/shims/error-boundary.d.ts +2 -0
  155. package/dist/shims/error-boundary.js +7 -0
  156. package/dist/shims/error.js +3 -2
  157. package/dist/shims/error.react-server.d.ts +9 -0
  158. package/dist/shims/error.react-server.js +6 -0
  159. package/dist/shims/fetch-cache.d.ts +3 -1
  160. package/dist/shims/fetch-cache.js +45 -20
  161. package/dist/shims/hash-scroll.js +6 -1
  162. package/dist/shims/headers.js +29 -4
  163. package/dist/shims/internal/als-registry.js +28 -1
  164. package/dist/shims/internal/app-route-detection.js +8 -17
  165. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  166. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  167. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  168. package/dist/shims/internal/navigation-untracked.js +55 -0
  169. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  170. package/dist/shims/internal/pages-data-target.js +17 -8
  171. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  172. package/dist/shims/internal/pages-router-accessor.js +13 -0
  173. package/dist/shims/internal/router-context.d.ts +2 -1
  174. package/dist/shims/internal/router-context.js +3 -1
  175. package/dist/shims/link.js +12 -5
  176. package/dist/shims/navigation.d.ts +8 -2
  177. package/dist/shims/navigation.js +61 -31
  178. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  179. package/dist/shims/ppr-fallback-shell.js +28 -7
  180. package/dist/shims/router.d.ts +13 -2
  181. package/dist/shims/router.js +419 -128
  182. package/dist/shims/server.d.ts +16 -1
  183. package/dist/shims/server.js +44 -12
  184. package/dist/shims/unified-request-context.js +1 -0
  185. package/dist/utils/built-asset-url.d.ts +4 -0
  186. package/dist/utils/built-asset-url.js +11 -0
  187. package/dist/utils/commonjs-loader.d.ts +16 -0
  188. package/dist/utils/commonjs-loader.js +100 -0
  189. package/dist/utils/deployment-id.d.ts +8 -0
  190. package/dist/utils/deployment-id.js +22 -0
  191. package/dist/utils/html-limited-bots.d.ts +18 -1
  192. package/dist/utils/html-limited-bots.js +23 -1
  193. package/dist/utils/parse-cookie.d.ts +13 -0
  194. package/dist/utils/parse-cookie.js +52 -0
  195. package/dist/utils/path.d.ts +7 -1
  196. package/dist/utils/path.js +9 -1
  197. package/package.json +2 -2
  198. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  199. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -0,0 +1,91 @@
1
+ import { consumeDynamicUsage, consumeInvalidDynamicUsageError } from "../shims/headers.js";
2
+ import { _consumeRequestScopedCacheLife } from "../shims/cache.js";
3
+ import { getCollectedFetchTags } from "../shims/fetch-cache.js";
4
+ import { readStreamAsText } from "../utils/text-stream.js";
5
+ import { teeAppPageRscStreamForCapture } from "./app-page-execution.js";
6
+ import { consumeAppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope } from "./app-page-render-observation.js";
7
+ import { isAppSsrRenderResult } from "./app-page-stream.js";
8
+ import { buildAppPageTags } from "./implicit-tags.js";
9
+ //#region src/server/app-page-cache-render.ts
10
+ /**
11
+ * Render an App page element to HTML (and optionally its RSC payload) for cache
12
+ * storage. Combines the RSC stream, SSR handler, observation consumption, and
13
+ * cache-tag construction used by both normal ISR revalidation and PPR fallback
14
+ * shell regeneration.
15
+ */
16
+ async function renderAppPageCacheArtifacts(options) {
17
+ const rscCapture = teeAppPageRscStreamForCapture(options.renderToReadableStream(options.element, { onError: options.onError }), options.captureRscData);
18
+ const capturedRscDataRef = { value: null };
19
+ const htmlResult = await (await options.loadSsrHandler()).handleSsr(rscCapture.ssrStream, options.getNavigationContext(), {
20
+ links: options.getFontLinks(),
21
+ styles: options.getFontStyles(),
22
+ preloads: options.getFontPreloads()
23
+ }, {
24
+ basePath: options.basePath,
25
+ clientTraceMetadata: options.clientTraceMetadata,
26
+ reactMaxHeadersLength: options.reactMaxHeadersLength,
27
+ rootParams: options.rootParams,
28
+ waitForAllReady: options.waitForAllReady,
29
+ ...rscCapture.sideStream ? {
30
+ sideStream: rscCapture.sideStream,
31
+ capturedRscDataRef
32
+ } : {}
33
+ });
34
+ const html = await readStreamAsText(isAppSsrRenderResult(htmlResult) ? htmlResult.htmlStream : htmlResult);
35
+ let rscData;
36
+ if (options.captureRscData) {
37
+ const capturedPromise = capturedRscDataRef.value;
38
+ if (!capturedPromise) throw new Error("[vinext] Expected captured RSC data while rendering app page cache artifacts");
39
+ rscData = await capturedPromise;
40
+ }
41
+ const cacheLife = _consumeRequestScopedCacheLife();
42
+ const tags = buildAppPageTags(options.cleanPathname, getCollectedFetchTags(), options.route.routeSegments);
43
+ const observationState = consumeAppPageRenderObservationState();
44
+ consumeInvalidDynamicUsageError();
45
+ consumeDynamicUsage();
46
+ const result = {
47
+ html,
48
+ htmlRenderObservation: createAppPageRenderObservation({
49
+ boundaryOutcome: { kind: "success" },
50
+ cacheability: "public",
51
+ cacheTags: tags,
52
+ cleanPathname: options.cleanPathname,
53
+ completeness: "complete",
54
+ output: createAppPageHtmlOutputScope({
55
+ element: options.element,
56
+ renderEpoch: null,
57
+ rootBoundaryId: null,
58
+ routePattern: options.route.pattern
59
+ }),
60
+ params: options.navigationParams,
61
+ state: observationState
62
+ }),
63
+ tags,
64
+ cacheControl: typeof cacheLife?.revalidate === "number" ? {
65
+ revalidate: cacheLife.revalidate,
66
+ expire: cacheLife.expire
67
+ } : void 0
68
+ };
69
+ if (options.captureRscData) {
70
+ result.rscData = rscData;
71
+ result.rscRenderObservation = createAppPageRenderObservation({
72
+ boundaryOutcome: { kind: "success" },
73
+ cacheability: "public",
74
+ cacheTags: tags,
75
+ cleanPathname: options.cleanPathname,
76
+ completeness: "complete",
77
+ output: createAppPageRscOutputScope({
78
+ element: options.element,
79
+ mountedSlotsHeader: options.mountedSlotsHeader,
80
+ renderEpoch: null,
81
+ rootBoundaryId: null,
82
+ routePattern: options.route.pattern
83
+ }),
84
+ params: options.navigationParams,
85
+ state: observationState
86
+ });
87
+ }
88
+ return result;
89
+ }
90
+ //#endregion
91
+ export { renderAppPageCacheArtifacts };
@@ -1,8 +1,8 @@
1
1
  import { RenderObservation } from "./cache-proof.js";
2
2
  import { CacheControlMetadata, CachedAppPageValue } from "../shims/cache.js";
3
+ import { AppPageRenderObservationState } from "./app-page-render-observation.js";
3
4
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
4
5
  import { ISRCacheEntry } from "./isr-cache.js";
5
- import { AppPageRenderObservationState } from "./app-page-render-observation.js";
6
6
 
7
7
  //#region src/server/app-page-cache.d.ts
8
8
  type AppPageDebugLogger = (event: string, detail: string) => void;
@@ -70,6 +70,19 @@ type ReadAppPageCacheResponseOptions = {
70
70
  renderFreshPageForCache: () => Promise<AppPageCacheRenderResult>;
71
71
  scheduleBackgroundRegeneration: AppPageBackgroundRegenerator;
72
72
  };
73
+ type ReadAppPageFallbackShellCacheResponseOptions = {
74
+ clearRequestContext: () => void;
75
+ expireSeconds?: number;
76
+ fallbackPathname: string;
77
+ isEdgeRuntime?: boolean;
78
+ isrDebug?: AppPageDebugLogger;
79
+ isrGet: AppPageCacheGetter;
80
+ isrHtmlKey: (pathname: string) => string;
81
+ middlewareHeaders?: Headers | null;
82
+ middlewareStatus?: number | null;
83
+ revalidateSeconds: number;
84
+ rewriteHtml: (html: string) => string;
85
+ };
73
86
  type FinalizeAppPageHtmlCacheResponseOptions = {
74
87
  capturedDynamicUsageBeforeContextCleanup?: () => boolean;
75
88
  capturedRscDataPromise: Promise<ArrayBuffer> | null;
@@ -113,8 +126,9 @@ type ScheduleAppPageRscCacheWriteOptions = {
113
126
  declare function buildAppPageCacheTags(pathname: string, extraTags: readonly string[]): string[];
114
127
  declare function buildAppPageCachedResponse(cachedValue: CachedAppPageValue, options: BuildAppPageCachedResponseOptions): Response | null;
115
128
  declare function readAppPageCacheResponse(options: ReadAppPageCacheResponseOptions): Promise<Response | null>;
129
+ declare function readAppPageFallbackShellCacheResponse(options: ReadAppPageFallbackShellCacheResponseOptions): Promise<Response | null>;
116
130
  declare function finalizeAppPageHtmlCacheResponse(response: Response, options: FinalizeAppPageHtmlCacheResponseOptions): Response;
117
131
  declare function finalizeAppPageRscCacheResponse(response: Response, options: ScheduleAppPageRscCacheWriteOptions): Response;
118
132
  declare function scheduleAppPageRscCacheWrite(options: ScheduleAppPageRscCacheWriteOptions): boolean;
119
133
  //#endregion
120
- export { AppPageCacheOutcomeMetric, buildAppPageCacheTags, buildAppPageCachedResponse, finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse, readAppPageCacheResponse, scheduleAppPageRscCacheWrite };
134
+ export { AppPageCacheOutcomeMetric, buildAppPageCacheTags, buildAppPageCachedResponse, finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse, readAppPageCacheResponse, readAppPageFallbackShellCacheResponse, scheduleAppPageRscCacheWrite };
@@ -10,6 +10,7 @@ import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js
10
10
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
11
11
  import { hasCompleteNegativeRequestApiProof } from "./cache-proof.js";
12
12
  import { createEmptyAppPageRenderObservationState } from "./app-page-render-observation.js";
13
+ import { isAppPprDynamicFallbackShellHtml } from "./app-ppr-fallback-shell.js";
13
14
  //#region src/server/app-page-cache.ts
14
15
  /**
15
16
  * Apply the CDN cache adapter's headers to a freshly-streamed response whose
@@ -121,6 +122,29 @@ function buildAppPageCachedResponse(cachedValue, options) {
121
122
  headers: htmlHeaders
122
123
  });
123
124
  }
125
+ async function serveAppPageCachedHtml(options, transformValue) {
126
+ if (typeof options.cachedValue.html !== "string" || options.cachedValue.html.length === 0) {
127
+ if (options.cached?.isStale) options.scheduleRegeneration();
128
+ options.isrDebug?.(options.emptyDebugMessage, options.pathname);
129
+ return null;
130
+ }
131
+ const cacheState = options.cached?.isStale ? "STALE" : "HIT";
132
+ if (options.cached?.isStale) options.scheduleRegeneration();
133
+ const response = buildAppPageCachedResponse(transformValue ? transformValue(options.cachedValue) : options.cachedValue, {
134
+ cacheState,
135
+ cacheControl: options.cached?.value.cacheControl,
136
+ expireSeconds: options.expireSeconds,
137
+ isEdgeRuntime: options.isEdgeRuntime,
138
+ isRscRequest: false,
139
+ middlewareHeaders: options.middlewareHeaders,
140
+ middlewareStatus: options.middlewareStatus,
141
+ revalidateSeconds: options.revalidateSeconds
142
+ });
143
+ if (!response) return null;
144
+ options.isrDebug?.(`${cacheState} (${options.stateDebugLabel})`, options.pathname);
145
+ options.clearRequestContext();
146
+ return response;
147
+ }
124
148
  async function readAppPageCacheResponse(options) {
125
149
  const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
126
150
  const artifact = options.isRscRequest ? "rsc" : "html";
@@ -239,6 +263,43 @@ async function readAppPageCacheResponse(options) {
239
263
  }
240
264
  return null;
241
265
  }
266
+ async function readAppPageFallbackShellCacheResponse(options) {
267
+ const isrKey = options.isrHtmlKey(options.fallbackPathname);
268
+ try {
269
+ const cached = await options.isrGet(isrKey);
270
+ const cachedValue = getCachedAppPageValue(cached);
271
+ if (!cachedValue) {
272
+ options.isrDebug?.("MISS (fallback shell)", options.fallbackPathname);
273
+ return null;
274
+ }
275
+ if (isAppPprDynamicFallbackShellHtml(cachedValue.html)) {
276
+ options.isrDebug?.("MISS (dynamic fallback shell requires resume)", options.fallbackPathname);
277
+ return null;
278
+ }
279
+ return await serveAppPageCachedHtml({
280
+ cached,
281
+ cachedValue,
282
+ clearRequestContext: options.clearRequestContext,
283
+ emptyDebugMessage: "MISS (empty fallback shell)",
284
+ expireSeconds: options.expireSeconds,
285
+ isEdgeRuntime: options.isEdgeRuntime,
286
+ isrDebug: options.isrDebug,
287
+ middlewareHeaders: options.middlewareHeaders,
288
+ middlewareStatus: options.middlewareStatus,
289
+ pathname: options.fallbackPathname,
290
+ revalidateSeconds: options.revalidateSeconds,
291
+ scheduleRegeneration() {},
292
+ stateDebugLabel: "fallback shell"
293
+ }, (value) => ({
294
+ ...value,
295
+ html: options.rewriteHtml(value.html)
296
+ }));
297
+ } catch (isrReadError) {
298
+ options.isrDebug?.("MISS (fallback shell read error)", options.fallbackPathname);
299
+ console.error("[vinext] ISR fallback shell cache read error:", isrReadError);
300
+ return null;
301
+ }
302
+ }
242
303
  function finalizeAppPageHtmlCacheResponse(response, options) {
243
304
  if (!response.body) return response;
244
305
  const [streamForClient, streamForCache] = response.body.tee();
@@ -334,4 +395,4 @@ function scheduleAppPageRscCacheWrite(options) {
334
395
  return true;
335
396
  }
336
397
  //#endregion
337
- export { buildAppPageCacheTags, buildAppPageCachedResponse, finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse, readAppPageCacheResponse, scheduleAppPageRscCacheWrite };
398
+ export { buildAppPageCacheTags, buildAppPageCachedResponse, finalizeAppPageHtmlCacheResponse, finalizeAppPageRscCacheResponse, readAppPageCacheResponse, readAppPageFallbackShellCacheResponse, scheduleAppPageRscCacheWrite };
@@ -11,6 +11,7 @@ import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
11
11
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
12
12
  import { ISRCacheEntry } from "./isr-cache.js";
13
13
  import { FetchCacheMode } from "../shims/fetch-cache.js";
14
+ import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
14
15
  import { ValidateAppPageDynamicParamsOptions } from "./app-page-request.js";
15
16
  import { ReactNode } from "react";
16
17
  import { ReactFormState } from "react-dom/client";
@@ -36,6 +37,7 @@ type AppPageDispatchIntercept<TPage = unknown> = {
36
37
  slotId?: string | null;
37
38
  slotKey: string;
38
39
  sourceRouteIndex: number;
40
+ sourcePageSegments?: readonly string[] | null;
39
41
  };
40
42
  type AppPageDispatchInterceptOptions<TPage = unknown> = {
41
43
  interceptionContext: string | null;
@@ -45,6 +47,7 @@ type AppPageDispatchInterceptOptions<TPage = unknown> = {
45
47
  interceptSlotId?: string | null;
46
48
  interceptSlotKey: string;
47
49
  interceptSourceMatchedUrl?: string | null;
50
+ interceptSourcePageSegments?: readonly string[] | null;
48
51
  };
49
52
  type AppPageModule = {
50
53
  default?: unknown;
@@ -120,6 +123,7 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
120
123
  getNavigationContext: () => NavigationContext | null;
121
124
  getSourceRoute: (sourceRouteIndex: number) => TRoute | undefined;
122
125
  hasGenerateStaticParams: boolean;
126
+ hasCustomGlobalError?: boolean;
123
127
  hasPageDefaultExport: boolean;
124
128
  hasPageModule: boolean;
125
129
  handlerStart: number;
@@ -138,6 +142,20 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
138
142
  middlewareContext: AppPageMiddlewareContext;
139
143
  mountedSlotsHeader?: string | null;
140
144
  params: AppPageParams;
145
+ pprFallbackCacheShells?: readonly AppPagePprFallbackCacheShell[] | null;
146
+ pprFallbackShell?: {
147
+ fallbackParamNames: readonly string[];
148
+ routePattern: string;
149
+ };
150
+ /**
151
+ * Set of concrete URL paths that were pre-rendered at build time for this
152
+ * route. When the exact cache entry for a known pregenerated path is absent
153
+ * (evicted, stale-empty, cold start, read error), the fallback shell must
154
+ * NOT be served — the route is a valid generated route whose cache merely
155
+ * has a transient gap. Falls through to a fresh render instead.
156
+ */
157
+ renderedConcreteUrlPaths?: ReadonlySet<string>;
158
+ skipStaticParamsValidation?: boolean;
141
159
  staticParamsValidationParams?: AppPageParams;
142
160
  rootParams?: RootParams;
143
161
  probeLayoutAt: (layoutIndex: number, layoutParamAccess?: AppLayoutParamAccessTracker) => unknown;
@@ -152,10 +170,18 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
152
170
  }, middlewareContext: AppPageMiddlewareContext | null) => Promise<Response | null>;
153
171
  renderToReadableStream: (element: AppPageRenderableElement, options: {
154
172
  onError: AppPageBoundaryOnError;
173
+ signal?: AbortSignal;
155
174
  }) => ReadableStream<Uint8Array>;
175
+ prerenderToReadableStream?: (element: AppPageRenderableElement, options: {
176
+ onError: AppPageBoundaryOnError;
177
+ signal?: AbortSignal;
178
+ }) => Promise<{
179
+ prelude: ReadableStream<Uint8Array>;
180
+ }>;
156
181
  request: Request;
157
182
  revalidateSeconds: number | null;
158
183
  resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;
184
+ resolveRouteDynamicConfig?: (route: TRoute) => string | null | undefined;
159
185
  rootForbiddenModule?: AppPageModule | null;
160
186
  rootNotFoundModule?: AppPageModule | null;
161
187
  rootUnauthorizedModule?: AppPageModule | null;
@@ -1,29 +1,31 @@
1
1
  import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
- import { consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, markDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
3
+ import { beginPprFallbackShellFinalRender, createPprFallbackShellState, getPprFallbackShellState, runWithPprFallbackShellState } from "../shims/ppr-fallback-shell.js";
4
+ import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, markDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
4
5
  import { _consumeRequestScopedCacheLife, _peekRequestScopedCacheLife } from "../shims/cache.js";
5
6
  import { AppElementsWire } from "./app-elements-wire.js";
6
7
  import { shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
7
8
  import "./app-elements.js";
8
- import { consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
9
+ import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
9
10
  import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
10
- import { readStreamAsText } from "../utils/text-stream.js";
11
11
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
12
12
  import "./app-page-response.js";
13
- import { buildAppPageSpecialErrorResponse, resolveAppPageSpecialError, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
13
+ import { buildAppPageSpecialErrorResponse, probeAppPageThrownError, resolveAppPageSpecialError } from "./app-page-execution.js";
14
14
  import { createAppPageTreePath } from "./app-page-route-wiring.js";
15
- import { createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope } from "./app-page-render-observation.js";
16
- import { readAppPageCacheResponse } from "./app-page-cache.js";
15
+ import { consumeAppPageRenderObservationState, discardAppPageRenderState } from "./app-page-render-observation.js";
16
+ import { rewriteAppPprFallbackShellHtmlNavigation } from "./app-ppr-fallback-shell.js";
17
+ import { readAppPageCacheResponse, readAppPageFallbackShellCacheResponse } from "./app-page-cache.js";
17
18
  import { resolveAppPageParentHttpAccessBoundary, resolveAppPageParentHttpAccessBoundaryModule } from "./app-page-boundary.js";
18
- import { isAppSsrRenderResult } from "./app-page-stream.js";
19
19
  import { createAppLayoutParamAccessTracker, isAppLayoutObservationUnsafeForStaticReuse } from "./app-layout-param-observation.js";
20
+ import { buildAppPageTags } from "./implicit-tags.js";
21
+ import { renderAppPageCacheArtifacts } from "./app-page-cache-render.js";
22
+ import { warmPprFallbackShellCaches } from "./app-ppr-fallback-shell-render.js";
20
23
  import { resolveAppPageMethodResponse } from "./app-page-method.js";
21
24
  import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
22
25
  import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
23
26
  import { buildAppPageElement, resolveAppPageIntercept, resolveAppPageInterceptionRerenderTarget, validateAppPageDynamicParams } from "./app-page-request.js";
24
27
  import { renderAppPageLifecycle } from "./app-page-render.js";
25
28
  import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
26
- import { buildPageCacheTags } from "./implicit-tags.js";
27
29
  import React from "react";
28
30
  //#region src/server/app-page-dispatch.ts
29
31
  function resolveAppPageRouteBoundaryModule(route, statusCode) {
@@ -107,9 +109,6 @@ function shouldReadAppPageCache(options) {
107
109
  function hasSearchParams(searchParams) {
108
110
  return searchParams !== null && searchParams !== void 0 && searchParams.size > 0;
109
111
  }
110
- function buildAppPageTags(cleanPathname, extraTags, routeSegments) {
111
- return buildPageCacheTags(cleanPathname, extraTags, [...routeSegments], "page");
112
- }
113
112
  async function runAppPageRevalidationContext(options, renderFn) {
114
113
  return runWithRequestContext(createRequestContext({
115
114
  headersContext: createStaticGenerationHeadersContext({
@@ -119,6 +118,7 @@ async function runAppPageRevalidationContext(options, renderFn) {
119
118
  routePattern: options.routePattern
120
119
  }),
121
120
  currentFetchCacheMode: options.currentFetchCacheMode ?? null,
121
+ currentForceDynamicFetchDefault: options.dynamicConfig === "force-dynamic",
122
122
  executionContext: getRequestExecutionContext(),
123
123
  unstableCacheRevalidation: "foreground"
124
124
  }), async () => {
@@ -132,10 +132,6 @@ async function runAppPageRevalidationContext(options, renderFn) {
132
132
  return await runWithFetchDedupe(renderFn);
133
133
  });
134
134
  }
135
- function getCapturedRscDataPromise(capturedRscDataPromise) {
136
- if (!capturedRscDataPromise) throw new Error("[vinext] Expected captured RSC data while regenerating an app page cache entry");
137
- return capturedRscDataPromise;
138
- }
139
135
  function toInterceptOptions(interceptionContext, intercept) {
140
136
  return {
141
137
  interceptionContext,
@@ -144,11 +140,77 @@ function toInterceptOptions(interceptionContext, intercept) {
144
140
  interceptParams: intercept.matchedParams,
145
141
  interceptSlotId: intercept.slotId ?? null,
146
142
  interceptSlotKey: intercept.slotKey,
147
- interceptSourceMatchedUrl: interceptionContext
143
+ interceptSourceMatchedUrl: interceptionContext,
144
+ interceptSourcePageSegments: intercept.sourcePageSegments ?? null
145
+ };
146
+ }
147
+ /**
148
+ * Request-phase fallback-shell gate. Callers must run the exact cache read and
149
+ * static-param validation before this classification step.
150
+ */
151
+ function classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
152
+ if (options.renderedConcreteUrlPaths?.has(options.cleanPathname) === true) return { kind: "skip-known-pregenerated-route" };
153
+ const fallbackShells = options.pprFallbackCacheShells;
154
+ if (!fallbackShells || fallbackShells.length === 0) return { kind: "skip-no-fallback-shells" };
155
+ if (options.isRscRequest) return { kind: "skip-rsc-request" };
156
+ if (options.request.method !== "GET") return { kind: "skip-non-get" };
157
+ if (!isForceStatic && hasSearchParams(options.searchParams)) return { kind: "skip-search-params" };
158
+ if (!shouldReadAppPageCache({
159
+ isDraftMode,
160
+ isForceDynamic,
161
+ isProgressiveActionRender: options.isProgressiveActionRender === true,
162
+ isProduction: options.isProduction,
163
+ isRscRequest: false,
164
+ revalidateSeconds: currentRevalidateSeconds,
165
+ scriptNonce: options.scriptNonce
166
+ })) return { kind: "skip-cache-disabled" };
167
+ return {
168
+ kind: "probe-fallback-shells",
169
+ fallbackShells
148
170
  };
149
171
  }
172
+ async function probePprFallbackShellCache(options, route, fallbackShells, currentRevalidateSeconds) {
173
+ for (const fallbackShell of fallbackShells) {
174
+ const fallbackShellResponse = await readAppPageFallbackShellCacheResponse({
175
+ clearRequestContext: options.clearRequestContext,
176
+ expireSeconds: options.expireSeconds,
177
+ fallbackPathname: fallbackShell.pathname,
178
+ isEdgeRuntime: options.isEdgeRuntime,
179
+ isrDebug: options.isrDebug,
180
+ isrGet: options.isrGet,
181
+ isrHtmlKey: options.isrHtmlKey,
182
+ middlewareHeaders: options.middlewareContext.headers,
183
+ middlewareStatus: options.middlewareContext.status,
184
+ revalidateSeconds: currentRevalidateSeconds ?? 0,
185
+ rewriteHtml(html) {
186
+ return rewriteAppPprFallbackShellHtmlNavigation({
187
+ html,
188
+ params: options.params,
189
+ pathname: options.cleanPathname,
190
+ searchParams: options.searchParams
191
+ });
192
+ }
193
+ });
194
+ if (fallbackShellResponse) return fallbackShellResponse;
195
+ }
196
+ return null;
197
+ }
198
+ async function tryServePprFallbackShell(options, route, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) {
199
+ const decision = classifyPprFallbackShellEligibility(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic);
200
+ switch (decision.kind) {
201
+ case "skip-known-pregenerated-route":
202
+ case "skip-no-fallback-shells":
203
+ case "skip-rsc-request":
204
+ case "skip-non-get":
205
+ case "skip-search-params":
206
+ case "skip-cache-disabled": return null;
207
+ case "probe-fallback-shells": return await probePprFallbackShellCache(options, route, decision.fallbackShells, currentRevalidateSeconds);
208
+ }
209
+ }
150
210
  async function dispatchAppPage(options) {
151
- return await runWithFetchDedupe(() => dispatchAppPageInner(options));
211
+ const dispatch = () => runWithFetchDedupe(() => dispatchAppPageInner(options));
212
+ if (!options.pprFallbackShell) return await dispatch();
213
+ return await runWithPprFallbackShellState(createPprFallbackShellState(options.pprFallbackShell), dispatch);
152
214
  }
153
215
  async function dispatchAppPageInner(options) {
154
216
  const route = options.route;
@@ -161,6 +223,7 @@ async function dispatchAppPageInner(options) {
161
223
  const layoutParamAccess = createAppLayoutParamAccessTracker();
162
224
  setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
163
225
  setCurrentFetchCacheMode(options.fetchCache ?? null);
226
+ setCurrentForceDynamicFetchDefault(isForceDynamic);
164
227
  if (options.hasPageModule && !options.hasPageDefaultExport) {
165
228
  options.clearRequestContext();
166
229
  return new Response("Page has no default export", { status: 500 });
@@ -242,7 +305,7 @@ async function dispatchAppPageInner(options) {
242
305
  displayPathname: options.displayPathname,
243
306
  currentFetchCacheMode: options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
244
307
  draftModeSecret: options.draftModeSecret,
245
- dynamicConfig,
308
+ dynamicConfig: options.resolveRouteDynamicConfig?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? dynamicConfig : void 0),
246
309
  params: revalidationTarget.navigationParams,
247
310
  routePattern: revalidationTarget.route.pattern,
248
311
  routeSegments: revalidationTarget.route.routeSegments,
@@ -250,72 +313,34 @@ async function dispatchAppPageInner(options) {
250
313
  }, async () => {
251
314
  const revalidatedElement = await options.buildPageElement(revalidationTarget.route, revalidationTarget.params, revalidationTarget.interceptOpts, new URLSearchParams());
252
315
  const revalidatedOnError = options.createRscOnErrorHandler(options.cleanPathname, revalidationTarget.route.pattern);
253
- const revalidatedRscCapture = teeAppPageRscStreamForCapture(options.renderToReadableStream(revalidatedElement, { onError: revalidatedOnError }), true);
254
- const revalidatedSsrEntry = await options.loadSsrHandler();
255
- const revalidatedCapturedRscRef = { value: null };
256
- const revalidatedHtmlResult = await revalidatedSsrEntry.handleSsr(revalidatedRscCapture.ssrStream, options.getNavigationContext(), {
257
- links: options.getFontLinks(),
258
- styles: options.getFontStyles(),
259
- preloads: options.getFontPreloads()
260
- }, {
316
+ const rendered = await renderAppPageCacheArtifacts({
261
317
  basePath: options.basePath,
318
+ captureRscData: true,
319
+ cleanPathname: options.cleanPathname,
262
320
  clientTraceMetadata: options.clientTraceMetadata,
321
+ element: revalidatedElement,
322
+ getFontLinks: options.getFontLinks,
323
+ getFontPreloads: options.getFontPreloads,
324
+ getFontStyles: options.getFontStyles,
325
+ getNavigationContext: options.getNavigationContext,
326
+ loadSsrHandler: options.loadSsrHandler,
327
+ mountedSlotsHeader: options.mountedSlotsHeader,
328
+ navigationParams: revalidationTarget.navigationParams,
329
+ onError: revalidatedOnError,
263
330
  reactMaxHeadersLength: options.reactMaxHeadersLength,
331
+ renderToReadableStream: options.renderToReadableStream,
264
332
  rootParams: options.rootParams,
265
- waitForAllReady: true,
266
- ...revalidatedRscCapture.sideStream ? {
267
- sideStream: revalidatedRscCapture.sideStream,
268
- capturedRscDataRef: revalidatedCapturedRscRef
269
- } : {}
333
+ route: revalidationTarget.route,
334
+ waitForAllReady: true
270
335
  });
271
- const html = await readStreamAsText(isAppSsrRenderResult(revalidatedHtmlResult) ? revalidatedHtmlResult.htmlStream : revalidatedHtmlResult);
272
- const rscData = await getCapturedRscDataPromise(revalidatedCapturedRscRef.value);
273
- const cacheLife = _consumeRequestScopedCacheLife();
274
336
  options.clearRequestContext();
275
- const tags = buildAppPageTags(options.cleanPathname, getCollectedFetchTags(), revalidationTarget.route.routeSegments);
276
- const observationState = {
277
- dynamicFetches: consumeDynamicFetchObservations(),
278
- requestApis: consumeRenderRequestApiUsage()
279
- };
280
337
  return {
281
- html,
282
- htmlRenderObservation: createAppPageRenderObservation({
283
- boundaryOutcome: { kind: "success" },
284
- cacheability: "public",
285
- cacheTags: tags,
286
- cleanPathname: options.cleanPathname,
287
- completeness: "complete",
288
- output: createAppPageHtmlOutputScope({
289
- element: revalidatedElement,
290
- renderEpoch: null,
291
- rootBoundaryId: null,
292
- routePattern: revalidationTarget.route.pattern
293
- }),
294
- params: revalidationTarget.navigationParams,
295
- state: observationState
296
- }),
297
- rscData,
298
- rscRenderObservation: createAppPageRenderObservation({
299
- boundaryOutcome: { kind: "success" },
300
- cacheability: "public",
301
- cacheTags: tags,
302
- cleanPathname: options.cleanPathname,
303
- completeness: "complete",
304
- output: createAppPageRscOutputScope({
305
- element: revalidatedElement,
306
- mountedSlotsHeader: options.mountedSlotsHeader,
307
- renderEpoch: null,
308
- rootBoundaryId: null,
309
- routePattern: revalidationTarget.route.pattern
310
- }),
311
- params: revalidationTarget.navigationParams,
312
- state: observationState
313
- }),
314
- tags,
315
- cacheControl: typeof cacheLife?.revalidate === "number" ? {
316
- revalidate: cacheLife.revalidate,
317
- expire: cacheLife.expire
318
- } : void 0
338
+ html: rendered.html,
339
+ htmlRenderObservation: rendered.htmlRenderObservation,
340
+ rscData: rendered.rscData,
341
+ rscRenderObservation: rendered.rscRenderObservation,
342
+ tags: rendered.tags,
343
+ cacheControl: rendered.cacheControl
319
344
  };
320
345
  });
321
346
  },
@@ -329,18 +354,23 @@ async function dispatchAppPageInner(options) {
329
354
  });
330
355
  if (cachedPageResponse) return cachedPageResponse;
331
356
  }
332
- const dynamicParamsResponse = await validateAppPageDynamicParams({
333
- clearRequestContext: options.clearRequestContext,
334
- enforceStaticParamsOnly: options.dynamicParamsConfig === false,
335
- generateStaticParams: options.generateStaticParams,
336
- isDynamicRoute: route.isDynamic,
337
- params: options.staticParamsValidationParams ?? options.params
338
- });
339
- if (dynamicParamsResponse) return dynamicParamsResponse;
357
+ if (options.skipStaticParamsValidation !== true) {
358
+ const dynamicParamsResponse = await validateAppPageDynamicParams({
359
+ clearRequestContext: options.clearRequestContext,
360
+ enforceStaticParamsOnly: options.dynamicParamsConfig === false,
361
+ generateStaticParams: options.generateStaticParams,
362
+ isDynamicRoute: route.isDynamic,
363
+ params: options.staticParamsValidationParams ?? options.params
364
+ });
365
+ if (dynamicParamsResponse) return dynamicParamsResponse;
366
+ }
367
+ const fallbackShellResponse = await tryServePprFallbackShell(options, route, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic);
368
+ if (fallbackShellResponse) return fallbackShellResponse;
340
369
  const interceptResult = await resolveAppPageIntercept({
341
370
  async buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess) {
342
371
  await options.ensureRouteLoaded?.(interceptRoute);
343
372
  setCurrentFetchCacheMode(options.resolveRouteFetchCacheMode?.(interceptRoute) ?? null);
373
+ setCurrentForceDynamicFetchDefault(options.resolveRouteDynamicConfig?.(interceptRoute) === "force-dynamic");
344
374
  return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, interceptLayoutParamAccess);
345
375
  },
346
376
  cleanPathname: options.cleanPathname,
@@ -380,11 +410,20 @@ async function dispatchAppPageInner(options) {
380
410
  }
381
411
  });
382
412
  if (interceptResult.response) return interceptResult.response;
383
- const pageBuildResult = await buildAppPageElement({
413
+ const buildCurrentPageElement = () => buildAppPageElement({
384
414
  buildPageElement() {
385
415
  if (options.actionFailed) throw options.actionError;
386
416
  return options.buildPageElement(route, options.params, interceptResult.interceptOpts, options.searchParams, layoutParamAccess);
387
417
  },
418
+ async probePageSpecialError() {
419
+ if (!shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") && route.loading?.default) return null;
420
+ return resolveAppPageSpecialError(await probeAppPageThrownError({
421
+ probePage: options.probePage,
422
+ runWithSuppressedHookWarning(probe) {
423
+ return options.runWithSuppressedHookWarning(probe);
424
+ }
425
+ }));
426
+ },
388
427
  renderErrorBoundaryPage(buildError) {
389
428
  return options.renderErrorBoundaryPage(buildError);
390
429
  },
@@ -393,6 +432,19 @@ async function dispatchAppPageInner(options) {
393
432
  },
394
433
  resolveSpecialError: resolveAppPageSpecialError
395
434
  });
435
+ const fallbackShellState = getPprFallbackShellState();
436
+ if (fallbackShellState && process.env.VINEXT_PRERENDER === "1" && !options.isRscRequest) {
437
+ const warmupBuildResult = await buildCurrentPageElement();
438
+ if (warmupBuildResult.response) return warmupBuildResult.response;
439
+ await warmPprFallbackShellCaches({
440
+ element: warmupBuildResult.element,
441
+ onError: options.createRscOnErrorHandler(options.cleanPathname, route.pattern),
442
+ renderToReadableStream: options.renderToReadableStream,
443
+ state: fallbackShellState
444
+ });
445
+ discardAppPageRenderState();
446
+ }
447
+ const pageBuildResult = await buildCurrentPageElement();
396
448
  if (pageBuildResult.response) return pageBuildResult.response;
397
449
  const navigationParams = resolveAppPageNavigationParams(route, options.params, options.cleanPathname, interceptResult.interceptOpts);
398
450
  options.setNavigationContext({
@@ -401,6 +453,9 @@ async function dispatchAppPageInner(options) {
401
453
  params: navigationParams
402
454
  });
403
455
  const layoutClassifications = getEffectiveLayoutClassifications(route, options.debugClassification);
456
+ const activeFallbackShellState = getPprFallbackShellState();
457
+ const pprFallbackShellSignal = activeFallbackShellState?.abortController.signal;
458
+ const pprFallbackShellReactSignal = activeFallbackShellState?.reactAbortController.signal;
404
459
  return renderAppPageLifecycle({
405
460
  basePath: options.basePath,
406
461
  clientTraceMetadata: options.clientTraceMetadata,
@@ -409,12 +464,7 @@ async function dispatchAppPageInner(options) {
409
464
  clearRequestContext: options.clearRequestContext,
410
465
  consumeDynamicUsage,
411
466
  consumeInvalidDynamicUsageError,
412
- consumeRenderObservationState() {
413
- return {
414
- dynamicFetches: consumeDynamicFetchObservations(),
415
- requestApis: consumeRenderRequestApiUsage()
416
- };
417
- },
467
+ consumeRenderObservationState: consumeAppPageRenderObservationState,
418
468
  createRscOnErrorHandler(pathname, routePath) {
419
469
  return options.createRscOnErrorHandler(pathname, routePath);
420
470
  },
@@ -457,6 +507,11 @@ async function dispatchAppPageInner(options) {
457
507
  middlewareContext: options.middlewareContext,
458
508
  navigationParams,
459
509
  params: options.params,
510
+ pprFallbackShellSignal,
511
+ pprFallbackShellReactSignal,
512
+ abortPprFallbackShell: activeFallbackShellState ? () => {
513
+ beginPprFallbackShellFinalRender(activeFallbackShellState);
514
+ } : void 0,
460
515
  layoutParamAccess,
461
516
  rootParams: options.rootParams,
462
517
  peekRenderObservationState() {
@@ -509,6 +564,8 @@ async function dispatchAppPageInner(options) {
509
564
  return renderPageSpecialError(options, specialError);
510
565
  },
511
566
  renderToReadableStream: options.renderToReadableStream,
567
+ hasCustomGlobalError: options.hasCustomGlobalError,
568
+ prerenderToReadableStream: options.prerenderToReadableStream,
512
569
  routePattern: route.pattern,
513
570
  runWithSuppressedHookWarning(probe) {
514
571
  return options.runWithSuppressedHookWarning(probe);