vinext 0.2.0 → 0.2.1

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 (128) hide show
  1. package/dist/build/css-url-assets.d.ts +3 -1
  2. package/dist/build/css-url-assets.js +18 -1
  3. package/dist/build/inject-pregenerated-paths.d.ts +3 -0
  4. package/dist/build/inject-pregenerated-paths.js +4 -1
  5. package/dist/build/prerender-server-entry.d.ts +1 -0
  6. package/dist/build/prerender-server-entry.js +49 -0
  7. package/dist/build/prerender-server-pool.d.ts +44 -0
  8. package/dist/build/prerender-server-pool.js +194 -0
  9. package/dist/build/prerender.js +86 -22
  10. package/dist/build/run-prerender.js +2 -1
  11. package/dist/check.d.ts +4 -6
  12. package/dist/check.js +8 -9
  13. package/dist/cli.js +1 -1
  14. package/dist/client/vinext-next-data.d.ts +4 -1
  15. package/dist/config/config-matchers.js +33 -11
  16. package/dist/config/next-config.d.ts +36 -6
  17. package/dist/config/next-config.js +16 -2
  18. package/dist/entries/app-browser-entry.js +5 -1
  19. package/dist/entries/app-rsc-entry.d.ts +3 -2
  20. package/dist/entries/app-rsc-entry.js +4 -0
  21. package/dist/entries/pages-client-entry.js +14 -3
  22. package/dist/entries/pages-server-entry.js +18 -4
  23. package/dist/index.js +320 -25
  24. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
  25. package/dist/packages/cloudflare/src/deploy.js +1 -5
  26. package/dist/packages/cloudflare/src/tpr.js +26 -5
  27. package/dist/plugins/fonts.js +1 -1
  28. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  29. package/dist/plugins/og-assets.js +2 -1
  30. package/dist/plugins/optimize-imports.js +1 -1
  31. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  32. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  33. package/dist/plugins/sass.d.ts +17 -1
  34. package/dist/plugins/sass.js +74 -1
  35. package/dist/plugins/styled-jsx.d.ts +16 -0
  36. package/dist/plugins/styled-jsx.js +149 -0
  37. package/dist/routing/app-route-graph.js +22 -16
  38. package/dist/routing/file-matcher.d.ts +8 -1
  39. package/dist/routing/file-matcher.js +15 -3
  40. package/dist/server/app-browser-entry.js +46 -14
  41. package/dist/server/app-browser-navigation-controller.js +1 -1
  42. package/dist/server/app-browser-server-action-client.js +5 -3
  43. package/dist/server/app-browser-state.d.ts +1 -0
  44. package/dist/server/app-browser-state.js +2 -2
  45. package/dist/server/app-browser-visible-commit.js +1 -1
  46. package/dist/server/app-page-boundary.js +2 -1
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +3 -3
  49. package/dist/server/app-page-cache.js +23 -6
  50. package/dist/server/app-page-dispatch.d.ts +1 -0
  51. package/dist/server/app-page-dispatch.js +25 -8
  52. package/dist/server/app-page-element-builder.js +1 -0
  53. package/dist/server/app-page-execution.js +2 -1
  54. package/dist/server/app-page-render-identity.d.ts +1 -0
  55. package/dist/server/app-page-render-identity.js +2 -1
  56. package/dist/server/app-page-render.d.ts +2 -0
  57. package/dist/server/app-page-render.js +67 -16
  58. package/dist/server/app-page-response.d.ts +7 -0
  59. package/dist/server/app-page-response.js +16 -4
  60. package/dist/server/app-page-stream.d.ts +2 -1
  61. package/dist/server/app-page-stream.js +1 -1
  62. package/dist/server/app-route-handler-execution.js +1 -1
  63. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  64. package/dist/server/app-route-tree-prefetch.js +187 -0
  65. package/dist/server/app-router-entry.js +1 -1
  66. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  67. package/dist/server/app-rsc-cache-busting.js +9 -4
  68. package/dist/server/app-rsc-handler.d.ts +6 -0
  69. package/dist/server/app-rsc-handler.js +89 -11
  70. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  71. package/dist/server/app-rsc-render-mode.js +4 -1
  72. package/dist/server/app-rsc-request-normalization.d.ts +3 -4
  73. package/dist/server/app-rsc-request-normalization.js +4 -5
  74. package/dist/server/app-server-action-execution.js +4 -3
  75. package/dist/server/app-ssr-entry.js +3 -3
  76. package/dist/server/cache-control.d.ts +3 -1
  77. package/dist/server/cache-control.js +13 -1
  78. package/dist/server/dev-server.d.ts +11 -1
  79. package/dist/server/dev-server.js +78 -20
  80. package/dist/server/headers.d.ts +6 -2
  81. package/dist/server/headers.js +11 -5
  82. package/dist/server/isr-cache.d.ts +2 -1
  83. package/dist/server/isr-cache.js +7 -3
  84. package/dist/server/pages-data-route.d.ts +4 -2
  85. package/dist/server/pages-data-route.js +18 -4
  86. package/dist/server/pages-dev-module-url.d.ts +2 -1
  87. package/dist/server/pages-dev-module-url.js +6 -3
  88. package/dist/server/pages-node-compat.d.ts +12 -1
  89. package/dist/server/pages-node-compat.js +50 -1
  90. package/dist/server/pages-page-data.d.ts +9 -0
  91. package/dist/server/pages-page-data.js +17 -9
  92. package/dist/server/pages-page-handler.js +19 -7
  93. package/dist/server/pages-page-response.d.ts +1 -0
  94. package/dist/server/pages-page-response.js +3 -2
  95. package/dist/server/pages-request-pipeline.d.ts +8 -6
  96. package/dist/server/pages-request-pipeline.js +30 -6
  97. package/dist/server/pages-router-entry.js +1 -1
  98. package/dist/server/prod-server.d.ts +4 -2
  99. package/dist/server/prod-server.js +38 -22
  100. package/dist/server/request-pipeline.js +1 -1
  101. package/dist/shims/cache-handler.js +8 -1
  102. package/dist/shims/cache.js +3 -0
  103. package/dist/shims/fetch-cache.d.ts +3 -1
  104. package/dist/shims/fetch-cache.js +77 -52
  105. package/dist/shims/form.d.ts +1 -1
  106. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  107. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  108. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
  109. package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
  110. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
  111. package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
  112. package/dist/shims/internal/pages-data-target.d.ts +8 -3
  113. package/dist/shims/internal/pages-data-target.js +9 -4
  114. package/dist/shims/link.d.ts +1 -1
  115. package/dist/shims/link.js +179 -42
  116. package/dist/shims/navigation.d.ts +15 -3
  117. package/dist/shims/navigation.js +202 -39
  118. package/dist/shims/navigation.react-server.js +1 -1
  119. package/dist/shims/request-context.js +18 -0
  120. package/dist/shims/router.js +31 -15
  121. package/dist/shims/unified-request-context.js +1 -0
  122. package/dist/typegen.js +1 -1
  123. package/dist/utils/middleware-request-headers.js +1 -1
  124. package/dist/utils/protocol-headers.d.ts +7 -1
  125. package/dist/utils/protocol-headers.js +7 -1
  126. package/dist/utils/vite-version.d.ts +2 -0
  127. package/dist/utils/vite-version.js +11 -1
  128. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
