vinext 0.2.0 → 1.0.0-beta.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 (168) hide show
  1. package/README.md +50 -29
  2. package/dist/build/client-build-config.d.ts +13 -92
  3. package/dist/build/client-build-config.js +17 -95
  4. package/dist/build/css-url-assets.d.ts +3 -1
  5. package/dist/build/css-url-assets.js +18 -1
  6. package/dist/build/inject-pregenerated-paths.d.ts +3 -0
  7. package/dist/build/inject-pregenerated-paths.js +4 -1
  8. package/dist/build/prerender-paths.d.ts +23 -0
  9. package/dist/build/prerender-paths.js +296 -0
  10. package/dist/build/prerender-server-entry.d.ts +1 -0
  11. package/dist/build/prerender-server-entry.js +49 -0
  12. package/dist/build/prerender-server-pool.d.ts +44 -0
  13. package/dist/build/prerender-server-pool.js +194 -0
  14. package/dist/build/prerender.d.ts +12 -1
  15. package/dist/build/prerender.js +87 -23
  16. package/dist/build/run-prerender.js +2 -1
  17. package/dist/cache/cache-adapters-virtual.d.ts +7 -1
  18. package/dist/cache/cache-adapters-virtual.js +26 -2
  19. package/dist/check.d.ts +4 -6
  20. package/dist/check.js +13 -9
  21. package/dist/cli.js +34 -54
  22. package/dist/client/vinext-next-data.d.ts +4 -1
  23. package/dist/config/config-matchers.js +33 -11
  24. package/dist/config/next-config.d.ts +36 -6
  25. package/dist/config/next-config.js +17 -4
  26. package/dist/config/prerender.d.ts +11 -1
  27. package/dist/config/prerender.js +19 -1
  28. package/dist/config/tsconfig-paths.js +5 -1
  29. package/dist/entries/app-browser-entry.js +5 -1
  30. package/dist/entries/app-rsc-entry.d.ts +3 -2
  31. package/dist/entries/app-rsc-entry.js +4 -0
  32. package/dist/entries/pages-client-entry.js +14 -3
  33. package/dist/entries/pages-server-entry.js +18 -4
  34. package/dist/image/image-adapters-virtual.js +1 -0
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +549 -152
  37. package/dist/init-cloudflare.js +12 -3
  38. package/dist/init-platform.d.ts +10 -1
  39. package/dist/init-platform.js +78 -12
  40. package/dist/init.d.ts +11 -3
  41. package/dist/init.js +129 -31
  42. package/dist/plugins/fonts.js +1 -1
  43. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  44. package/dist/plugins/og-assets.js +2 -1
  45. package/dist/plugins/optimize-imports.js +1 -1
  46. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  47. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  48. package/dist/plugins/sass.d.ts +17 -1
  49. package/dist/plugins/sass.js +74 -1
  50. package/dist/plugins/styled-jsx.d.ts +16 -0
  51. package/dist/plugins/styled-jsx.js +149 -0
  52. package/dist/routing/app-route-graph.js +22 -16
  53. package/dist/routing/file-matcher.d.ts +8 -1
  54. package/dist/routing/file-matcher.js +15 -3
  55. package/dist/server/app-browser-entry.js +44 -14
  56. package/dist/server/app-browser-navigation-controller.js +5 -2
  57. package/dist/server/app-browser-server-action-client.js +5 -3
  58. package/dist/server/app-browser-state.d.ts +1 -0
  59. package/dist/server/app-browser-state.js +1 -1
  60. package/dist/server/app-layout-param-observation.d.ts +1 -1
  61. package/dist/server/app-page-boundary.js +2 -1
  62. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  63. package/dist/server/app-page-cache-finalizer.js +3 -3
  64. package/dist/server/app-page-cache-render.d.ts +1 -1
  65. package/dist/server/app-page-cache.js +23 -6
  66. package/dist/server/app-page-dispatch.d.ts +2 -1
  67. package/dist/server/app-page-dispatch.js +27 -10
  68. package/dist/server/app-page-element-builder.js +1 -0
  69. package/dist/server/app-page-execution.js +2 -1
  70. package/dist/server/app-page-render-identity.d.ts +1 -0
  71. package/dist/server/app-page-render-identity.js +2 -1
  72. package/dist/server/app-page-render.d.ts +3 -1
  73. package/dist/server/app-page-render.js +67 -16
  74. package/dist/server/app-page-response.d.ts +7 -0
  75. package/dist/server/app-page-response.js +16 -4
  76. package/dist/server/app-page-route-wiring.js +3 -3
  77. package/dist/server/app-page-stream.d.ts +2 -1
  78. package/dist/server/app-page-stream.js +1 -1
  79. package/dist/server/app-route-handler-execution.d.ts +1 -1
  80. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  81. package/dist/server/app-route-tree-prefetch.js +187 -0
  82. package/dist/server/app-router-entry.js +1 -1
  83. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  84. package/dist/server/app-rsc-cache-busting.js +9 -5
  85. package/dist/server/app-rsc-handler.d.ts +6 -0
  86. package/dist/server/app-rsc-handler.js +88 -10
  87. package/dist/server/app-rsc-render-mode.d.ts +3 -5
  88. package/dist/server/app-rsc-render-mode.js +5 -12
  89. package/dist/server/app-rsc-request-normalization.d.ts +3 -4
  90. package/dist/server/app-rsc-request-normalization.js +4 -5
  91. package/dist/server/app-server-action-execution.js +6 -5
  92. package/dist/server/app-ssr-entry.js +1 -1
  93. package/dist/server/cache-control.d.ts +3 -1
  94. package/dist/server/cache-control.js +13 -1
  95. package/dist/server/dev-module-runner.js +1 -1
  96. package/dist/server/dev-origin-check.d.ts +2 -2
  97. package/dist/server/dev-origin-check.js +2 -2
  98. package/dist/server/dev-server.d.ts +11 -1
  99. package/dist/server/dev-server.js +82 -24
  100. package/dist/server/headers.d.ts +6 -2
  101. package/dist/server/headers.js +11 -5
  102. package/dist/server/image-optimization.d.ts +12 -1
  103. package/dist/server/image-optimization.js +13 -1
  104. package/dist/server/isr-cache.d.ts +13 -4
  105. package/dist/server/isr-cache.js +8 -4
  106. package/dist/server/pages-data-route.d.ts +4 -2
  107. package/dist/server/pages-data-route.js +18 -4
  108. package/dist/server/pages-dev-module-url.d.ts +2 -1
  109. package/dist/server/pages-dev-module-url.js +6 -3
  110. package/dist/server/pages-node-compat.d.ts +12 -1
  111. package/dist/server/pages-node-compat.js +50 -1
  112. package/dist/server/pages-page-data.d.ts +9 -0
  113. package/dist/server/pages-page-data.js +18 -10
  114. package/dist/server/pages-page-handler.js +19 -7
  115. package/dist/server/pages-page-response.d.ts +1 -0
  116. package/dist/server/pages-page-response.js +5 -4
  117. package/dist/server/pages-request-pipeline.d.ts +8 -6
  118. package/dist/server/pages-request-pipeline.js +31 -7
  119. package/dist/server/pages-router-entry.js +1 -1
  120. package/dist/server/prerender-manifest.d.ts +15 -1
  121. package/dist/server/prerender-manifest.js +29 -1
  122. package/dist/server/prod-server.d.ts +10 -7
  123. package/dist/server/prod-server.js +43 -28
  124. package/dist/server/request-pipeline.js +1 -1
  125. package/dist/server/static-file-cache.js +1 -1
  126. package/dist/shims/cache-handler.js +8 -1
  127. package/dist/shims/cache.d.ts +1 -1
  128. package/dist/shims/cache.js +3 -0
  129. package/dist/shims/cdn-cache.d.ts +2 -7
  130. package/dist/shims/cdn-cache.js +2 -14
  131. package/dist/shims/fetch-cache.d.ts +3 -1
  132. package/dist/shims/fetch-cache.js +77 -52
  133. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  134. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  135. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
  136. package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
  137. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
  138. package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
  139. package/dist/shims/internal/pages-data-target.d.ts +8 -3
  140. package/dist/shims/internal/pages-data-target.js +9 -4
  141. package/dist/shims/link.d.ts +1 -1
  142. package/dist/shims/link.js +179 -42
  143. package/dist/shims/navigation.d.ts +15 -3
  144. package/dist/shims/navigation.js +202 -39
  145. package/dist/shims/request-context.js +18 -0
  146. package/dist/shims/request-state-types.d.ts +2 -2
  147. package/dist/shims/router.js +31 -15
  148. package/dist/shims/unified-request-context.d.ts +1 -1
  149. package/dist/shims/unified-request-context.js +1 -0
  150. package/dist/typegen.js +1 -1
  151. package/dist/utils/middleware-request-headers.js +1 -1
  152. package/dist/utils/project.d.ts +1 -1
  153. package/dist/utils/protocol-headers.d.ts +7 -1
  154. package/dist/utils/protocol-headers.js +7 -1
  155. package/dist/utils/vite-version.d.ts +4 -12
  156. package/dist/utils/vite-version.js +39 -21
  157. package/package.json +31 -13
  158. package/dist/cloudflare/index.d.ts +0 -3
  159. package/dist/cloudflare/index.js +0 -3
  160. package/dist/packages/cloudflare/src/cache/cdn-adapter.runtime.js +0 -102
  161. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +0 -126
  162. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +0 -435
  163. package/dist/packages/cloudflare/src/deploy-config.js +0 -150
  164. package/dist/packages/cloudflare/src/deploy-help.js +0 -55
  165. package/dist/packages/cloudflare/src/deploy.js +0 -276
  166. package/dist/packages/cloudflare/src/tpr.d.ts +0 -45
  167. package/dist/packages/cloudflare/src/tpr.js +0 -561
  168. package/dist/packages/cloudflare/src/utils/cache-control-metadata.js +0 -20
