vinext 1.0.0-beta.2 → 1.0.0-beta.4

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 (174) hide show
  1. package/README.md +6 -9
  2. package/dist/build/client-build-config.js +7 -1
  3. package/dist/build/precompress.js +1 -1
  4. package/dist/build/prerender.d.ts +2 -1
  5. package/dist/build/prerender.js +12 -2
  6. package/dist/check.js +4 -0
  7. package/dist/cli-args.d.ts +2 -1
  8. package/dist/cli-args.js +10 -0
  9. package/dist/cli.js +14 -8
  10. package/dist/client/navigation-runtime.d.ts +6 -0
  11. package/dist/client/navigation-runtime.js +1 -1
  12. package/dist/config/config-matchers.js +4 -1
  13. package/dist/config/dotenv.d.ts +3 -4
  14. package/dist/config/dotenv.js +30 -22
  15. package/dist/config/next-config.d.ts +16 -5
  16. package/dist/config/next-config.js +7 -0
  17. package/dist/entries/app-browser-entry.d.ts +4 -10
  18. package/dist/entries/app-browser-entry.js +20 -4
  19. package/dist/entries/app-rsc-entry.js +21 -3
  20. package/dist/entries/app-rsc-manifest.js +19 -0
  21. package/dist/entries/pages-client-entry.js +0 -1
  22. package/dist/entries/pages-server-entry.js +13 -3
  23. package/dist/index.js +122 -49
  24. package/dist/init-cloudflare.d.ts +3 -1
  25. package/dist/init-cloudflare.js +59 -5
  26. package/dist/plugins/client-reference-dedup.js +7 -5
  27. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  28. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  29. package/dist/plugins/import-meta-url.js +17 -6
  30. package/dist/plugins/require-context.js +20 -15
  31. package/dist/plugins/sass.js +3 -4
  32. package/dist/plugins/transform-cache.d.ts +19 -0
  33. package/dist/plugins/transform-cache.js +36 -0
  34. package/dist/routing/app-route-graph.d.ts +14 -6
  35. package/dist/routing/app-route-graph.js +106 -16
  36. package/dist/server/api-handler.d.ts +2 -0
  37. package/dist/server/api-handler.js +7 -6
  38. package/dist/server/app-bfcache-identity.js +28 -2
  39. package/dist/server/app-browser-entry.js +175 -75
  40. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  41. package/dist/server/app-browser-navigation-controller.js +30 -5
  42. package/dist/server/app-browser-prefetch-response.d.ts +9 -0
  43. package/dist/server/app-browser-prefetch-response.js +32 -0
  44. package/dist/server/app-browser-state.d.ts +8 -3
  45. package/dist/server/app-browser-state.js +9 -3
  46. package/dist/server/app-page-cache-finalizer.js +1 -1
  47. package/dist/server/app-page-cache.d.ts +1 -1
  48. package/dist/server/app-page-cache.js +16 -2
  49. package/dist/server/app-page-dispatch.d.ts +9 -1
  50. package/dist/server/app-page-dispatch.js +37 -8
  51. package/dist/server/app-page-element-builder.d.ts +4 -1
  52. package/dist/server/app-page-element-builder.js +34 -7
  53. package/dist/server/app-page-head.d.ts +3 -3
  54. package/dist/server/app-page-head.js +58 -13
  55. package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
  56. package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
  57. package/dist/server/app-page-probe.d.ts +4 -0
  58. package/dist/server/app-page-probe.js +6 -2
  59. package/dist/server/app-page-render.d.ts +1 -1
  60. package/dist/server/app-page-render.js +13 -3
  61. package/dist/server/app-page-request.d.ts +3 -1
  62. package/dist/server/app-page-request.js +4 -13
  63. package/dist/server/app-page-response.d.ts +2 -0
  64. package/dist/server/app-page-response.js +7 -2
  65. package/dist/server/app-page-route-wiring.d.ts +10 -2
  66. package/dist/server/app-page-route-wiring.js +269 -59
  67. package/dist/server/app-pages-bridge.d.ts +2 -1
  68. package/dist/server/app-pages-bridge.js +3 -1
  69. package/dist/server/app-route-handler-cache.js +4 -0
  70. package/dist/server/app-route-handler-dispatch.js +9 -3
  71. package/dist/server/app-route-handler-response.js +1 -1
  72. package/dist/server/app-route-module-loader.d.ts +6 -0
  73. package/dist/server/app-route-module-loader.js +3 -0
  74. package/dist/server/app-router-entry.js +6 -3
  75. package/dist/server/app-rsc-cache-busting.d.ts +7 -0
  76. package/dist/server/app-rsc-cache-busting.js +6 -0
  77. package/dist/server/app-rsc-errors.js +10 -0
  78. package/dist/server/app-rsc-handler.d.ts +2 -0
  79. package/dist/server/app-rsc-handler.js +30 -13
  80. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  81. package/dist/server/app-rsc-render-mode.js +4 -1
  82. package/dist/server/app-rsc-request-normalization.js +65 -4
  83. package/dist/server/app-rsc-route-matching.d.ts +9 -0
  84. package/dist/server/app-rsc-route-matching.js +6 -0
  85. package/dist/server/app-server-action-execution.d.ts +1 -1
  86. package/dist/server/app-ssr-entry.js +4 -4
  87. package/dist/server/app-visited-response-cache.d.ts +6 -1
  88. package/dist/server/app-visited-response-cache.js +49 -1
  89. package/dist/server/cache-control.d.ts +2 -2
  90. package/dist/server/cache-control.js +2 -1
  91. package/dist/server/dev-server.d.ts +3 -1
  92. package/dist/server/dev-server.js +204 -348
  93. package/dist/server/edge-api-runtime.d.ts +10 -1
  94. package/dist/server/edge-api-runtime.js +29 -1
  95. package/dist/server/headers.d.ts +4 -2
  96. package/dist/server/headers.js +6 -3
  97. package/dist/server/isr-cache.d.ts +10 -33
  98. package/dist/server/isr-cache.js +33 -43
  99. package/dist/server/isr-decision.d.ts +2 -2
  100. package/dist/server/pages-api-route.d.ts +4 -0
  101. package/dist/server/pages-api-route.js +6 -3
  102. package/dist/server/pages-asset-tags.d.ts +1 -0
  103. package/dist/server/pages-asset-tags.js +6 -4
  104. package/dist/server/pages-dev-hydration.js +0 -1
  105. package/dist/server/pages-document-asset-props.d.ts +26 -0
  106. package/dist/server/pages-document-asset-props.js +69 -0
  107. package/dist/server/pages-get-initial-props.d.ts +1 -1
  108. package/dist/server/pages-get-initial-props.js +1 -4
  109. package/dist/server/pages-i18n.js +64 -16
  110. package/dist/server/pages-node-compat.d.ts +2 -0
  111. package/dist/server/pages-node-compat.js +10 -6
  112. package/dist/server/pages-page-data.d.ts +61 -9
  113. package/dist/server/pages-page-data.js +334 -74
  114. package/dist/server/pages-page-handler.d.ts +6 -1
  115. package/dist/server/pages-page-handler.js +119 -20
  116. package/dist/server/pages-page-response.d.ts +7 -3
  117. package/dist/server/pages-page-response.js +41 -33
  118. package/dist/server/pages-request-pipeline.d.ts +7 -0
  119. package/dist/server/pages-request-pipeline.js +5 -1
  120. package/dist/server/pages-revalidate.d.ts +1 -1
  121. package/dist/server/pages-revalidate.js +54 -8
  122. package/dist/server/pages-router-entry.d.ts +1 -0
  123. package/dist/server/pages-router-entry.js +10 -4
  124. package/dist/server/prerender-manifest.d.ts +1 -0
  125. package/dist/server/prod-server.d.ts +2 -1
  126. package/dist/server/prod-server.js +38 -13
  127. package/dist/server/revalidation-host.d.ts +11 -0
  128. package/dist/server/revalidation-host.js +19 -0
  129. package/dist/server/seed-cache.js +1 -1
  130. package/dist/server/worker-revalidation-context.d.ts +13 -0
  131. package/dist/server/worker-revalidation-context.js +30 -0
  132. package/dist/shims/app-router-scroll-state.d.ts +2 -1
  133. package/dist/shims/app-router-scroll-state.js +7 -2
  134. package/dist/shims/cache-handler.d.ts +1 -1
  135. package/dist/shims/cache-handler.js +10 -7
  136. package/dist/shims/cache-runtime.d.ts +6 -0
  137. package/dist/shims/cache-runtime.js +4 -1
  138. package/dist/shims/cache.js +1 -1
  139. package/dist/shims/document.js +15 -2
  140. package/dist/shims/error.js +1 -1
  141. package/dist/shims/fetch-cache.js +1 -1
  142. package/dist/shims/font-google-base.js +17 -8
  143. package/dist/shims/font-local.js +41 -10
  144. package/dist/shims/hash-scroll.d.ts +1 -1
  145. package/dist/shims/hash-scroll.js +2 -1
  146. package/dist/shims/headers.d.ts +10 -13
  147. package/dist/shims/headers.js +85 -36
  148. package/dist/shims/internal/cookie-serialize.d.ts +10 -9
  149. package/dist/shims/internal/cookie-serialize.js +9 -8
  150. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  151. package/dist/shims/internal/interpolate-as.js +27 -2
  152. package/dist/shims/link.d.ts +2 -0
  153. package/dist/shims/link.js +77 -24
  154. package/dist/shims/metadata.d.ts +18 -34
  155. package/dist/shims/metadata.js +98 -56
  156. package/dist/shims/navigation.d.ts +18 -2
  157. package/dist/shims/navigation.js +70 -21
  158. package/dist/shims/request-context.d.ts +6 -2
  159. package/dist/shims/router.js +18 -7
  160. package/dist/shims/script.js +1 -1
  161. package/dist/shims/server.d.ts +7 -6
  162. package/dist/shims/server.js +156 -57
  163. package/dist/shims/slot.d.ts +2 -1
  164. package/dist/shims/slot.js +6 -2
  165. package/dist/shims/streamed-icons.d.ts +9 -0
  166. package/dist/shims/streamed-icons.js +33 -0
  167. package/dist/shims/unified-request-context.d.ts +21 -2
  168. package/dist/shims/unified-request-context.js +82 -1
  169. package/dist/utils/cache-control-metadata.d.ts +2 -1
  170. package/dist/utils/cache-control-metadata.js +5 -1
  171. package/dist/utils/html-limited-bots.js +1 -1
  172. package/dist/utils/protocol-headers.d.ts +7 -1
  173. package/dist/utils/protocol-headers.js +7 -1
  174. package/package.json +1 -1