1
  import { 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 } from "../utils/protocol-headers.js";
4
+ import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
5
5
  import { ACTION_REVALIDATED_HEADER } from "./headers.js";
6
6
  import { isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
7
7
  import { notFoundResponse } from "./http-error-responses.js";
@@ -19,10 +19,11 @@ import "./app-page-response.js";
19
19
  import { parseNextHttpErrorDigest } from "./next-error-digest.js";
20
20
  import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
21
21
  import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
22
+ import { pickRootParams, setRootParams } from "../shims/root-params.js";
22
23
  import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
23
24
  import { buildPageCacheTags } from "./implicit-tags.js";
24
25
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
25
- import { pickRootParams, setRootParams } from "../shims/root-params.js";
26
+ import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
26
27
  import { flattenErrorCauses } from "../utils/error-cause.js";
27
28
  import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
28
29
  import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
@@ -163,10 +164,10 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
163
164
  headers: { Location: location }
164
165
  });
165
166
  }
166
- const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({
167
+ const rscCacheBustingRedirect = hadBasePath ? await resolveInvalidRscCacheBustingRequest({
167
168
  isRscRequest,
168
169
  request
169
- });
170
+ }) : null;
170
171
  if (rscCacheBustingRedirect) return rscCacheBustingRedirect;
171
172
  const normalizedUserlandRequest = requestWithoutRscSuffix(request);