@@ -68,7 +68,7 @@ function resolveServerActionRequestState(options) {
68
68
  const headers = createRscRequestHeaders();
69
69
  headers.set(RSC_ACTION_HEADER, options.actionId);
70
70
  headers.set(NEXT_ACTION_HEADER, options.actionId);
71
- const interceptionContext = resolveInterceptionContextFromPreviousNextUrl(options.previousNextUrl, options.basePath);
71
+ const interceptionContext = resolveInterceptionContextFromPreviousNextUrl(options.previousNextUrl, options.basePath) ?? options.interceptionContext ?? null;
72
72
  if (interceptionContext !== null) headers.set(VINEXT_INTERCEPTION_CONTEXT_HEADER, interceptionContext);
73
73
  const mountedSlotsHeader = getMountedSlotIdsHeader(options.elements);
74
74
  if (mountedSlotsHeader !== null) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, mountedSlotsHeader);
@@ -1,7 +1,7 @@
1
- import { UnstableCacheObservation } from "../shims/cache-request-state.js";
2
1
  import { RenderRequestApiKind } from "./cache-proof.js";
3
2
  import { ClientReuseManifestRejectionCode, ClientReuseManifestTraceFields } from "./client-reuse-manifest.js";
4
3
  import { ThenableParamsObserver } from "../shims/thenable-params.js";
4
+ import { UnstableCacheObservation } from "../shims/cache-request-state.js";
5
5
 
6
6
  //#region src/server/app-layout-param-observation.d.ts