@@ -20,6 +20,7 @@ function loadAppInterceptLayouts(intercept) {
20
20
  if (loadState?.interceptLayoutsLoading) return loadState.interceptLayoutsLoading;
21
21
  const loads = [];
22
22
  pushArrayLoads(loads, intercept.interceptLayouts, intercept.__loadInterceptLayouts);
23
+ pushArrayLoads(loads, intercept.interceptLoadings, intercept.__loadInterceptLoadings);
23
24
  if (loads.length === 0) return Promise.resolve(intercept.interceptLayouts ?? []);
24
25
  const loading = Promise.all(loads).then(() => {
25
26
  if (loadState) loadState.interceptLayoutsLoading = null;
@@ -52,6 +53,7 @@ function ensureAppRouteModulesLoaded(route) {
52
53
  pushFieldLoad(loads, route, "unauthorized", route.__loadUnauthorized);
53
54
  pushArrayLoads(loads, route.layouts, route.__loadLayouts);
54
55
  pushArrayLoads(loads, route.templates, route.__loadTemplates);
56
+ pushArrayLoads(loads, route.loadings, route.__loadLoadings);
55
57
  pushArrayLoads(loads, route.errors, route.__loadErrors);
56
58
  pushArrayLoads(loads, route.errorPaths, route.__loadErrorPaths);
57
59
  pushArrayLoads(loads, route.notFounds, route.__loadNotFounds);
@@ -63,6 +65,7 @@ function ensureAppRouteModulesLoaded(route) {
63
65
  pushFieldLoad(loads, slot, "layout", slot.__loadLayout);
64
66
  pushArrayLoads(loads, slot.configLayouts, slot.__loadConfigLayouts);
65
67
  pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
68
+ pushArrayLoads(loads, slot.loadings, slot.__loadLoadings);
66
69
  pushFieldLoad(loads, slot, "error", slot.__loadError);
67
70
  pushFieldLoad(loads, slot, "notFound", slot.__loadNotFound);
68
71
  }
@@ -1,6 +1,6 @@
1
1
  import "./server-globals.js";
2
2
  import { runWithExecutionContext } from "../shims/request-context.js";
3
- import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "../utils/protocol-headers.js";
3
+ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
4
4
  import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
5
5
  import { isOpenRedirectShaped } from "./open-redirect.js";
6
6
  import { cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
@@ -8,6 +8,7 @@ import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js"
8
8
  import { getImageOptimizer, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
9
9
  import { finalizeMissingStaticAssetResponse, resolveStaticAssetSignal } from "./worker-utils.js";
10
10
  import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
11
+ import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
11
12
  import rscHandler, { __assetPrefix, __basePath, __imageAllowedWidths, __imageConfig } from "virtual:vinext-rsc-entry";
12
13
  import { registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
13
14
  import { registerConfiguredImageOptimizer } from "virtual:vinext-image-adapters";
@@ -17,7 +18,8 @@ const __workerAssetPathPrefix = assetPrefixPathname(typeof __assetPrefix === "st
17
18
  var app_router_entry_default = { async fetch(request, env, ctx) {
18
19
  return handleRequest(request, env, ctx);
19
20
  } };
20
- async function handleRequest(request, env, ctx) {
21
+ async function handleRequest(request, env, platformCtx) {
22
+ const ctx = platformCtx?.trustedRevalidateOrigin ? platformCtx : createWorkerRevalidationContext(platformCtx, (internalRequest, internalCtx) => handleRequest(internalRequest, env, internalCtx));
21
23
  registerConfiguredCacheAdapters(env);
22
24
  registerConfiguredImageOptimizer(env);
23
25
  const url = new URL(request.url);
@@ -34,7 +36,8 @@ async function handleRequest(request, env, ctx) {
34
36
  const missingBuildAsset = isNextStaticPath(url.pathname, __workerBasePath, __workerAssetPathPrefix);
35
37
  {
36
38
  const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);
37
- const filteredHeaders = filterInternalHeaders(request.headers);
39
+ const filteredHeaders = ctx.isInternalPagesRevalidation ? new Headers(request.headers) : filterInternalHeaders(request.headers);
40
+ filteredHeaders.delete(VINEXT_REVALIDATE_HOST_HEADER);
38
41
  const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
39
42
  if (prerenderRouteParamsHeader !== null) filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
40
43
  request = cloneRequestWithHeaders(request, filteredHeaders);
@@ -16,7 +16,14 @@ type CreateRscRequestHeadersOptions = {
16
16
  clientReuseManifestHeader?: string | null;
17
17
  interceptionContext?: string | null;
18
18
  mountedSlotsHeader?: string | null;
19
+ includePrefetchHeader?: boolean;
19
20
  renderMode?: AppRscRenderMode;
21
+ fetchPriority?: "auto" | "high" | "low";
22
+ nextUrl?: string | null;
23
+ prefetchRouterState?: {
24
+ pathAndSearch: string;
25
+ routeId: string;
26
+ } | null;
20
27
  };
21
28
  type ResolveInvalidRscCacheBustingRequestOptions = {
22
29
  isRscRequest: boolean;
@@ -154,6 +154,12 @@ function createRscRequestHeaders(options = {}) {
154
154
  ["RSC"]: "1"
155
155
  });
156
156
  applyDeploymentIdHeader(headers);
157
+ if (options.prefetchRouterState) {
158
+ if (options.includePrefetchHeader !== false) headers.set(NEXT_ROUTER_PREFETCH_HEADER, "1");
159
+ headers.set(NEXT_ROUTER_STATE_TREE_HEADER, encodeURIComponent(JSON.stringify(options.prefetchRouterState)));
160
+ }
161
+ if (options.nextUrl) headers.set(NEXT_URL_HEADER, options.nextUrl);
162
+ if (process.env.__NEXT_TEST_MODE && options.fetchPriority) headers.set("Next-Test-Fetch-Priority", options.fetchPriority);
157
163
  if (options.interceptionContext !== void 0 && options.interceptionContext !== null) headers.set(VINEXT_INTERCEPTION_CONTEXT_HEADER, options.interceptionContext);
158
164
  if (options.mountedSlotsHeader !== void 0 && options.mountedSlotsHeader !== null) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);
159
165
  if (options.clientReuseManifestHeader !== void 0 && options.clientReuseManifestHeader !== null) headers.set(VINEXT_CLIENT_REUSE_MANIFEST_HEADER, options.clientReuseManifestHeader);
@@ -7,6 +7,11 @@ function hasDigest(error) {
7
7
  }
8
8
  const BAILOUT_TO_CSR_DIGEST = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
9
9
  const DYNAMIC_SERVER_USAGE_DIGEST = "DYNAMIC_SERVER_USAGE";
10
+ function isAbortError(error) {
11
+ if (!error || typeof error !== "object") return false;
12
+ const name = Reflect.get(error, "name");
13
+ return name === "AbortError" || name === "ResponseAborted";
14
+ }
10
15
  /**
11
16
  * vinext's mirror of Next.js's `getDigestForWellKnownError`: returns the digest
12
17
  * string only when the error is a genuine control-flow signal — a redirect,
@@ -52,6 +57,7 @@ function sanitizeErrorForClient(error, nodeEnv = process.env.NODE_ENV) {
52
57
  function createRscOnErrorHandler(options) {
53
58
  return (error) => {
54
59
  const nodeEnv = options.nodeEnv ?? process.env.NODE_ENV;
60
+ if (isAbortError(error)) return;
55
61
  const wellKnownDigest = getDigestForWellKnownError(error);
56
62
  if (wellKnownDigest !== void 0) return wellKnownDigest;
57
63
  if (nodeEnv !== "production" && error instanceof Error && error.message.includes("Only plain objects, and a few built-ins, can be passed to Client Components")) {
@@ -62,6 +68,10 @@ function createRscOnErrorHandler(options) {
62
68
  const reportableError = typeof error === "object" && ORIGINAL_SERVER_ERROR in error ? Reflect.get(error, ORIGINAL_SERVER_ERROR) : error;
63
69
  options.reportRequestError(reportableError instanceof Error ? reportableError : new Error(getThrownValueMessage(reportableError)), options.requestInfo, options.errorContext);
64
70
  }
71
+ if (nodeEnv !== "production" && error && !hasDigest(error)) {
72
+ const loggableError = typeof error === "object" && ORIGINAL_SERVER_ERROR in error ? Reflect.get(error, ORIGINAL_SERVER_ERROR) : error;
73
+ console.error("[vinext] Server render error:", loggableError);
74
+ }
65
75
  if (hasDigest(error)) return String(error.digest);
66
76
  if (error) {
67
77
  const digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
@@ -125,6 +125,7 @@ type HandleServerActionRequestOptions<TRoute> = {
125
125
  middlewareContext: AppRscMiddlewareContext;
126
126
  mountedSlotsHeader: string | null;
127
127
  request: Request;
128
+ scriptNonce?: string;
128
129
  routeMatch: AppRscRouteMatch<TRoute> | null;
129
130
  routePathname: string;
130
131
  searchParams: URLSearchParams;
@@ -195,6 +196,7 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
195
196
  imageConfig?: ImageConfig;
196
197
  isDev: boolean;
197
198
  loadPrerenderPagesRoutes?: () => Promise<unknown>;
199
+ matchInterceptRoute?: (pathname: string, sourcePathname: string) => AppRscRouteMatch<TRoute> | null;
198
200
  matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
199
201
  matchRequestRoute?: (pathname: string) => AppRscRouteMatch<TRoute> | null;
200
202
  runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
@@ -1,12 +1,13 @@
1
- import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
1
+ import { closeAfterResponse, closeAfterResponseWithBody, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
2
  import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
3
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
- import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
4
+ import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
5
5
  import { ACTION_REVALIDATED_HEADER } from "./headers.js";
6
6
  import { requestContextFromRequest } from "../config/request-context.js";
7
7
  import { isExternalUrl } from "../utils/external-url.js";
8
8
  import { notFoundResponse } from "./http-error-responses.js";
9
9
  import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
10
+ import { isOnDemandRevalidateRequest } from "./isr-cache.js";
10
11
  import { headersContextFromRequest } from "../shims/headers.js";
11
12
  import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
12
13
  import { mergeRewriteQuery } from "../utils/query.js";
@@ -190,8 +191,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
190
191
  };
191
192
  let didMiddlewareRewrite = false;
192
193
  let didMiddlewareRewritePathname = false;
193
- if (options.runMiddleware) {
194
- const middlewareResult = await options.runMiddleware({
194
+ const runMiddleware = isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) ? void 0 : options.runMiddleware;
195
+ if (runMiddleware) {
196
+ const middlewareResult = await runMiddleware({
195
197
  cleanPathname,
196
198
  context: middlewareContext,
197
199
  hadBasePath,
@@ -326,7 +328,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
326
328
  searchParams: getResolvedSearchParams(),
327
329
  params: {}
328
330
  });
329
- const preActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
331
+ const directPreActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
332
+ const preActionRoutePathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
333
+ const interceptionPreActionMatch = filesystemRouteEligible && directPreActionMatch === null && isRscRequest && interceptionContextHeader !== null ? options.matchInterceptRoute?.(preActionRoutePathname, interceptionContextHeader) ?? null : null;
334
+ const preActionMatch = directPreActionMatch ?? interceptionPreActionMatch;
335
+ const isInterceptionMatch = interceptionPreActionMatch !== null;
330
336
  if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
331
337
  if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch) {
332
338
  const headers = new Headers();
@@ -372,8 +378,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
372
378
  middlewareContext,
373
379
  mountedSlotsHeader,
374
380
  request,
381
+ scriptNonce,
375
382
  routeMatch: preActionMatch,
376
- routePathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
383
+ routePathname: preActionRoutePathname,
377
384
  searchParams: getResolvedSearchParams()
378
385
  }) : null;
379
386
  if (serverActionResponse) return serverActionResponse;
@@ -381,7 +388,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
381
388
  let match = preActionMatch;
382
389
  const renderPagesForMatchKind = async (matchKind) => {
383
390
  if (!filesystemRouteEligible) return null;
384
- const response = match === null || match.route.isDynamic ? await options.renderPagesFallback?.({
391
+ const response = !isInterceptionMatch && (match === null || match.route.isDynamic) ? await options.renderPagesFallback?.({
385
392
  appRouteMatch: match ?? null,
386
393
  allowRscDocumentFallback: didMiddlewareRewritePathname,
387
394
  isDataRequest,
@@ -407,7 +414,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
407
414
  options.clearRequestContext();
408
415
  return staticPagesFallbackResponse;
409
416
  }
410
- if (!resolvedLateRewritesForAction && (!match || match.route.isDynamic)) for (const rewrite of options.configRewrites.afterFiles) {
417
+ if (!isInterceptionMatch && !resolvedLateRewritesForAction && (!match || match.route.isDynamic)) for (const rewrite of options.configRewrites.afterFiles) {
411
418
  const afterFilesRewrite = await applyRewrite({
412
419
  basePathState,
413
420
  clearRequestContext: options.clearRequestContext,
@@ -480,7 +487,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
480
487
  }
481
488
  if (pagesDataRequest) {
482
489
  options.clearRequestContext();
483
- if (options.runMiddleware && (middlewareContext.status === null || middlewareContext.status === 200 || middlewareContext.status === 404)) {
490
+ if (runMiddleware && (middlewareContext.status === null || middlewareContext.status === 200 || middlewareContext.status === 404)) {
484
491
  const response = buildNextDataNotFoundResponse();
485
492
  const headers = new Headers(response.headers);
486
493
  headers.set("x-nextjs-matched-path", matchPathname(canonicalPathname));
@@ -632,9 +639,11 @@ function createAppRscHandler(options) {
632
639
  const pagesDataNormalization = options.renderPagesFallback && pagesDataCandidate ? normalizePagesDataRequest(pagesDataCandidate, options.buildId, "", typeof options.runMiddleware === "function" && options.trailingSlash) : null;
633
640
  if (pagesDataNormalization?.notFoundResponse) return pagesDataNormalization.notFoundResponse;
634
641
  const isPagesDataRequest = pagesDataNormalization?.isDataReq === true;
642
+ const executionContext = isExecutionContextLike(ctx) ? ctx : getRequestExecutionContext() ?? null;
635
643
  const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);
636
644
  const isTrustedSpeculativePrerender = process.env.VINEXT_PRERENDER === "1" && rawRequest.headers.get("x-vinext-prerender-secret") !== null && rawRequest.headers.get("x-vinext-prerender-speculative") === "1";
637
- const filteredHeaders = filterInternalHeaders(rawRequest.headers);
645
+ const filteredHeaders = executionContext?.isInternalPagesRevalidation ? new Headers(rawRequest.headers) : filterInternalHeaders(rawRequest.headers);
646
+ filteredHeaders.delete(VINEXT_REVALIDATE_HOST_HEADER);
638
647
  if (mwCtx !== null) filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);
639
648
  const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
640
649
  if (prerenderRouteParamsHeader !== null) filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
@@ -647,12 +656,12 @@ function createAppRscHandler(options) {
647
656
  }
648
657
  const request = cloneRequestWithHeaders(appRequest, filteredHeaders);
649
658
  const pagesDataRequest = pagesDataNormalization?.isDataReq ? cloneRequestWithHeaders(pagesDataCandidate, filteredHeaders) : null;
650
- const executionContext = isExecutionContextLike(ctx) ? ctx : getRequestExecutionContext() ?? null;
651
- return runWithRequestContext(createRequestContext({
659
+ const requestContext = createRequestContext({
652
660
  headersContext: headersContextFromRequest(request, { draftModeSecret: options.draftModeSecret }),
653
661
  executionContext,
654
662
  unstableCacheRevalidation: "background"
655
- }), () => runWithPrerenderWorkUnit(async () => {
663
+ });
664
+ const responsePromise = runWithRequestContext(requestContext, () => runWithPrerenderWorkUnit(async () => {
656
665
  ensureFetchPatch();
657
666
  const preMiddlewareRequestContext = requestContextFromRequest(request);
658
667
  let response;
@@ -669,6 +678,14 @@ function createAppRscHandler(options) {
669
678
  requestContext: preMiddlewareRequestContext
670
679
  });
671
680
  }, { route: () => new URL(request.url).pathname }));
681
+ let response;
682
+ try {
683
+ response = await responsePromise;
684
+ } catch (error) {
685
+ await closeAfterResponse(requestContext);
686
+ throw error;
687
+ }
688
+ return closeAfterResponseWithBody(response, requestContext);
672
689
  };
673
690
  }
674
691
  //#endregion
@@ -1,9 +1,10 @@
1
1
  //#region src/server/app-rsc-render-mode.d.ts
2
- type AppRscRenderMode = "navigation" | "prefetch-dynamic-shell" | "prefetch-loading-shell";
2
+ type AppRscRenderMode = "navigation" | "prefetch-empty" | "prefetch-dynamic-shell" | "prefetch-loading-shell";
3
3
  declare const APP_RSC_RENDER_MODE_NAVIGATION = "navigation";
4
+ declare const APP_RSC_RENDER_MODE_PREFETCH_EMPTY = "prefetch-empty";
4
5
  declare const APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL = "prefetch-dynamic-shell";
5
6
  declare const APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL = "prefetch-loading-shell";
6
7
  declare function getRscRenderModeCacheVariant(mode: AppRscRenderMode): string | null;
7
8
  declare function parseAppRscRenderMode(value: string | null): AppRscRenderMode;
8
9
  //#endregion
9
- export { APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, AppRscRenderMode, getRscRenderModeCacheVariant, parseAppRscRenderMode };
10
+ export { APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, AppRscRenderMode, getRscRenderModeCacheVariant, parseAppRscRenderMode };
@@ -1,18 +1,21 @@
1
1
  //#region src/server/app-rsc-render-mode.ts
2
2
  const APP_RSC_RENDER_MODE_NAVIGATION = "navigation";
3
+ const APP_RSC_RENDER_MODE_PREFETCH_EMPTY = "prefetch-empty";
3
4
  const APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL = "prefetch-dynamic-shell";
4
5
  const APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL = "prefetch-loading-shell";
5
6
  function getRscRenderModeCacheVariant(mode) {
7
+ if (mode === "prefetch-empty") return "prefetch-empty";
6
8
  if (mode === "prefetch-dynamic-shell") return "prefetch-dynamic-shell";
7
9
  if (mode === "prefetch-loading-shell") return "prefetch-loading-shell";
8
10
  return null;
9
11
  }
10
12
  function parseAppRscRenderMode(value) {
11
13
  switch (value) {
14
+ case APP_RSC_RENDER_MODE_PREFETCH_EMPTY: return APP_RSC_RENDER_MODE_PREFETCH_EMPTY;
12
15
  case APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL: return APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL;
13
16
  case APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL: return APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;
14
17
  default: return APP_RSC_RENDER_MODE_NAVIGATION;
15
18
  }
16
19
  }
17
20
  //#endregion
18
- export { APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, getRscRenderModeCacheVariant, parseAppRscRenderMode };
21
+ export { APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, getRscRenderModeCacheVariant, parseAppRscRenderMode };
@@ -1,15 +1,63 @@
1
1
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
2
2
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
3
- import { VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
3
+ import { NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
4
4
  import { normalizePath } from "./normalize-path.js";
5
5
  import { badRequestResponse, notFoundResponse } from "./http-error-responses.js";
6
6
  import { guardProtocolRelativeUrl } from "./request-pipeline.js";
7
7
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
8
- import { APP_RSC_RENDER_MODE_NAVIGATION, parseAppRscRenderMode } from "./app-rsc-render-mode.js";
9
- import { stripRscSuffix } from "./app-rsc-cache-busting.js";
8
+ import { APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, parseAppRscRenderMode } from "./app-rsc-render-mode.js";
9
+ import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, stripRscSuffix } from "./app-rsc-cache-busting.js";
10
10
  import { parseClientReuseManifestHeader } from "./client-reuse-manifest.js";
11
11
  import { normalizeInterceptionContextHeader } from "./app-interception-context-header.js";
12
12
  //#region src/server/app-rsc-request-normalization.ts
13
+ function extractFlightRouterStatePath(value, depth = 0) {
14
+ if (!Array.isArray(value) || value.length < 2 || depth > 64) return null;
15
+ const rawSegment = value[0];
16
+ const segment = Array.isArray(rawSegment) ? rawSegment[1] : rawSegment;
17
+ if (typeof segment !== "string") return null;
18
+ if (segment === "__DEFAULT__" || /^(?:\(\.\)|\(\.\.\)|\(\.\.\.\))/.test(segment)) return null;
19
+ const parallelRoutes = value[1];
20
+ if (!parallelRoutes || typeof parallelRoutes !== "object" || Array.isArray(parallelRoutes)) return null;
21
+ let childPath = null;
22
+ const children = Reflect.get(parallelRoutes, "children");
23
+ if (children !== void 0) childPath = extractFlightRouterStatePath(children, depth + 1);
24
+ if (childPath === null) for (const [key, child] of Object.entries(parallelRoutes)) {
25
+ if (key === "children") continue;
26
+ childPath = extractFlightRouterStatePath(child, depth + 1);
27
+ if (childPath !== null) break;
28
+ }
29
+ return `/${[segment === "" || segment === "children" || segment.startsWith("__PAGE__") || segment.startsWith("(") && segment.endsWith(")") ? "" : segment.replace(/^\/+/, ""), ...childPath === null ? [] : childPath.split("/")].filter(Boolean).join("/")}`;
30
+ }
31
+ function parsePrefetchRouterState(value) {
32
+ if (!value) return null;
33
+ try {
34
+ const parsed = JSON.parse(decodeURIComponent(value));
35
+ if (Array.isArray(parsed)) {
36
+ const pathAndSearch = extractFlightRouterStatePath(parsed);
37
+ return pathAndSearch === null ? null : { pathAndSearch };
38
+ }
39
+ if (!parsed || typeof parsed !== "object") return null;
40
+ const pathAndSearch = Reflect.get(parsed, "pathAndSearch");
41
+ const routeId = Reflect.get(parsed, "routeId");
42
+ if (typeof pathAndSearch !== "string" || !pathAndSearch.startsWith("/") || typeof routeId !== "string" || routeId.length === 0) return null;
43
+ return { pathAndSearch };
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+ function normalizeComparablePathAndSearch(value, basePath, baseUrl) {
49
+ const parsed = new URL(value, baseUrl);
50
+ const pathname = basePath && hasBasePath(parsed.pathname, basePath) ? stripBasePath(parsed.pathname, basePath) : parsed.pathname;
51
+ const search = parsed.searchParams.toString();
52
+ return `${pathname}${search ? `?${search}` : ""}`;
53
+ }
54
+ function tryNormalizeComparablePathAndSearch(value, basePath, baseUrl) {
55
+ try {
56
+ return normalizeComparablePathAndSearch(value, basePath, baseUrl);
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
13
61
  /**
14
62
  * Normalize an App Router RSC request.
15
63
  *
@@ -65,7 +113,20 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
65
113
  const requestCleanPathname = stripRscSuffix(requestPathname);
66
114
  const interceptionContextHeader = normalizeInterceptionContextHeader(request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER));
67
115
  const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER));
68
- const renderMode = isRscRequest ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) : APP_RSC_RENDER_MODE_NAVIGATION;
116
+ let renderMode = isRscRequest ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) : APP_RSC_RENDER_MODE_NAVIGATION;
117
+ if (isRscRequest && renderMode === "navigation" && request.headers.get("Next-Router-Prefetch") === "1" && request.headers.get("Next-Router-Segment-Prefetch") === null) {
118
+ const nextUrl = request.headers.get(NEXT_URL_HEADER);
119
+ const routerState = parsePrefetchRouterState(request.headers.get(NEXT_ROUTER_STATE_TREE_HEADER));
120
+ if (nextUrl && routerState) {
121
+ const targetUrl = new URL(url);
122
+ targetUrl.pathname = cleanPathname;
123
+ targetUrl.searchParams.delete(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
124
+ const routerPathAndSearch = tryNormalizeComparablePathAndSearch(routerState.pathAndSearch, basePath, url);
125
+ const nextPathAndSearch = tryNormalizeComparablePathAndSearch(nextUrl, basePath, url);
126
+ const targetPathAndSearch = normalizeComparablePathAndSearch(targetUrl.href, basePath, url);
127
+ if (routerPathAndSearch !== null && nextPathAndSearch !== null) renderMode = routerPathAndSearch === nextPathAndSearch && routerPathAndSearch === targetPathAndSearch ? APP_RSC_RENDER_MODE_PREFETCH_EMPTY : APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;
128
+ }
129
+ }
69
130
  return {
70
131
  clientReuseManifest: isRscRequest ? parseClientReuseManifestHeader(request.headers.get(VINEXT_CLIENT_REUSE_MANIFEST_HEADER)) : { kind: "absent" },
71
132
  hadBasePath,
@@ -33,8 +33,11 @@ type AppRscInterceptForMatching = {
33
33
  interceptLayouts: readonly unknown[];
34
34
  interceptLayoutSegments?: readonly (readonly string[])[];
35
35
  interceptBranchSegments?: readonly string[];
36
+ interceptLoadings?: readonly unknown[];
37
+ interceptLoadingTreePositions?: readonly number[];
36
38
  interceptNotFoundBranchSegments?: readonly string[];
37
39
  __loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
40
+ __loadInterceptLoadings?: readonly (() => Promise<unknown>)[] | null;
38
41
  page: unknown;
39
42
  __pageLoader?: (() => Promise<unknown>) | null;
40
43
  notFound?: unknown;
@@ -54,8 +57,11 @@ type AppRscSiblingInterceptForMatching = {
54
57
  interceptLayouts: readonly unknown[];
55
58
  interceptLayoutSegments?: readonly (readonly string[])[];
56
59
  interceptBranchSegments?: readonly string[];
60
+ interceptLoadings?: readonly unknown[];
61
+ interceptLoadingTreePositions?: readonly number[];
57
62
  interceptNotFoundBranchSegments?: readonly string[];
58
63
  __loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
64
+ __loadInterceptLoadings?: readonly (() => Promise<unknown>)[] | null;
59
65
  page: unknown;
60
66
  __pageLoader?: (() => Promise<unknown>) | null;
61
67
  notFound?: unknown;
@@ -93,8 +99,11 @@ type AppRscInterceptLookupEntry = {
93
99
  interceptLayouts: readonly unknown[];
94
100
  interceptLayoutSegments?: readonly (readonly string[])[];
95
101
  interceptBranchSegments?: readonly string[];
102
+ interceptLoadings?: readonly unknown[];
103
+ interceptLoadingTreePositions?: readonly number[];
96
104
  interceptNotFoundBranchSegments?: readonly string[];
97
105
  __loadInterceptLayouts?: readonly (() => Promise<unknown>)[] | null;
106
+ __loadInterceptLoadings?: readonly (() => Promise<unknown>)[] | null;
98
107
  page: unknown;
99
108
  __pageLoader?: (() => Promise<unknown>) | null;
100
109
  notFound: unknown;
@@ -170,8 +170,11 @@ function createInterceptLookup(routes) {
170
170
  interceptLayouts: intercept.interceptLayouts,
171
171
  interceptLayoutSegments: intercept.interceptLayoutSegments,
172
172
  interceptBranchSegments: intercept.interceptBranchSegments,
173
+ interceptLoadings: intercept.interceptLoadings,
174
+ interceptLoadingTreePositions: intercept.interceptLoadingTreePositions,
173
175
  interceptNotFoundBranchSegments: intercept.interceptNotFoundBranchSegments,
174
176
  __loadInterceptLayouts: intercept.__loadInterceptLayouts,
177
+ __loadInterceptLoadings: intercept.__loadInterceptLoadings,
175
178
  page: intercept.page,
176
179
  __pageLoader: intercept.__pageLoader,
177
180
  notFound: intercept.notFound,
@@ -203,8 +206,11 @@ function createInterceptLookup(routes) {
203
206
  interceptLayouts: intercept.interceptLayouts,
204
207
  interceptLayoutSegments: intercept.interceptLayoutSegments,
205
208
  interceptBranchSegments: intercept.interceptBranchSegments,
209
+ interceptLoadings: intercept.interceptLoadings,
210
+ interceptLoadingTreePositions: intercept.interceptLoadingTreePositions,
206
211
  interceptNotFoundBranchSegments: intercept.interceptNotFoundBranchSegments,
207
212
  __loadInterceptLayouts: intercept.__loadInterceptLayouts,
213
+ __loadInterceptLoadings: intercept.__loadInterceptLoadings,
208
214
  page: intercept.page,
209
215
  __pageLoader: intercept.__pageLoader,
210
216
  notFound: intercept.notFound,
@@ -1,5 +1,5 @@
1
- import { ActionRevalidationKind } from "../shims/cache-request-state.js";
2
1
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
2
+ import { ActionRevalidationKind } from "../shims/cache-request-state.js";
3
3
  import { FetchCacheMode } from "../shims/fetch-cache.js";
4
4
  import { HeadersAccessPhase } from "../shims/headers.js";
5
5
  import { ReactFormState } from "react-dom/client";
@@ -6,13 +6,12 @@ import "./app-elements.js";
6
6
  import { isPprFallbackShellAbortError } from "../shims/ppr-fallback-shell.js";
7
7
  import { AppRouterContext } from "../shims/internal/app-router-context.js";
8
8
  import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
9
- import { ServerInsertedHTMLContext, clearServerInsertedHTML, getBfcacheIdMapContext, registerServerInsertedHTMLCallback, renderServerInsertedHTML, setNavigationContext } from "../shims/navigation-context-state.js";
10
- import "../shims/navigation-server.js";
11
- import { runWithNavigationContext } from "../shims/navigation-state.js";
12
9
  import { withScriptNonce } from "../shims/script-nonce-context.js";
13
10
  import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonStringify } from "./html.js";
14
11
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
15
12
  import { setPagesClientAssets } from "./pages-client-assets.js";
13
+ import { ServerInsertedHTMLContext, clearServerInsertedHTML, getBfcacheIdMapContext, registerServerInsertedHTMLCallback, renderServerInsertedHTML, setNavigationContext } from "../shims/navigation-context-state.js";
14
+ import "../shims/navigation-server.js";
16
15
  import DefaultGlobalError from "../shims/default-global-error.js";
17
16
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
18
17
  import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
@@ -22,6 +21,7 @@ import { RSC_FORM_STATE_GLOBAL } from "./app-browser-hydration.js";
22
21
  import { createClientReferencePreloader } from "./app-client-reference-preloader.js";
23
22
  import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
24
23
  import { runWithRootParamsScope } from "../shims/root-params.js";
24
+ import { runWithNavigationContext } from "../shims/navigation-state.js";
25
25
  import { BeforeInteractiveContext } from "../shims/before-interactive-context.js";
26
26
  import { renderBeforeInteractiveInlineScripts } from "./before-interactive-head.js";
27
27
  import { createInitialDevServerErrorScript } from "./dev-initial-server-error.js";
@@ -123,7 +123,7 @@ function renderFontHtml(fontData, nonce, options = {}) {
123
123
  const nonceAttr = createNonceAttribute(nonce);
124
124
  const includeStyles = options.includeStyles ?? true;
125
125
  for (const url of fontData.links ?? []) fontHTML += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(url))}" />\n`;
126
- for (const preload of fontData.preloads ?? []) fontHTML += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(preload.href))}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n`;
126
+ for (const preload of fontData.preloads ?? []) fontHTML += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(preload.href)}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n`;
127
127
  if (includeStyles && fontData.styles && fontData.styles.length > 0) fontHTML += `<style data-vinext-fonts${nonceAttr}>${fontData.styles.join("\n")}</style>\n`;
128
128
  return fontHTML;
129
129
  }
@@ -25,5 +25,10 @@ declare function isVisitedResponseCacheEntryFresh(entry: VisitedResponseCacheEnt
25
25
  navigationKind: VisitedResponseCacheNavigationKind;
26
26
  now: number;
27
27
  }): boolean;
28
+ declare function findVisitedResponseCacheEntry(cache: Map<string, VisitedResponseCacheEntry>, rscUrl: string, interceptionContext: string | null): {
29
+ cacheKey: string;
30
+ entry: VisitedResponseCacheEntry;
31
+ } | null;
32
+ declare function deleteVisitedResponseCacheEntry(cache: Map<string, VisitedResponseCacheEntry>, rscUrl: string, interceptionContext: string | null): boolean;
28
33
  //#endregion
29
- export { MAX_TRAVERSAL_CACHE_TTL, VISITED_RESPONSE_CACHE_TTL, VisitedResponseCacheEntry, createVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh };
34
+ export { MAX_TRAVERSAL_CACHE_TTL, VISITED_RESPONSE_CACHE_TTL, VisitedResponseCacheEntry, createVisitedResponseCacheEntry, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh };
@@ -1,3 +1,6 @@
1
+ import { AppElementsWire } from "./app-elements-wire.js";
2
+ import "./app-elements.js";
3
+ import { stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
1
4
  import { resolveCachedRscResponseExpiresAt } from "../shims/navigation.js";
2
5
  //#region src/server/app-visited-response-cache.ts
3
6
  const VISITED_RESPONSE_CACHE_TTL = 5 * 6e4;
@@ -17,5 +20,50 @@ function isVisitedResponseCacheEntryFresh(entry, options) {
17
20
  if (options.navigationKind === "traverse") return options.now - entry.createdAt < MAX_TRAVERSAL_CACHE_TTL;
18
21
  return entry.expiresAt > options.now;
19
22
  }
23
+ function normalizeVisitedResponseCacheLookupUrl(rscUrl) {
24
+ try {
25
+ const url = new URL(rscUrl, "http://vinext.local");
26
+ stripRscCacheBustingSearchParam(url);
27
+ return `${url.pathname}${url.search}`;
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function parseVisitedResponseCacheKey(cacheKey) {
33
+ const separatorIndex = cacheKey.indexOf("\0");
34
+ if (separatorIndex === -1) return {
35
+ interceptionContext: null,
36
+ rscUrl: cacheKey
37
+ };
38
+ return {
39
+ interceptionContext: cacheKey.slice(separatorIndex + 1),
40
+ rscUrl: cacheKey.slice(0, separatorIndex)
41
+ };
42
+ }
43
+ function findVisitedResponseCacheEntry(cache, rscUrl, interceptionContext) {
44
+ const exactCacheKey = AppElementsWire.encodeCacheKey(rscUrl, interceptionContext);
45
+ const exactEntry = cache.get(exactCacheKey);
46
+ if (exactEntry) return {
47
+ cacheKey: exactCacheKey,
48
+ entry: exactEntry
49
+ };
50
+ const normalizedTarget = normalizeVisitedResponseCacheLookupUrl(rscUrl);
51
+ if (normalizedTarget === null) return null;
52
+ for (const [cacheKey, entry] of cache) {
53
+ const source = parseVisitedResponseCacheKey(cacheKey);
54
+ if (source.interceptionContext !== interceptionContext) continue;
55
+ if (normalizeVisitedResponseCacheLookupUrl(source.rscUrl) !== normalizedTarget) continue;
56
+ return {
57
+ cacheKey,
58
+ entry
59
+ };
60
+ }
61
+ return null;
62
+ }
63
+ function deleteVisitedResponseCacheEntry(cache, rscUrl, interceptionContext) {
64
+ const match = findVisitedResponseCacheEntry(cache, rscUrl, interceptionContext);
65
+ if (!match) return false;
66
+ return cache.delete(match.cacheKey);
67
+ }
20
68
  //#endregion
21
- export { MAX_TRAVERSAL_CACHE_TTL, VISITED_RESPONSE_CACHE_TTL, createVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh };
69
+ export { MAX_TRAVERSAL_CACHE_TTL, VISITED_RESPONSE_CACHE_TTL, createVisitedResponseCacheEntry, deleteVisitedResponseCacheEntry, findVisitedResponseCacheEntry, isVisitedResponseCacheEntryFresh };
@@ -26,7 +26,7 @@ declare function applyCdnResponseHeaders(headers: Headers, input: CdnCacheableHe
26
26
  * Next.js source:
27
27
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/cache-control.ts
28
28
  */
29
- declare function buildRevalidateCacheControl(revalidateSeconds: number, expireSeconds?: number): string;
29
+ declare function buildRevalidateCacheControl(revalidateSeconds: number | false, expireSeconds?: number): string;
30
30
  /**
31
31
  * Builds Cache-Control for ISR cache reads. HIT responses and STALE responses
32
32
  * with stored expire metadata use the same route policy because Next.js derives
@@ -34,6 +34,6 @@ declare function buildRevalidateCacheControl(revalidateSeconds: number, expireSe
34
34
  * STALE entries without expire metadata keep vinext's legacy `s-maxage=0`
35
35
  * fallback so older cache entries are not treated as newly fresh downstream.
36
36
  */
37
- declare function buildCachedRevalidateCacheControl(cacheState: "HIT" | "STALE", revalidateSeconds: number, expireSeconds?: number): string;
37
+ declare function buildCachedRevalidateCacheControl(cacheState: "HIT" | "STALE", revalidateSeconds: number | false, expireSeconds?: number): string;
38
38
  //#endregion
39
39
  export { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, buildCachedRevalidateCacheControl, buildRevalidateCacheControl, shouldUseNextDeployCacheControl };
@@ -48,6 +48,7 @@ function applyCdnResponseHeaders(headers, input) {
48
48
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/cache-control.ts
49
49
  */
50
50
  function buildRevalidateCacheControl(revalidateSeconds, expireSeconds) {
51
+ if (revalidateSeconds === false) return STATIC_CACHE_CONTROL;
51
52
  if (expireSeconds === void 0) return `s-maxage=${revalidateSeconds}, stale-while-revalidate`;
52
53
  if (revalidateSeconds >= expireSeconds) return `s-maxage=${revalidateSeconds}`;
53
54
  return `s-maxage=${revalidateSeconds}, stale-while-revalidate=${expireSeconds - revalidateSeconds}`;
@@ -60,7 +61,7 @@ function buildRevalidateCacheControl(revalidateSeconds, expireSeconds) {
60
61
  * fallback so older cache entries are not treated as newly fresh downstream.
61
62
  */
62
63
  function buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds) {
63
- if (revalidateSeconds === Infinity) return STATIC_CACHE_CONTROL;
64
+ if (revalidateSeconds === false || revalidateSeconds === Infinity) return STATIC_CACHE_CONTROL;
64
65
  if (cacheState === "STALE" && expireSeconds === void 0) return STALE_REVALIDATE_CACHE_CONTROL;
65
66
  return buildRevalidateCacheControl(revalidateSeconds, expireSeconds);
66
67
  }
@@ -53,7 +53,9 @@ clientTraceMetadata?: readonly string[], htmlLimitedBots?: string,
53
53
  * `nextConfig?.reactStrictMode === true`.
54
54
  */
55
55
 
56
- reactStrictMode?: boolean): (req: IncomingMessage, res: ServerResponse, url: string, /** Status code override propagated from middleware rewrite status. */
56
+ reactStrictMode?: boolean, /** Next.js `expireTime`, used when formatting terminal GSP responses. */
57
+
58
+ expireTime?: number, crossOrigin?: string): (req: IncomingMessage, res: ServerResponse, url: string, /** Status code override — propagated from middleware rewrite status. */
57
59
 
58
60
  statusCode?: number,
59
61
  /**