172
173
  const userlandRequest = requestWithoutRscCacheBustingSearchParam(normalizedUserlandRequest);
@@ -200,6 +201,13 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
200
201
  const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);
201
202
  const postMiddlewareRequestContext = buildPostMwRequestContext(userlandRequest);
202
203
  let filesystemRouteEligible = hadBasePath || didMiddlewareRewrite;
204
+ const validateClaimedOutsideBasePathRsc = async () => {
205
+ if (hadBasePath || !filesystemRouteEligible) return null;
206
+ return resolveInvalidRscCacheBustingRequest({
207
+ isRscRequest,
208
+ request
209
+ });
210
+ };
203
211
  for (const rewrite of options.configRewrites.beforeFiles) {
204
212
  const beforeFilesRewrite = await applyRewrite({
205
213
  basePathState,
@@ -215,6 +223,51 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
215
223
  filesystemRouteEligible = true;
216
224
  }
217
225
  }
226
+ const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
227
+ if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
228
+ const actionId = request.headers.get("x-rsc-action") ?? request.headers.get("next-action");
229
+ const isPostRequest = request.method.toUpperCase() === "POST";
230
+ const contentType = request.headers.get("content-type") || "";
231
+ const isProgressiveActionRequest = isPostRequest && !actionId && contentType.startsWith("multipart/form-data");
232
+ let resolvedLateRewritesForAction = false;
233
+ if (!filesystemRouteEligible && (actionId || isProgressiveActionRequest)) {
234
+ let actionMatch = null;
235
+ for (const rewrite of options.configRewrites.afterFiles) {
236
+ const rewritten = await applyRewrite({
237
+ basePathState,
238
+ clearRequestContext: options.clearRequestContext,
239
+ request: normalizedUserlandRequest,
240
+ requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
241
+ rewrites: [rewrite]
242
+ }, matchPathname(cleanPathname));
243
+ if (rewritten instanceof Response) return rewritten;
244
+ if (!rewritten) continue;
245
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
246
+ cleanPathname = pathnameForResolvedUrl(resolvedUrl);
247
+ filesystemRouteEligible = true;
248
+ actionMatch = options.matchRoute(cleanPathname);
249
+ if (actionMatch) break;
250
+ }
251
+ if (!actionMatch) for (const rewrite of options.configRewrites.fallback) {
252
+ const rewritten = await applyRewrite({
253
+ basePathState,
254
+ clearRequestContext: options.clearRequestContext,
255
+ request: normalizedUserlandRequest,
256
+ requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
257
+ rewrites: [rewrite]
258
+ }, matchPathname(cleanPathname));
259
+ if (rewritten instanceof Response) return rewritten;
260
+ if (!rewritten) continue;
261
+ resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
262
+ cleanPathname = pathnameForResolvedUrl(resolvedUrl);
263
+ filesystemRouteEligible = true;
264
+ actionMatch = options.matchRoute(cleanPathname);
265
+ if (actionMatch) break;
266
+ }
267
+ resolvedLateRewritesForAction = filesystemRouteEligible;
268
+ }
269
+ const lateActionRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
270
+ if (lateActionRscCacheBustingRedirect) return lateActionRscCacheBustingRedirect;
218
271
  if (filesystemRouteEligible && isImageOptimizationPath(cleanPathname)) {
219
272
  const imageRedirect = resolveDevImageRedirect(url, [...options.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...options.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], options.imageConfig?.qualities, { isDev: options.isDev });
220
273
  if (!imageRedirect) return new Response("Invalid image optimization parameters", { status: 400 });
@@ -255,9 +308,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
255
308
  });
256
309
  const preActionMatch = filesystemRouteEligible ? options.matchRoute(cleanPathname) : null;
257
310
  if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