7
7
  type AppLayoutParamAccessObservation = Readonly<{
@@ -1,6 +1,6 @@
1
1
  import { runWithFetchDedupe } from "../shims/fetch-cache.js";
2
2
  import { resolveAppPageSegmentParams } from "./app-page-params.js";
3
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
3
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
4
4
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
5
5
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
6
6
  //#region src/server/app-page-boundary.ts
@@ -109,6 +109,7 @@ async function renderAppPageBoundaryResponse(options) {
109
109
  applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);
110
110
  mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
111
111
  applyRscCompatibilityIdHeader(headers);
112
+ applyRscDeploymentIdHeader(headers);
112
113
  return new Response(rscStream, {
113
114
  status: options.status,
114
115
  headers
@@ -50,6 +50,7 @@ type ScheduleAppPageRscCacheWriteOptions = {
50
50
  isrSet: AppPageCacheSetter;
51
51
  interceptionContext?: string | null;
52
52
  mountedSlotsHeader?: string | null;
53
+ omitPendingDynamicCacheState?: boolean;
53
54
  renderMode?: AppRscRenderMode;
54
55
  preserveClientResponseHeaders?: boolean;
55
56
  expireSeconds?: number;
@@ -83,7 +83,7 @@ function finalizeAppPageRscCacheResponse(response, options) {
83
83
  if (!scheduleAppPageRscCacheWrite(options)) return response;
84
84
  if (options.preserveClientResponseHeaders === true) return response;
85
85
  const clientHeaders = new Headers(response.headers);
86
- applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags());
86
+ applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
87
87
  return new Response(response.body, {
88
88
  status: response.status,
89
89
  statusText: response.statusText,
@@ -92,8 +92,8 @@ function finalizeAppPageRscCacheResponse(response, options) {
92
92
  }
93
93
  function scheduleAppPageRscCacheWrite(options) {
94
94
  const capturedRscDataPromise = options.capturedRscDataPromise;
95
- if (!capturedRscDataPromise || options.dynamicUsedDuringBuild) return false;
96
- const rscKey = options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext);
95
+ if (!capturedRscDataPromise || options.dynamicUsedDuringBuild || options.mountedSlotsHeader) return false;
96
+ const rscKey = options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext);
97
97
  const cachePromise = (async () => {
98
98
  try {
99
99
  const rscData = await capturedRscDataPromise;
@@ -1,8 +1,8 @@
1
- import { CacheControlMetadata } from "../shims/cache-handler.js";
2
1
  import { NavigationContext } from "../shims/navigation-context-state.js";
3
2
  import { AppPageFontPreload } from "./app-page-execution.js";
4
3
  import { RootParams } from "../shims/root-params.js";
5
4
  import { AppPageSsrHandler } from "./app-page-stream.js";
5
+ import { CacheControlMetadata } from "../shims/cache-handler.js";
6
6
  import { createAppPageRenderObservation } from "./app-page-render-observation.js";
7
7
  import { ReactNode } from "react";
8
8
 
@@ -4,7 +4,7 @@ import { applyCdnResponseHeaders } from "./cache-control.js";
4
4
  import { decideIsr } from "./isr-decision.js";
5
5
  import { buildAppPageCacheValue } from "./isr-cache.js";
6
6
  import { encodeCacheTag } from "../utils/encode-cache-tag.js";
7
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
7
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
8
8
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
9
9
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
10
10
  import { hasCompleteNegativeRequestApiProof } from "./cache-proof.js";
@@ -55,6 +55,15 @@ function getCachedAppPageValue(entry) {
55
55
  function hasQueryInvariantAppPageProof(cachedValue) {
56
56
  return cachedValue.renderObservation !== void 0 && hasCompleteNegativeRequestApiProof(cachedValue.renderObservation, ["searchParams"]);
57
57
  }
58
+ function resolveRegeneratedAppPageCachePolicy(options) {
59
+ let revalidateSeconds = options.routeRevalidateSeconds;
60
+ const renderRevalidateSeconds = options.renderCacheControl?.revalidate;
61
+ if (renderRevalidateSeconds !== void 0) revalidateSeconds = revalidateSeconds > 0 ? Math.min(revalidateSeconds, renderRevalidateSeconds) : renderRevalidateSeconds;
62
+ return {
63
+ expireSeconds: options.renderCacheControl?.expire ?? options.expireSeconds,
64
+ revalidateSeconds
65
+ };
66
+ }
58
67
  function buildAppPageCachedResponse(cachedValue, options) {
59
68
  const status = options.middlewareStatus ?? (cachedValue.status || 200);
60
69
  const { cacheControl } = decideIsr({
@@ -75,6 +84,7 @@ function buildAppPageCachedResponse(cachedValue, options) {
75
84
  mountedSlotsHeader: options.mountedSlotsHeader
76
85
  });
77
86
  applyRscCompatibilityIdHeader(rscHeaders);
87
+ applyRscDeploymentIdHeader(rscHeaders);
78
88
  return new Response(cachedValue.rscData, {
79
89
  status,
80
90
  headers: rscHeaders
@@ -118,7 +128,11 @@ async function serveAppPageCachedHtml(options, transformValue) {
118
128
  return response;
119
129
  }
120
130
  async function readAppPageCacheResponse(options) {
121
- const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
131
+ if (options.isRscRequest && options.mountedSlotsHeader) {
132
+ options.isrDebug?.("MISS (mounted slots RSC variant)", options.cleanPathname);
133
+ return null;
134
+ }
135
+ const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
122
136
  const artifact = options.isRscRequest ? "rsc" : "html";
123
137
  try {
124
138
  const cached = await options.isrGet(isrKey);
@@ -177,10 +191,13 @@ async function readAppPageCacheResponse(options) {
177
191
  if (cached?.isStale && cachedValue) {
178
192
  options.scheduleBackgroundRegeneration(isrKey, async () => {
179
193
  const revalidatedPage = await options.renderFreshPageForCache();
180
- const revalidateSeconds = revalidatedPage.cacheControl?.revalidate ?? options.revalidateSeconds;
181
- const expireSeconds = revalidatedPage.cacheControl?.expire ?? options.expireSeconds;
182
- const writes = [options.isrSet(options.isRscRequest ? isrKey : options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext), buildAppPageCacheValue("", revalidatedPage.rscData, 200, revalidatedPage.rscRenderObservation), revalidateSeconds, revalidatedPage.tags, expireSeconds)];
183
- if (!options.isRscRequest) writes.push(options.isrSet(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, 200, revalidatedPage.htmlRenderObservation, revalidatedPage.linkHeader ? { link: revalidatedPage.linkHeader } : void 0), revalidateSeconds, revalidatedPage.tags, expireSeconds));
194
+ const cachePolicy = resolveRegeneratedAppPageCachePolicy({
195
+ expireSeconds: options.expireSeconds,
196
+ renderCacheControl: revalidatedPage.cacheControl,
197
+ routeRevalidateSeconds: options.revalidateSeconds
198
+ });
199
+ const writes = [options.isrSet(options.isRscRequest ? isrKey : options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext), buildAppPageCacheValue("", revalidatedPage.rscData, 200, revalidatedPage.rscRenderObservation), cachePolicy.revalidateSeconds, revalidatedPage.tags, cachePolicy.expireSeconds)];
200
+ if (!options.isRscRequest) writes.push(options.isrSet(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, 200, revalidatedPage.htmlRenderObservation, revalidatedPage.linkHeader ? { link: revalidatedPage.linkHeader } : void 0), cachePolicy.revalidateSeconds, revalidatedPage.tags, cachePolicy.expireSeconds));
184
201
  await Promise.all(writes);
185
202
  options.isrDebug?.("regen complete", options.cleanPathname);
186
203
  });
@@ -1,5 +1,4 @@
1
1
  import { ClassificationReason } from "../build/layout-classification-types.js";
2
- import { CachedAppPageValue } from "../shims/cache-handler.js";
3
2
  import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
4
3
  import { AppOutgoingElements } from "./app-elements-wire.js";
5
4
  import { NavigationContext } from "../shims/navigation-context-state.js";
@@ -8,6 +7,7 @@ import { AppPageMiddlewareContext } from "./app-page-response.js";
8
7
  import { RootParams } from "../shims/root-params.js";
9
8
  import { AppPageSsrHandler } from "./app-page-stream.js";
10
9
  import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
10
+ import { CachedAppPageValue } from "../shims/cache-handler.js";
11
11
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
12
12
  import { ISRCacheEntry } from "./isr-cache.js";
13
13
  import { PprFallbackShellState } from "../shims/ppr-fallback-shell.js";
@@ -199,6 +199,7 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
199
199
  }>;
200
200
  request: Request;
201
201
  revalidateSeconds: number | null;
202
+ renderedPathAndSearch?: string | null;
202
203
  resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;
203
204
  resolveRouteDynamicConfig?: (route: TRoute) => string | null | undefined;
204
205
  rootForbiddenModule?: AppPageModule | null;
@@ -1,12 +1,13 @@
1
1
  import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
+ import "../utils/protocol-headers.js";
3
4
  import { AppElementsWire } from "./app-elements-wire.js";
4
- import { shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
5
+ import { APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL } from "./app-rsc-render-mode.js";
5
6
  import "./app-elements.js";
6
7
  import { consumeDynamicUsage, consumeInvalidDynamicUsageError, getAndClearPendingCookies, getDraftModeCookieHeader, getHeadersContext, isDraftModeRequest, markDynamicUsage, peekDynamicUsage, peekRenderRequestApiUsage, setHeadersContext } from "../shims/headers.js";
7
8
  import { _consumeRequestScopedCacheLife, _peekRequestScopedCacheLife } from "../shims/cache-request-state.js";
8
- import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
9
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
9
+ import { ensureFetchPatch, getCollectedFetchTags, peekDynamicFetchObservations, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, setRefreshStaleFetchesInForeground } from "../shims/fetch-cache.js";
10
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
10
11
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
11
12
  import "./app-page-response.js";
12
13
  import { buildAppPageSpecialErrorResponse, probeAppPageThrownError, resolveAppPageSpecialError } from "./app-page-execution.js";
@@ -100,6 +101,10 @@ function getEffectiveLayoutClassifications(route, debugClassification) {
100
101
  function shouldReadAppPageCache(options) {
101
102
  return options.isProduction && !options.isProgressiveActionRender && !options.isDraftMode && !options.isForceDynamic && (options.isRscRequest || !options.scriptNonce) && (options.revalidateSeconds === null || options.revalidateSeconds > 0);
102
103
  }
104
+ function resolveAppPageCacheReadRevalidateSeconds(options) {
105
+ if (options.revalidateSeconds === null && (options.isForceStatic || options.isDynamicError)) return Infinity;
106
+ return options.revalidateSeconds ?? 0;
107
+ }
103
108
  function hasSearchParams(searchParams) {
104
109
  return searchParams !== null && searchParams !== void 0 && searchParams.size > 0;
105
110
  }
@@ -119,6 +124,7 @@ async function runAppPageRevalidationContext(options, renderFn) {
119
124
  unstableCacheRevalidation: "foreground"
120
125
  }), async () => {
121
126
  ensureFetchPatch();
127
+ setRefreshStaleFetchesInForeground(process.env.VINEXT_PRERENDER === "1");
122
128
  setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], options.routeSegments));
123
129
  options.setNavigationContext({
124
130
  pathname: options.displayPathname ?? options.cleanPathname,
@@ -154,12 +160,14 @@ async function dispatchAppPageInner(options) {
154
160
  const isForceStatic = dynamicConfig === "force-static";
155
161
  const isDynamicError = dynamicConfig === "error";
156
162
  const isForceDynamic = dynamicConfig === "force-dynamic";
163
+ const isPrefetchDynamicShell = options.renderMode === APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL;
157
164
  const isDraftMode = isDraftModeRequest(options.request, options.draftModeSecret);
158
165
  const requestHeadersContext = getHeadersContext();
159
- const hasRequestSearchParams = !isForceStatic && hasSearchParams(options.searchParams);
160
- const pageSearchParams = isForceStatic ? new URLSearchParams() : options.searchParams;
166
+ const shouldUseEmptySearchParams = isForceStatic || isPrefetchDynamicShell;
167
+ const hasRequestSearchParams = !shouldUseEmptySearchParams && hasSearchParams(options.searchParams);
168
+ const pageSearchParams = shouldUseEmptySearchParams ? new URLSearchParams() : options.searchParams;
161
169
  const layoutParamAccess = createAppLayoutParamAccessTracker();
162
- const hasActiveLoadingBoundary = shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") ? false : Boolean(route.loading?.default);
170
+ const hasActiveLoadingBoundary = Boolean(route.loading?.default);
163
171
  setCurrentFetchSoftTags(buildAppPageTags(options.cleanPathname, [], route.routeSegments));
164
172
  setCurrentFetchCacheMode(options.fetchCache ?? null);
165
173
  setCurrentForceDynamicFetchDefault(isForceDynamic);
@@ -222,7 +230,11 @@ async function dispatchAppPageInner(options) {
222
230
  mountedSlotsHeader: options.mountedSlotsHeader,
223
231
  renderMode: options.renderMode,
224
232
  expireSeconds: options.expireSeconds,
225
- revalidateSeconds: currentRevalidateSeconds ?? 0,
233
+ revalidateSeconds: resolveAppPageCacheReadRevalidateSeconds({
234
+ isDynamicError,
235
+ isForceStatic,
236
+ revalidateSeconds: currentRevalidateSeconds
237
+ }),
226
238
  renderFreshPageForCache: async () => {
227
239
  const revalidationTarget = await resolveAppPageInterceptionRerenderTarget({
228
240
  cleanPathname: options.cleanPathname,
@@ -361,6 +373,7 @@ async function dispatchAppPageInner(options) {
361
373
  });
362
374
  mergeMiddlewareResponseHeaders(interceptHeaders, options.middlewareContext.headers);
363
375
  applyRscCompatibilityIdHeader(interceptHeaders);
376
+ applyRscDeploymentIdHeader(interceptHeaders);
364
377
  return new Response(interceptStream, {
365
378
  status: options.middlewareContext.status ?? 200,
366
379
  headers: interceptHeaders
@@ -388,7 +401,7 @@ async function dispatchAppPageInner(options) {
388
401
  });
389
402
  },
390
403
  async probePageSpecialError() {
391
- if (!shouldSuppressLoadingBoundaries(options.renderMode ?? "navigation") && route.loading?.default) return null;
404
+ if (route.loading?.default) return null;
392
405
  return resolveAppPageSpecialError(await probeAppPageThrownError({
393
406
  probePage: () => options.probePage(pageSearchParams),
394
407
  runWithSuppressedHookWarning(probe) {
@@ -428,6 +441,8 @@ async function dispatchAppPageInner(options) {
428
441
  const activeFallbackShellState = options.pprRuntime?.getState() ?? null;
429
442
  const pprFallbackShellSignal = activeFallbackShellState?.abortController.signal;
430
443
  const pprFallbackShellReactSignal = activeFallbackShellState?.reactAbortController.signal;
444
+ const isPrerender = process.env.VINEXT_PRERENDER === "1";
445
+ const isSpeculativePrerender = isPrerender && options.request.headers.get("x-vinext-prerender-speculative") === "1";
431
446
  return renderAppPageLifecycle({
432
447
  basePath: options.basePath,
433
448
  clientTraceMetadata: options.clientTraceMetadata,
@@ -459,7 +474,7 @@ async function dispatchAppPageInner(options) {
459
474
  },
460
475
  handlerStart: options.handlerStart,
461
476
  hasLoadingBoundary: hasActiveLoadingBoundary,
462
- omitPendingDynamicCacheState: !options.isRscRequest && hasRequestSearchParams,
477
+ omitPendingDynamicCacheState: hasRequestSearchParams,
463
478
  formState: options.formState ?? null,
464
479
  isProgressiveActionRender: options.isProgressiveActionRender === true,
465
480
  isDynamicError,
@@ -467,7 +482,8 @@ async function dispatchAppPageInner(options) {
467
482
  isForceDynamic,
468
483
  isForceStatic,
469
484
  isEdgeRuntime: options.isEdgeRuntime === true,
470
- isPrerender: process.env.VINEXT_PRERENDER === "1",
485
+ isPrerender,
486
+ isSpeculativePrerender,
471
487
  isProduction: options.isProduction,
472
488
  isRscRequest: options.isRscRequest,
473
489
  isrDebug: options.isrDebug,
@@ -483,6 +499,7 @@ async function dispatchAppPageInner(options) {
483
499
  params: options.params,
484
500
  pprFallbackShellSignal,
485
501
  pprFallbackShellReactSignal,
502
+ renderedPathAndSearch: options.renderedPathAndSearch,
486
503
  abortPprFallbackShell: activeFallbackShellState ? () => {
487
504
  options.pprRuntime.beginFinalRender(activeFallbackShellState);
488
505
  } : void 0,
@@ -51,6 +51,7 @@ async function buildPageElements(options) {
51
51
  const hasPageModule = !!pageModule;
52
52
  const renderIdentity = createAppPageRenderIdentity({
53
53
  displayPathname,
54
+ matchedRoutePathname: routePath,
54
55
  targetMatchedPathname: routePath,
55
56
  interceptionContext: opts?.interceptionContext ?? null,
56
57
  interceptSourceMatchedUrl: opts?.interceptSourceMatchedUrl ?? null,
@@ -1,7 +1,7 @@
1
1
  import { addBasePathToPathname } from "../utils/base-path.js";
2
2
  import { VINEXT_RSC_REDIRECT_HEADER } from "./headers.js";
3
3
  import { runWithConnectionProbe } from "../shims/headers.js";
4
- import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, createRscRedirectLocation } from "./app-rsc-cache-busting.js";
4
+ import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, createRscRedirectLocation } from "./app-rsc-cache-busting.js";
5
5
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
6
6
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
7
7
  import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
@@ -161,6 +161,7 @@ async function buildAppPageSpecialErrorResponse(options) {
161
161
  });
162
162
  applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);
163
163
  applyRscCompatibilityIdHeader(headers);
164
+ applyRscDeploymentIdHeader(headers);
164
165
  mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);
165
166
  const pendingCookies = options.getAndClearPendingCookies?.() ?? [];
166
167
  for (const cookie of pendingCookies) headers.append("Set-Cookie", cookie);
@@ -2,6 +2,7 @@ import { AppElementsInterception } from "./app-elements-wire.js";
2
2
  //#region src/server/app-page-render-identity.d.ts
3
3
  type AppPageRenderIdentityInput = {
4
4
  displayPathname: string;
5
+ matchedRoutePathname?: string;
5
6
  targetMatchedPathname?: string;
6
7
  interceptionContext?: string | null;
7
8
  interceptSourceMatchedUrl?: string | null;
@@ -14,9 +14,10 @@ function normalizeAppPageInterceptionProofPathname(pathname) {
14
14
  function createAppPageRenderIdentity(input) {
15
15
  const interceptionContext = input.interceptionContext ?? null;
16
16
  const targetMatchedPathname = normalizeAppPageRenderMatchedPathname(input.targetMatchedPathname ?? input.displayPathname);
17
+ const requestedMatchedRoutePathname = normalizeAppPageRenderMatchedPathname(input.matchedRoutePathname ?? input.targetMatchedPathname ?? input.displayPathname);
17
18
  const sourceMatchedPathname = normalizeAppPageInterceptionProofPathname(input.interceptSourceMatchedUrl ?? null);
18
19
  const slotId = input.interceptSlotId ?? null;
19
- const matchedRoutePathname = sourceMatchedPathname ?? targetMatchedPathname;
20
+ const matchedRoutePathname = sourceMatchedPathname ?? requestedMatchedRoutePathname;
20
21
  const routeId = AppElementsWire.encodeRouteId(matchedRoutePathname, null);
21
22
  const pageId = AppElementsWire.encodePageId(matchedRoutePathname, null);
22
23
  const interception = sourceMatchedPathname === null || slotId === null ? null : {
@@ -1,4 +1,3 @@
1
- import { CachedAppPageValue } from "../shims/cache-handler.js";
2
1
  import { ClientReuseManifestParseResult, ClientReuseManifestSkipDisposition } from "./client-reuse-manifest.js";
3
2
  import { AppOutgoingElements } from "./app-elements-wire.js";
4
3
  import { NavigationContext } from "../shims/navigation-context-state.js";
@@ -7,6 +6,7 @@ import { AppPageMiddlewareContext } from "./app-page-response.js";
7
6
  import { RootParams } from "../shims/root-params.js";
8
7
  import { AppPageSsrHandler } from "./app-page-stream.js";
9
8
  import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
9
+ import { CachedAppPageValue } from "../shims/cache-handler.js";
10
10
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
11
11
  import { AppPageRenderObservationState } from "./app-page-render-observation.js";
12
12
  import { ReactNode } from "react";
@@ -60,6 +60,7 @@ type RenderAppPageLifecycleOptions = {
60
60
  isForceStatic: boolean;
61
61
  isProgressiveActionRender?: boolean;
62
62
  isPrerender?: boolean;
63
+ isSpeculativePrerender?: boolean;
63
64
  isProduction: boolean;
64
65
  probePageBeforeRender?: boolean;
65
66
  omitPendingDynamicCacheState?: boolean;
@@ -103,6 +104,7 @@ type RenderAppPageLifecycleOptions = {
103
104
  clientReuseManifest?: ClientReuseManifestParseResult;
104
105
  skipDisposition?: ClientReuseManifestSkipDisposition;
105
106
  mountedSlotsHeader?: string | null;
107
+ renderedPathAndSearch?: string | null;
106
108
  renderMode?: AppRscRenderMode;
107
109
  waitUntil?: (promise: Promise<void>) => void;
108
110
  layoutParamAccess?: AppLayoutParamAccessTracker;
@@ -27,8 +27,14 @@ function buildResponseTiming(options) {
27
27
  };
28
28
  }
29
29
  function readRequestCacheLifeForPrerender(options) {
30
+ if (options.isEdgeRuntime && options.revalidateSeconds === null) return (options.peekRequestCacheLife?.() ?? options.getRequestCacheLife())?.revalidate !== void 0 ? { revalidate: 0 } : null;
30
31
  return options.peekRequestCacheLife?.() ?? options.getRequestCacheLife();
31
32
  }
33
+ function readRequestCacheLifeForCachePolicy(options) {
34
+ const requestCacheLife = options.getRequestCacheLife();
35
+ if (options.isEdgeRuntime && options.revalidateSeconds === null) return null;
36
+ return requestCacheLife;
37
+ }
32
38
  function applyRequestCacheLife(options) {
33
39
  let revalidateSeconds = options.revalidateSeconds;
34
40
  let expireSeconds = options.expireSeconds;
@@ -40,6 +46,10 @@ function applyRequestCacheLife(options) {
40
46
  revalidateSeconds
41
47
  };
42
48
  }
49
+ function resolveAppPageCacheWriteRevalidateSeconds(options) {
50
+ if (options.revalidateSeconds === null && (options.isForceStatic || options.isDynamicError)) return Infinity;
51
+ return options.revalidateSeconds;
52
+ }
43
53
  function readRootBoundaryId(element) {
44
54
  const rootLayoutTreePath = element[AppElementsWire.keys.rootLayout];
45
55
  return typeof rootLayoutTreePath === "string" ? rootLayoutTreePath : null;
@@ -338,6 +348,8 @@ async function renderAppPageLifecycle(options) {
338
348
  if (options.pprFallbackShellSignal) pprFallbackShellRsc = new Uint8Array(await readAppPageBinaryStream(rscStream));
339
349
  let revalidateSeconds = options.revalidateSeconds;
340
350
  let expireSeconds = options.expireSeconds;
351
+ const shouldWaitForAllReady = options.isPrerender === true && options.isSpeculativePrerender !== true;
352
+ const shouldReadRequestCacheLifeForPrerender = options.isPrerender === true;
341
353
  const shouldCaptureRscForCacheMetadata = options.isProgressiveActionRender !== true && (options.isProduction || options.isPrerender === true) && (revalidateSeconds === null || revalidateSeconds > 0 && revalidateSeconds !== Infinity) && !options.isDraftMode && !options.isForceDynamic && !shouldBypassRscCacheForSkipTransport;
342
354
  const createBufferedRscStream = (close) => new ReadableStream({ start(controller) {
343
355
  if (pprFallbackShellRsc) controller.enqueue(pprFallbackShellRsc);
@@ -351,11 +363,13 @@ async function renderAppPageLifecycle(options) {
351
363
  const capturedRscDataRef = { value: null };
352
364
  if (rscCapture.sideStream && options.isRscRequest) capturedRscDataRef.value = readAppPageBinaryStream(rscCapture.sideStream);
353
365
  if (options.isRscRequest) {
354
- if (options.isPrerender === true) {
355
- await settleCapturedRscRenderForCacheMetadata(capturedRscDataRef.value);
366
+ let requestCacheLifeForPrerender = null;
367
+ if (shouldWaitForAllReady) await settleCapturedRscRenderForCacheMetadata(capturedRscDataRef.value);
368
+ if (shouldReadRequestCacheLifeForPrerender) {
369
+ requestCacheLifeForPrerender = readRequestCacheLifeForPrerender(options);
356
370
  ({expireSeconds, revalidateSeconds} = applyRequestCacheLife({
357
371
  expireSeconds,
358
- requestCacheLife: readRequestCacheLifeForPrerender(options),
372
+ requestCacheLife: requestCacheLifeForPrerender,
359
373
  revalidateSeconds
360
374
  }));
361
375
  }
@@ -378,6 +392,8 @@ async function renderAppPageLifecycle(options) {
378
392
  mountedSlotsHeader: options.mountedSlotsHeader,
379
393
  params: options.navigationParams,
380
394
  policy: rscResponsePolicy,
395
+ renderedPathAndSearch: options.renderedPathAndSearch,
396
+ requestCacheLife: requestCacheLifeForPrerender,
381
397
  timing: buildResponseTiming({
382
398
  compileEnd,
383
399
  handlerStart: options.handlerStart,
@@ -407,17 +423,22 @@ async function renderAppPageLifecycle(options) {
407
423
  return options.getPageTags();
408
424
  },
409
425
  getRequestCacheLife() {
410
- return options.getRequestCacheLife();
426
+ return readRequestCacheLifeForCachePolicy(options);
411
427
  },
412
428
  isrDebug: options.isrDebug,
413
429
  isrRscKey: options.isrRscKey,
414
430
  isrSet: options.isrSet,
415
431
  interceptionContext: options.interceptionContext,
416
432
  mountedSlotsHeader: options.mountedSlotsHeader,
433
+ omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
417
434
  renderMode: options.renderMode,
418
435
  preserveClientResponseHeaders: rscResponsePolicy.cacheState !== "MISS",
419
436
  expireSeconds,
420
- revalidateSeconds,
437
+ revalidateSeconds: resolveAppPageCacheWriteRevalidateSeconds({
438
+ isDynamicError: options.isDynamicError,
439
+ isForceStatic: options.isForceStatic,
440
+ revalidateSeconds
441
+ }),
421
442
  waitUntil(promise) {
422
443
  options.waitUntil?.(promise);
423
444
  }
@@ -469,7 +490,8 @@ async function renderAppPageLifecycle(options) {
469
490
  scriptNonce: options.scriptNonce,
470
491
  sideStream: rscCapture.sideStream,
471
492
  ssrHandler,
472
- waitForAllReady: options.isPrerender === true
493
+ fallbackToErrorDocumentOnShellError: options.isPrerender === true && options.isSpeculativePrerender === true ? false : void 0,
494
+ waitForAllReady: shouldWaitForAllReady
473
495
  });
474
496
  },
475
497
  renderSpecialErrorResponse(specialError) {
@@ -492,15 +514,27 @@ async function renderAppPageLifecycle(options) {
492
514
  }
493
515
  }
494
516
  }
495
- if (options.isPrerender === true) {
496
- await settleCapturedRscRenderForCacheMetadata(htmlRender.capturedRscData);
517
+ let requestCacheLifeForPrerender = null;
518
+ let dynamicUsedDuringRender = options.consumeDynamicUsage();
519
+ dynamicUsedDuringHtmlRender = dynamicUsedDuringRender;
520
+ const stopSpeculativeMetadataWaitOnDynamicUsage = options.isSpeculativePrerender === true && shouldReadRequestCacheLifeForPrerender ? () => {
521
+ if (dynamicUsedDuringRender || (options.peekDynamicUsage?.() ?? peekDynamicUsage())) {
522
+ dynamicUsedDuringRender = true;
523
+ dynamicUsedDuringHtmlRender = true;
524
+ return true;
525
+ }
526
+ return false;
527
+ } : void 0;
528
+ if (shouldWaitForAllReady || shouldReadRequestCacheLifeForPrerender) await settleCapturedRscRenderForCacheMetadata(htmlRender.capturedRscData, stopSpeculativeMetadataWaitOnDynamicUsage);
529
+ if (shouldReadRequestCacheLifeForPrerender) {
530
+ requestCacheLifeForPrerender = readRequestCacheLifeForPrerender(options);
497
531
  ({expireSeconds, revalidateSeconds} = applyRequestCacheLife({
498
532
  expireSeconds,
499
- requestCacheLife: readRequestCacheLifeForPrerender(options),
533
+ requestCacheLife: requestCacheLifeForPrerender,
500
534
  revalidateSeconds
501
535
  }));
502
536
  }
503
- let dynamicUsedDuringRender = options.consumeDynamicUsage();
537
+ dynamicUsedDuringRender = dynamicUsedDuringRender || options.consumeDynamicUsage();
504
538
  dynamicUsedDuringHtmlRender = dynamicUsedDuringRender;
505
539
  const draftCookie = options.getDraftModeCookieHeader();
506
540
  let dynamicUsedBeforeContextCleanup = dynamicUsedDuringRender;
@@ -538,12 +572,13 @@ async function renderAppPageLifecycle(options) {
538
572
  status: 500
539
573
  },
540
574
  policy: { cacheControl: NEVER_CACHE_CONTROL },
575
+ requestCacheLife: requestCacheLifeForPrerender,
541
576
  timing: htmlResponseTiming
542
577
  });
543
578
  applyCdnResponseHeaders(response.headers, { cacheControl: NEVER_CACHE_CONTROL });
544
579
  return response;
545
580
  }
546
- const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
581
+ const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && !options.isEdgeRuntime && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
547
582
  if (htmlResponsePolicy.shouldWriteToCache || shouldSpeculativelyWriteCache) {
548
583
  const isrResponse = buildAppPageHtmlResponse(safeHtmlStream, {
549
584
  draftCookie,
@@ -551,6 +586,7 @@ async function renderAppPageLifecycle(options) {
551
586
  isEdgeRuntime: options.isEdgeRuntime,
552
587
  middlewareContext: options.middlewareContext,
553
588
  policy: htmlResponsePolicy,
589
+ requestCacheLife: requestCacheLifeForPrerender,
554
590
  timing: htmlResponseTiming
555
591
  });
556
592
  if (options.isPrerender === true) return isrResponse;
@@ -590,7 +626,7 @@ async function renderAppPageLifecycle(options) {
590
626
  return options.getPageTags();
591
627
  },
592
628
  getRequestCacheLife() {
593
- return options.getRequestCacheLife();
629
+ return readRequestCacheLifeForCachePolicy(options);
594
630
  },
595
631
  isrDebug: options.isrDebug,
596
632
  isrHtmlKey: options.isrHtmlKey,
@@ -600,7 +636,11 @@ async function renderAppPageLifecycle(options) {
600
636
  omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
601
637
  preserveClientResponseHeaders: !htmlResponsePolicy.shouldWriteToCache,
602
638
  expireSeconds,
603
- revalidateSeconds,
639
+ revalidateSeconds: resolveAppPageCacheWriteRevalidateSeconds({
640
+ isDynamicError: options.isDynamicError,
641
+ isForceStatic: options.isForceStatic,
642
+ revalidateSeconds
643
+ }),
604
644
  waitUntil(cachePromise) {
605
645
  options.waitUntil?.(cachePromise);
606
646
  }
@@ -612,14 +652,25 @@ async function renderAppPageLifecycle(options) {
612
652
  isEdgeRuntime: options.isEdgeRuntime,
613
653
  middlewareContext: options.middlewareContext,
614
654
  policy: htmlResponsePolicy,
655
+ requestCacheLife: requestCacheLifeForPrerender,
615
656
  timing: htmlResponseTiming
616
657
  });
617
658
  }
618
- async function settleCapturedRscRenderForCacheMetadata(capturedRscDataPromise) {
659
+ async function settleCapturedRscRenderForCacheMetadata(capturedRscDataPromise, shouldStopWaiting) {
619
660
  if (!capturedRscDataPromise) return;
661
+ if (!shouldStopWaiting) {
662
+ try {
663
+ await capturedRscDataPromise;
664
+ } catch {}
665
+ return;
666
+ }
667
+ let settled = false;
668
+ const settledPromise = capturedRscDataPromise.catch(() => {}).then(() => {
669
+ settled = true;
670
+ });
620
671
  try {
621
- await capturedRscDataPromise;
622
- } catch {}
672
+ while (!settled && !shouldStopWaiting()) await Promise.race([settledPromise, new Promise((resolve) => setTimeout(resolve, 0))]);
673
+ } finally {}
623
674
  }
624
675
  //#endregion
625
676
  export { renderAppPageLifecycle };
@@ -15,6 +15,10 @@ type AppPageResponsePolicy = {
15
15
  cacheControl?: string;
16
16
  cacheState?: "MISS" | "STATIC";
17
17
  };
18
+ type AppPagePrerenderCacheLife = {
19
+ expire?: number;
20
+ revalidate?: number;
21
+ };
18
22
  type ResolveAppPageResponsePolicyBaseOptions = {
19
23
  isDraftMode: boolean;
20
24
  isDynamicError: boolean;
@@ -42,6 +46,8 @@ type BuildAppPageRscResponseOptions = {
42
46
  mountedSlotsHeader?: string | null;
43
47
  params?: Record<string, unknown>;
44
48
  policy: AppPageResponsePolicy;
49
+ renderedPathAndSearch?: string | null;
50
+ requestCacheLife?: AppPagePrerenderCacheLife | null;
45
51
  timing?: AppPageResponseTiming;
46
52
  };
47
53
  type BuildAppPageHtmlResponseOptions = {
@@ -50,6 +56,7 @@ type BuildAppPageHtmlResponseOptions = {
50
56
  isEdgeRuntime?: boolean;
51
57
  middlewareContext: AppPageMiddlewareContext;
52
58
  policy: AppPageResponsePolicy;
59
+ requestCacheLife?: AppPagePrerenderCacheLife | null;
53
60
  timing?: AppPageResponseTiming;
54
61
  };
55
62
  declare function resolveAppPageRscResponsePolicy(options: ResolveAppPageRscResponsePolicyOptions): AppPageResponsePolicy;
@@ -1,7 +1,7 @@
1
- import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
1
+ import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
2
2
  import { setCacheStateHeaders } from "./cache-headers.js";
3
3
  import { NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildRevalidateCacheControl } from "./cache-control.js";
4
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
4
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
5
5
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
6
6
  //#region src/server/app-page-response.ts
7
7
  function applyTimingHeader(headers, timing) {
@@ -14,6 +14,14 @@ function applyTimingHeader(headers, timing) {
14
14
  function applyDynamicStaleTimeHeader(headers, dynamicStaleTimeSeconds) {
15
15
  if (dynamicStaleTimeSeconds !== void 0 && Number.isInteger(dynamicStaleTimeSeconds) && dynamicStaleTimeSeconds >= 0) headers.set(VINEXT_DYNAMIC_STALE_TIME_HEADER, String(dynamicStaleTimeSeconds));
16
16
  }
17
+ function applyPrerenderCacheLifeHeader(headers, requestCacheLife) {
18
+ if (!requestCacheLife) return;
19
+ const payload = {};
20
+ if (typeof requestCacheLife.revalidate === "number" && Number.isFinite(requestCacheLife.revalidate)) payload.revalidate = requestCacheLife.revalidate;
21
+ if (typeof requestCacheLife.expire === "number" && Number.isFinite(requestCacheLife.expire)) payload.expire = requestCacheLife.expire;
22
+ if (payload.revalidate === void 0 && payload.expire === void 0) return;
23
+ headers.set(VINEXT_PRERENDER_CACHE_LIFE_HEADER, JSON.stringify(payload));
24
+ }
17
25
  function resolveAppPageRscResponsePolicy(options) {
18
26
  if (options.isDraftMode) return { cacheControl: NO_STORE_CACHE_CONTROL };
19
27
  if (options.isForceDynamic || options.dynamicUsedDuringBuild) return { cacheControl: NO_STORE_CACHE_CONTROL };
@@ -51,8 +59,8 @@ function resolveAppPageHtmlResponsePolicy(options) {
51
59
  };
52
60
  if ((options.isForceStatic || options.isDynamicError) && options.revalidateSeconds === null) return {
53
61
  cacheControl: STATIC_CACHE_CONTROL,
54
- cacheState: "STATIC",
55
- shouldWriteToCache: false
62
+ cacheState: options.isProduction ? "MISS" : "STATIC",
63
+ shouldWriteToCache: options.isProduction
56
64
  };
57
65
  if (options.dynamicUsedDuringRender) return {
58
66
  cacheControl: NO_STORE_CACHE_CONTROL,
@@ -92,7 +100,10 @@ function buildAppPageRscResponse(body, options) {
92
100
  if (options.policy.cacheControl) headers.set("Cache-Control", options.policy.cacheControl);
93
101
  if (options.policy.cacheState) setCacheStateHeaders(headers, options.policy.cacheState);
94
102
  mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);
103
+ if (options.renderedPathAndSearch) headers.set(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, encodeURIComponent(options.renderedPathAndSearch));
95
104
  applyRscCompatibilityIdHeader(headers);
105
+ applyRscDeploymentIdHeader(headers);
106
+ applyPrerenderCacheLifeHeader(headers, options.requestCacheLife);
96
107
  applyTimingHeader(headers, options.timing);
97
108
  return new Response(body, {
98
109
  status: options.middlewareContext.status ?? 200,
@@ -110,6 +121,7 @@ function buildAppPageHtmlResponse(body, options) {
110
121
  if (options.draftCookie) headers.append("Set-Cookie", options.draftCookie);
111
122
  if (options.linkHeader) headers.set("Link", options.linkHeader);
112
123
  mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);
124
+ applyPrerenderCacheLifeHeader(headers, options.requestCacheLife);
113
125
  applyTimingHeader(headers, options.timing);
114
126
  return new Response(body, {
115
127
  status: options.middlewareContext.status ?? 200,