258
- const actionId = request.headers.get("x-rsc-action") ?? request.headers.get("next-action");
259
- const contentType = request.headers.get("content-type") || "";
260
- const isPostRequest = request.method.toUpperCase() === "POST";
311
+ if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch) {
312
+ const headers = new Headers();
313
+ mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
314
+ headers.set("content-type", "application/json");
315
+ headers.set("x-nextjs-rewrite", resolvedUrl);
316
+ options.clearRequestContext();
317
+ return new Response("{}", { headers });
318
+ }
319
+ if (!filesystemRouteEligible && isPostRequest && actionId) {
320
+ options.clearRequestContext();
321
+ return notFoundResponse();
322
+ }
261
323
  let progressiveActionResult = null;
262
324
  if (filesystemRouteEligible && isPostRequest && contentType.startsWith("multipart/form-data") && !actionId) {
263
325
  if (options.handleProgressiveActionRequest) progressiveActionResult = await options.handleProgressiveActionRequest({
@@ -322,7 +384,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
322
384
  options.clearRequestContext();
323
385
  return staticPagesFallbackResponse;
324
386
  }
325
- if (!match || match.route.isDynamic) for (const rewrite of options.configRewrites.afterFiles) {
387
+ if (!resolvedLateRewritesForAction && (!match || match.route.isDynamic)) for (const rewrite of options.configRewrites.afterFiles) {
326
388
  const afterFilesRewrite = await applyRewrite({
327
389
  basePathState,
328
390
  clearRequestContext: options.clearRequestContext,
@@ -335,6 +397,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
335
397
  resolvedUrl = mergeRewriteQuery(resolvedUrl, afterFilesRewrite);
336
398
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
337
399
  filesystemRouteEligible = true;
400
+ const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
401
+ if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
338
402
  match = options.matchRoute(cleanPathname);
339
403
  const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
340
404
  if (rewrittenStaticPagesResponse) {
@@ -353,7 +417,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
353
417
  options.clearRequestContext();
354
418
  return dynamicPagesFallbackResponse;
355
419
  }
356
- if (!match) for (const rewrite of options.configRewrites.fallback) {
420
+ if (!resolvedLateRewritesForAction && !match) for (const rewrite of options.configRewrites.fallback) {
357
421
  const fallbackRewrite = await applyRewrite({
358
422
  basePathState,
359
423
  clearRequestContext: options.clearRequestContext,
@@ -366,6 +430,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
366
430
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
367
431
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
368
432
  filesystemRouteEligible = true;
433
+ const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
434
+ if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
369
435
  match = options.matchRoute(cleanPathname);
370
436
  const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
371
437
  if (rewrittenStaticPagesResponse) {
@@ -391,6 +457,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
391
457
  const response = buildNextDataNotFoundResponse();
392
458
  const headers = new Headers(response.headers);
393
459
  headers.set("x-nextjs-matched-path", matchPathname(canonicalPathname));
460
+ if (resolvedUrl !== originalResolvedUrl) headers.set("x-nextjs-rewrite", resolvedUrl);
394
461
  return new Response("{}", {
395
462
  status: 200,
396
463
  headers
@@ -418,11 +485,19 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
418
485
  }
419
486
  const { route, params } = match;
420
487
  if (options.ensureRouteLoaded) await options.ensureRouteLoaded(route);
488
+ const resolvedSearchParams = getResolvedSearchParams();
489
+ if (isRouteTreePrefetchRequest(request) && !route.routeHandler) {
490
+ const response = await createRouteTreePrefetchResponse(route, {
491
+ buildId: options.buildId,
492
+ prefetchInlining: options.prefetchInlining
493
+ });
494
+ options.clearRequestContext();
495
+ return applyMiddlewareContextToResponse(response, middlewareContext);
496
+ }
421
497
  const prerenderRouteParamsMatch = matchPrerenderRouteParamsPayload(readTrustedPrerenderRouteParams(request), route.pattern, params);
422
498
  const prerenderRouteParams = prerenderRouteParamsMatch?.params ?? null;
423
499
  const isPrerenderFallbackShell = prerenderRouteParamsMatch?.kind === "fallback-shell";
424
500
  const renderParams = prerenderRouteParams ?? params;
425
- const resolvedSearchParams = getResolvedSearchParams();
426
501
  let runtimeFallbackShells = [];
427
502
  if (options.createPprFallbackShells && request.method === "GET" && !isRscRequest && !isPrerenderFallbackShell && route.params) runtimeFallbackShells = options.createPprFallbackShells({
428
503
  params: route.params,
@@ -476,6 +551,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
476
551
  staticParamsValidationParams: prerenderRouteParams === null || isPrerenderFallbackShell ? void 0 : params,
477
552
  rootParams,
478
553
  request,
554
+ renderedPathAndSearch: resolvedUrl,
479
555
  route,
480
556
  scriptNonce,
481
557
  searchParams: resolvedSearchParams,
@@ -525,14 +601,16 @@ function createAppRscHandler(options) {
525
601
  const pagesDataInScope = !options.basePath || hasBasePath(pagesDataUrl.pathname, options.basePath);
526
602
  if (pagesDataInScope) pagesDataUrl.pathname = stripBasePath(pagesDataUrl.pathname, options.basePath);
527
603
  const pagesDataCandidate = pagesDataInScope ? cloneRequestWithUrl(rawRequest, pagesDataUrl.toString()) : null;
528
- const pagesDataNormalization = options.renderPagesFallback && pagesDataCandidate ? normalizePagesDataRequest(pagesDataCandidate, options.buildId) : null;
604
+ const pagesDataNormalization = options.renderPagesFallback && pagesDataCandidate ? normalizePagesDataRequest(pagesDataCandidate, options.buildId, "", typeof options.runMiddleware === "function" && options.trailingSlash) : null;
529
605
  if (pagesDataNormalization?.notFoundResponse) return pagesDataNormalization.notFoundResponse;
530
606
  const isPagesDataRequest = pagesDataNormalization?.isDataReq === true;
531
607
  const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);
608
+ const isTrustedSpeculativePrerender = process.env.VINEXT_PRERENDER === "1" && rawRequest.headers.get("x-vinext-prerender-secret") !== null && rawRequest.headers.get("x-vinext-prerender-speculative") === "1";
532
609
  const filteredHeaders = filterInternalHeaders(rawRequest.headers);
533
610
  if (mwCtx !== null) filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);
534
611
  const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
535
612
  if (prerenderRouteParamsHeader !== null) filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
613
+ if (isTrustedSpeculativePrerender) filteredHeaders.set(VINEXT_PRERENDER_SPECULATIVE_HEADER, "1");
536
614
  let appRequest = rawRequest;
537
615
  if (pagesDataNormalization?.isDataReq) {
538
616
  const appRequestUrl = new URL(pagesDataNormalization.request.url);
@@ -1,6 +1,7 @@
1
1
  //#region src/server/app-rsc-render-mode.d.ts
2
- type AppRscRenderMode = "navigation" | "prefetch-loading-shell" | "refresh-preserve-ui" | "action-rerender-preserve-ui";
2
+ type AppRscRenderMode = "navigation" | "prefetch-dynamic-shell" | "prefetch-loading-shell" | "refresh-preserve-ui" | "action-rerender-preserve-ui";
3
3
  declare const APP_RSC_RENDER_MODE_NAVIGATION = "navigation";
4
+ declare const APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL = "prefetch-dynamic-shell";
4
5
  declare const APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL = "prefetch-loading-shell";
5
6
  declare const APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI = "refresh-preserve-ui";
6
7
  declare const APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI = "action-rerender-preserve-ui";
@@ -8,4 +9,4 @@ declare function shouldSuppressLoadingBoundaries(mode: AppRscRenderMode): boolea
8
9
  declare function getRscRenderModeCacheVariant(mode: AppRscRenderMode): string | null;
9
10
  declare function parseAppRscRenderMode(value: string | null): AppRscRenderMode;
10
11
  //#endregion
11
- export { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI, APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI, AppRscRenderMode, getRscRenderModeCacheVariant, parseAppRscRenderMode, shouldSuppressLoadingBoundaries };
12
+ export { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI, APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI, AppRscRenderMode, getRscRenderModeCacheVariant, parseAppRscRenderMode, shouldSuppressLoadingBoundaries };
@@ -1,5 +1,6 @@
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_DYNAMIC_SHELL = "prefetch-dynamic-shell";
3
4
  const APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL = "prefetch-loading-shell";
4
5
  const APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI = "refresh-preserve-ui";
5
6
  const APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI = "action-rerender-preserve-ui";
@@ -10,11 +11,13 @@ function shouldUsePreserveUiCacheVariant(mode) {
10
11
  return shouldSuppressLoadingBoundaries(mode);
11
12
  }
12
13
  function getRscRenderModeCacheVariant(mode) {
14
+ if (mode === "prefetch-dynamic-shell") return "prefetch-dynamic-shell";
13
15
  if (mode === "prefetch-loading-shell") return "prefetch-loading-shell";
14
16
  return shouldUsePreserveUiCacheVariant(mode) ? "preserve-ui" : null;
15
17
  }
16
18
  function parseAppRscRenderMode(value) {
17
19
  switch (value) {
20
+ case APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL: return APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL;
18
21
  case APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL: return APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;
19
22
  case APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI: return APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI;
20
23
  case APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI: return APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI;
@@ -22,4 +25,4 @@ function parseAppRscRenderMode(value) {
22
25
  }
23
26
  }
24
27
  //#endregion
25
- export { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI, APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI, getRscRenderModeCacheVariant, parseAppRscRenderMode, shouldSuppressLoadingBoundaries };
28
+ export { APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI, APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI, getRscRenderModeCacheVariant, parseAppRscRenderMode, shouldSuppressLoadingBoundaries };
@@ -31,10 +31,9 @@ type NormalizedRscRequest = {
31
31
  * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
32
32
  * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
33
33
  * `/__vinext/` bypasses this for internal prerender endpoints.
34
- * 6. RSC detection: `.rsc` suffix, or Next-style `RSC: 1` plus the internal
35
- * `_rsc` cache-busting query. The header alone does not select payload
36
- * rendering at the canonical HTML URL, so caches that ignore Vary cannot
37
- * store Flight responses under HTML URLs.
34
+ * 6. RSC detection: `.rsc` suffix or Next-style `RSC: 1`. The internal
35
+ * `_rsc` cache-busting query is validated separately so full-route Flight
36
+ * responses do not share the canonical HTML URL in caches that ignore Vary.
38
37
  * 7. cleanPathname — pathname with `.rsc` suffix stripped
39
38
  * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
40
39
  * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
@@ -27,10 +27,9 @@ import { normalizeInterceptionContextHeader } from "./app-interception-context-h
27
27
  * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
28
28
  * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
29
29
  * `/__vinext/` bypasses this for internal prerender endpoints.
30
- * 6. RSC detection: `.rsc` suffix, or Next-style `RSC: 1` plus the internal
31
- * `_rsc` cache-busting query. The header alone does not select payload
32
- * rendering at the canonical HTML URL, so caches that ignore Vary cannot
33
- * store Flight responses under HTML URLs.
30
+ * 6. RSC detection: `.rsc` suffix or Next-style `RSC: 1`. The internal
31
+ * `_rsc` cache-busting query is validated separately so full-route Flight
32
+ * responses do not share the canonical HTML URL in caches that ignore Vary.
34
33
  * 7. cleanPathname — pathname with `.rsc` suffix stripped
35
34
  * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
36
35
  * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
@@ -57,7 +56,7 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
57
56
  if (!hadBasePath && !pathname.startsWith("/__vinext/") && !allowOutsideBasePath) return notFoundResponse();
58
57
  if (hadBasePath) pathname = stripBasePath(pathname, basePath);
59
58
  }
60
- const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("RSC") === "1" && url.searchParams.has("_rsc");
59
+ const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("RSC") === "1";
61
60
  const cleanPathname = stripRscSuffix(pathname);
62
61
  const interceptionContextHeader = normalizeInterceptionContextHeader(request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER));
63
62
  const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER));
@@ -13,13 +13,13 @@ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityI
13
13
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
14
14
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
15
15
  import { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
16
+ import { createRootParamsUsageController, pickRootParams, runWithRootParamsScope, runWithRootParamsUsage } from "../shims/root-params.js";
16
17
  import { createServerActionNotFoundResponse, getServerActionNotFoundMessage, isServerActionNotFoundError } from "./server-action-not-found.js";
17
18
  import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
18
19
  import "./app-page-stream.js";
19
20
  import { buildAppPageTags } from "./implicit-tags.js";
20
21
  import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
21
22
  import { resolveAppPageActionRerenderTarget } from "./app-page-request.js";
22
- import { createRootParamsUsageController, pickRootParams, runWithRootParamsScope, runWithRootParamsUsage } from "../shims/root-params.js";
23
23
  import { getSetCookieName } from "./cookie-utils.js";
24
24
  import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
25
25
  //#region src/server/app-server-action-execution.ts
@@ -737,6 +737,7 @@ async function handleServerActionRscRequest(options) {
737
737
  const match = options.matchRoute(options.cleanPathname);
738
738
  let element;
739
739
  let errorPattern = match ? match.route.pattern : options.cleanPathname;
740
+ const actionRerenderIsRscRequest = true;
740
741
  if (match) {
741
742
  const { route: actionRoute, params: actionParams } = match;
742
743
  const actionRerenderTarget = await resolveAppPageActionRerenderTarget({
@@ -746,7 +747,7 @@ async function handleServerActionRscRequest(options) {
746
747
  findIntercept: options.findIntercept,
747
748
  getRouteParamNames: options.getRouteParamNames,
748
749
  getSourceRoute: options.getSourceRoute,
749
- isRscRequest: options.isRscRequest,
750
+ isRscRequest: actionRerenderIsRscRequest,
750
751
  toInterceptOpts: options.toInterceptOpts
751
752
  });
752
753
  const resolvedActionNavigationParams = resolveAppPageNavigationParams(actionRerenderTarget.route, actionRerenderTarget.navigationParams, options.cleanPathname, actionRerenderTarget.interceptOpts);
@@ -771,7 +772,7 @@ async function handleServerActionRscRequest(options) {
771
772
  const buildActionRerenderElement = () => options.buildPageElement({
772
773
  cleanPathname: options.cleanPathname,
773
774
  interceptOpts: actionRerenderTarget.interceptOpts,
774
- isRscRequest: options.isRscRequest,
775
+ isRscRequest: actionRerenderIsRscRequest,
775
776
  mountedSlotsHeader: options.mountedSlotsHeader,
776
777
  params: actionRerenderTarget.params,
777
778
  request: options.request,
@@ -12,17 +12,17 @@ import { runWithNavigationContext } from "../shims/navigation-state.js";
12
12
  import { withScriptNonce } from "../shims/script-nonce-context.js";
13
13
  import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonStringify } from "./html.js";
14
14
  import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
15
+ import { setPagesClientAssets } from "./pages-client-assets.js";
15
16
  import DefaultGlobalError from "../shims/default-global-error.js";
16
17
  import { BfcacheStateKeyMapContext, ElementsContext, Slot } from "../shims/slot.js";
17
18
  import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
18
19
  import { createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform } from "./app-ssr-stream.js";
19
- import { setPagesClientAssets } from "./pages-client-assets.js";
20
+ import { BeforeInteractiveContext } from "../shims/before-interactive-context.js";
21
+ import { runWithRootParamsScope } from "../shims/root-params.js";
20
22
  import { createInitialBfcacheMaps } from "./app-bfcache-identity.js";
21
23
  import { RSC_FORM_STATE_GLOBAL } from "./app-browser-hydration.js";
22
24
  import { createClientReferencePreloader } from "./app-client-reference-preloader.js";
23
25
  import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
24
- import { runWithRootParamsScope } from "../shims/root-params.js";
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";
28
28
  import { ssrAppRouterInstance } from "./app-ssr-router-instance.js";
@@ -2,8 +2,10 @@ import { CdnCacheableHeaderInput } from "../shims/cdn-cache.js";
2
2
 
3
3
  //#region src/server/cache-control.d.ts
4
4
  declare const NEVER_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
5
+ declare const BROWSER_REVALIDATE_CACHE_CONTROL = "public, max-age=0, must-revalidate";
5
6
  declare const STATIC_CACHE_CONTROL = "s-maxage=31536000, stale-while-revalidate";
6
7
  declare const NO_STORE_CACHE_CONTROL = "no-store, must-revalidate";
8
+ declare function shouldUseNextDeployCacheControl(): boolean;
7
9
  /**
8
10
  * Route a cacheable response's headers through the active CDN cache adapter and
9
11
  * apply the result to `headers`. The default adapter yields a single
@@ -34,4 +36,4 @@ declare function buildRevalidateCacheControl(revalidateSeconds: number, expireSe
34
36
  */
35
37
  declare function buildCachedRevalidateCacheControl(cacheState: "HIT" | "STALE", revalidateSeconds: number, expireSeconds?: number): string;
36
38
  //#endregion
37
- export { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, buildCachedRevalidateCacheControl, buildRevalidateCacheControl };
39
+ export { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, buildCachedRevalidateCacheControl, buildRevalidateCacheControl, shouldUseNextDeployCacheControl };
@@ -1,9 +1,17 @@
1
1
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
2
2
  //#region src/server/cache-control.ts
3
3
  const NEVER_CACHE_CONTROL = "private, no-cache, no-store, max-age=0, must-revalidate";
4
+ const BROWSER_REVALIDATE_CACHE_CONTROL = "public, max-age=0, must-revalidate";
4
5
  const STATIC_CACHE_CONTROL = "s-maxage=31536000, stale-while-revalidate";
5
6
  const STALE_REVALIDATE_CACHE_CONTROL = "s-maxage=0, stale-while-revalidate";
6
7
  const NO_STORE_CACHE_CONTROL = "no-store, must-revalidate";
8
+ const SHARED_CACHE_DIRECTIVE_RE = /(?:^|,)\s*s-maxage\s*=/i;
9
+ function shouldUseNextDeployCacheControl() {
10
+ return process.env.VINEXT_NEXT_DEPLOY_CACHE_CONTROL === "1";
11
+ }
12
+ function isSharedCacheControl(cacheControl) {
13
+ return SHARED_CACHE_DIRECTIVE_RE.test(cacheControl);
14
+ }
7
15
  /**
8
16
  * Route a cacheable response's headers through the active CDN cache adapter and
9
17
  * apply the result to `headers`. The default adapter yields a single
@@ -17,6 +25,10 @@ const NO_STORE_CACHE_CONTROL = "no-store, must-revalidate";
17
25
  */
18
26
  function applyCdnResponseHeaders(headers, input) {
19
27
  headers.delete("Cache-Control");
28
+ if (shouldUseNextDeployCacheControl() && isSharedCacheControl(input.cacheControl)) {
29
+ headers.set("Cache-Control", BROWSER_REVALIDATE_CACHE_CONTROL);
30
+ return;
31
+ }
20
32
  const map = getCdnCacheAdapter().buildResponseHeaders(input);
21
33
  for (const [name, value] of Object.entries(map)) {
22
34
  if (value === null) {
@@ -53,4 +65,4 @@ function buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expire
53
65
  return buildRevalidateCacheControl(revalidateSeconds, expireSeconds);
54
66
  }
55
67
  //#endregion
56
- export { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, buildCachedRevalidateCacheControl, buildRevalidateCacheControl };
68
+ export { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, applyCdnResponseHeaders, buildCachedRevalidateCacheControl, buildRevalidateCacheControl, shouldUseNextDeployCacheControl };
@@ -43,7 +43,17 @@ declare function createSSRHandler(server: ViteDevServer, runner: ModuleImporter,
43
43
  * `next.config`. When undefined or empty, no meta tags are emitted.
44
44
  */
45
45
 
46
- clientTraceMetadata?: readonly string[], htmlLimitedBots?: string): (req: IncomingMessage, res: ServerResponse, url: string, /** Status code override — propagated from middleware rewrite status. */
46
+ clientTraceMetadata?: readonly string[], htmlLimitedBots?: string,
47
+ /**
48
+ * Whether `reactStrictMode: true` is set in next.config. When true, the dev
49
+ * hydration script sets `window.__VINEXT_REACT_STRICT_MODE__` so
50
+ * `wrapWithRouterContext` wraps the tree in `<React.StrictMode>` on the
51
+ * initial hydration and every navigation. Pages Router default is OFF
52
+ * (Next.js: `reactStrictMode === null ? false`), so callers pass
53
+ * `nextConfig?.reactStrictMode === true`.
54
+ */
55
+
56
+ reactStrictMode?: boolean): (req: IncomingMessage, res: ServerResponse, url: string, /** Status code override — propagated from middleware rewrite status. */
47
57
 
48
58
  statusCode?: number,
49
59
  /**