vinext 0.1.6 → 0.1.8

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 (114) hide show
  1. package/dist/build/client-build-config.d.ts +4 -6
  2. package/dist/build/client-build-config.js +27 -7
  3. package/dist/build/prerender.js +1 -2
  4. package/dist/check.d.ts +18 -0
  5. package/dist/check.js +37 -17
  6. package/dist/cli.js +2 -2
  7. package/dist/config/next-config.d.ts +2 -1
  8. package/dist/config/next-config.js +3 -0
  9. package/dist/config/server-external-packages.d.ts +4 -0
  10. package/dist/config/server-external-packages.js +91 -0
  11. package/dist/deploy.d.ts +7 -0
  12. package/dist/deploy.js +25 -18
  13. package/dist/entries/app-rsc-entry.d.ts +2 -1
  14. package/dist/entries/app-rsc-entry.js +89 -20
  15. package/dist/entries/app-rsc-manifest.js +8 -0
  16. package/dist/entries/pages-client-entry.js +1 -0
  17. package/dist/entries/pages-server-entry.js +1 -0
  18. package/dist/index.js +87 -34
  19. package/dist/init.js +2 -1
  20. package/dist/plugins/middleware-server-only.d.ts +8 -6
  21. package/dist/plugins/middleware-server-only.js +8 -7
  22. package/dist/plugins/og-assets.js +6 -6
  23. package/dist/plugins/optimize-imports.js +1 -1
  24. package/dist/plugins/remove-console.js +1 -1
  25. package/dist/plugins/strip-server-exports.js +2 -1
  26. package/dist/routing/app-route-graph.d.ts +6 -2
  27. package/dist/routing/app-route-graph.js +61 -13
  28. package/dist/routing/app-router.d.ts +5 -0
  29. package/dist/routing/app-router.js +5 -0
  30. package/dist/routing/file-matcher.d.ts +5 -0
  31. package/dist/routing/file-matcher.js +7 -1
  32. package/dist/server/app-action-request.d.ts +4 -0
  33. package/dist/server/app-action-request.js +9 -0
  34. package/dist/server/app-bfcache-identity.d.ts +12 -2
  35. package/dist/server/app-bfcache-identity.js +52 -23
  36. package/dist/server/app-browser-entry.js +42 -147
  37. package/dist/server/app-browser-history-controller.d.ts +2 -1
  38. package/dist/server/app-browser-history-controller.js +6 -2
  39. package/dist/server/app-browser-server-action-client.d.ts +32 -0
  40. package/dist/server/app-browser-server-action-client.js +128 -0
  41. package/dist/server/app-fallback-renderer.d.ts +3 -1
  42. package/dist/server/app-fallback-renderer.js +6 -2
  43. package/dist/server/app-history-state.d.ts +1 -2
  44. package/dist/server/app-history-state.js +1 -1
  45. package/dist/server/app-page-boundary-render.d.ts +3 -0
  46. package/dist/server/app-page-boundary-render.js +14 -3
  47. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  48. package/dist/server/app-page-cache-finalizer.js +8 -2
  49. package/dist/server/app-page-dispatch.d.ts +33 -4
  50. package/dist/server/app-page-dispatch.js +62 -90
  51. package/dist/server/app-page-element-builder.d.ts +7 -1
  52. package/dist/server/app-page-element-builder.js +56 -19
  53. package/dist/server/app-page-head.d.ts +16 -1
  54. package/dist/server/app-page-head.js +44 -22
  55. package/dist/server/app-page-method.js +1 -1
  56. package/dist/server/app-page-params.d.ts +2 -1
  57. package/dist/server/app-page-params.js +8 -1
  58. package/dist/server/app-page-ppr-runtime.d.ts +7 -0
  59. package/dist/server/app-page-ppr-runtime.js +70 -0
  60. package/dist/server/app-page-probe.d.ts +1 -0
  61. package/dist/server/app-page-probe.js +1 -1
  62. package/dist/server/app-page-render.d.ts +4 -1
  63. package/dist/server/app-page-render.js +8 -3
  64. package/dist/server/app-page-request.d.ts +8 -1
  65. package/dist/server/app-page-request.js +23 -11
  66. package/dist/server/app-page-route-wiring.d.ts +6 -1
  67. package/dist/server/app-page-route-wiring.js +30 -8
  68. package/dist/server/app-page-search-params-observation.d.ts +4 -2
  69. package/dist/server/app-page-search-params-observation.js +11 -7
  70. package/dist/server/app-page-stream.js +2 -1
  71. package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
  72. package/dist/server/app-route-handler-cache.js +1 -1
  73. package/dist/server/app-route-handler-dispatch.js +3 -2
  74. package/dist/server/app-route-handler-execution.js +5 -3
  75. package/dist/server/app-route-handler-policy.d.ts +1 -1
  76. package/dist/server/app-route-handler-policy.js +1 -6
  77. package/dist/server/app-route-module-loader.d.ts +2 -0
  78. package/dist/server/app-route-module-loader.js +1 -0
  79. package/dist/server/app-router-entry.js +7 -6
  80. package/dist/server/app-rsc-errors.d.ts +12 -1
  81. package/dist/server/app-rsc-errors.js +29 -3
  82. package/dist/server/app-rsc-handler.d.ts +15 -13
  83. package/dist/server/app-rsc-handler.js +28 -33
  84. package/dist/server/app-rsc-response-finalizer.js +5 -1
  85. package/dist/server/app-rsc-route-matching.d.ts +7 -0
  86. package/dist/server/app-rsc-route-matching.js +36 -3
  87. package/dist/server/app-segment-config.d.ts +1 -0
  88. package/dist/server/app-segment-config.js +32 -2
  89. package/dist/server/app-server-action-execution.d.ts +4 -0
  90. package/dist/server/app-server-action-execution.js +42 -11
  91. package/dist/server/app-ssr-entry.js +11 -6
  92. package/dist/server/app-static-generation.d.ts +1 -0
  93. package/dist/server/app-static-generation.js +1 -0
  94. package/dist/server/headers.d.ts +3 -1
  95. package/dist/server/headers.js +3 -1
  96. package/dist/server/metadata-route-response.d.ts +1 -1
  97. package/dist/server/prod-server.js +15 -6
  98. package/dist/server/worker-utils.d.ts +2 -1
  99. package/dist/server/worker-utils.js +7 -1
  100. package/dist/shims/dynamic.js +1 -1
  101. package/dist/shims/error-boundary.d.ts +19 -1
  102. package/dist/shims/error-boundary.js +11 -1
  103. package/dist/shims/headers.d.ts +3 -1
  104. package/dist/shims/headers.js +16 -5
  105. package/dist/shims/link.js +16 -12
  106. package/dist/shims/metadata.d.ts +3 -2
  107. package/dist/shims/metadata.js +8 -4
  108. package/dist/shims/router.js +13 -2
  109. package/dist/typegen.js +6 -5
  110. package/dist/utils/path.d.ts +2 -1
  111. package/dist/utils/path.js +1 -1
  112. package/dist/utils/project.d.ts +4 -0
  113. package/dist/utils/project.js +5 -1
  114. package/package.json +7 -3
@@ -2,9 +2,9 @@ import { AppRouteSemanticIds } from "../routing/app-route-graph.js";
2
2
  import { AppElements, AppElementsInterception } from "./app-elements-wire.js";
3
3
  import { AppPageParams } from "./app-page-boundary.js";
4
4
  import { ThenableParamsObserver } from "../shims/thenable-params.js";
5
+ import { Metadata, Viewport } from "../shims/metadata.js";
5
6
  import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
6
7
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
7
- import { Metadata, Viewport } from "../shims/metadata.js";
8
8
  import { AppPageRenderIdentity } from "./app-page-render-identity.js";
9
9
  import { resolveAppPageChildSegments } from "./app-page-segment-state.js";
10
10
  import { ComponentType, ReactNode } from "react";
@@ -31,6 +31,8 @@ type AppPageRouteWiringSlot<TModule extends AppPageModule = AppPageModule, TErro
31
31
  /** Graph-owned semantic slot identity. */id?: string | null; /** Slot prop name passed to the owning layout (e.g. "modal" from @modal). */
32
32
  name: string;
33
33
  default?: TModule | null;
34
+ configLayouts?: readonly (TModule | null | undefined)[] | null;
35
+ configLayoutTreePositions?: readonly number[] | null;
34
36
  error?: TErrorModule | null;
35
37
  layout?: TModule | null;
36
38
  layoutIndex: number;
@@ -83,6 +85,8 @@ type AppPageRouteWiringRoute<TModule extends AppPageModule = AppPageModule, TErr
83
85
  templates?: readonly (TModule | null | undefined)[] | null;
84
86
  };
85
87
  type AppPageSlotOverride<TModule extends AppPageModule = AppPageModule> = {
88
+ branchSegments?: readonly string[] | null;
89
+ layoutSegments?: readonly (readonly string[])[] | null;
86
90
  layoutModules?: readonly (TModule | null | undefined)[] | null;
87
91
  /**
88
92
  * The page module to render for this slot. Optional — when omitted, the
@@ -118,6 +122,7 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
118
122
  rootNotFoundModule?: TModule | null;
119
123
  rootUnauthorizedModule?: TModule | null;
120
124
  route: AppPageRouteWiringRoute<TModule, TErrorModule>;
125
+ createPageElement?: (component: AppPageComponent, props: Readonly<Record<string, unknown>>) => ReactNode;
121
126
  searchParams?: unknown;
122
127
  slotOverrides?: Readonly<Record<string, AppPageSlotOverride<TModule>>> | null;
123
128
  };
@@ -8,7 +8,7 @@ import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
8
8
  import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
9
9
  import { MetadataHead, ViewportHead, renderMetadataToHtml } from "../shims/metadata.js";
10
10
  import { Children as Children$1, ParallelSlot, Slot } from "../shims/slot.js";
11
- import { resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams } from "./app-page-params.js";
11
+ import { resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams } from "./app-page-params.js";
12
12
  import { probeReactServerSubtree } from "./app-page-probe.js";
13
13
  import { resolveAppPageChildSegments, resolveAppPageRouteStateKey, resolveAppPageSegmentStateKey } from "./app-page-segment-state.js";
14
14
  import { Fragment, Suspense } from "react";
@@ -16,6 +16,9 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
16
  //#region src/server/app-page-route-wiring.tsx
17
17
  const APP_PAGE_LAYOUT_PROBE_CHILD = /* @__PURE__ */ jsx(Fragment, {});
18
18
  const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
19
+ function resolveSlotLayoutParams(routeSegments, treePosition, params) {
20
+ return resolveAppPageBranchParams(routeSegments, treePosition, params);
21
+ }
19
22
  function getDefaultExport(module) {
20
23
  return module?.default ?? null;
21
24
  }
@@ -293,7 +296,9 @@ function buildAppPageElements(options) {
293
296
  const slotId = resolveAppPageSlotId(slot, layoutEntries[targetIndex]?.treePath ?? "/");
294
297
  const slotOverride = resolveSlotOverride(slotKey, slotName);
295
298
  const slotParams = getEffectiveSlotParams(slotKey, slotName);
296
- const slotResetKey = resolveAppPageRouteStateKey(slot.routeSegments ?? [], slotParams);
299
+ const slotRouteSegments = slot.routeSegments ?? [];
300
+ const slotOwnerParams = resolveAppPageSegmentParams(options.route.routeSegments, layoutEntries[targetIndex]?.treePosition ?? 0, options.matchedParams);
301
+ const slotResetKey = resolveAppPageRouteStateKey(slotRouteSegments, slotParams);
297
302
  const overrideOrPageComponent = getDefaultExport(slotOverride?.pageModule) ?? getDefaultExport(slot.page);
298
303
  const defaultComponent = getDefaultExport(slot.default);
299
304
  if (!overrideOrPageComponent && defaultComponent && options.isRscRequest && options.mountedSlotIds?.has(slotId)) continue;
@@ -302,23 +307,40 @@ function buildAppPageElements(options) {
302
307
  elements[slotId] = AppElementsWire.unmatchedSlotValue;
303
308
  continue;
304
309
  }
305
- const slotThenableParams = options.makeThenableParams(slotParams);
306
- const slotProps = { params: slotThenableParams };
310
+ const slotProps = { params: options.makeThenableParams(slotParams) };
307
311
  if (options.searchParams !== void 0) slotProps.searchParams = options.searchParams;
308
312
  if (slotOverride?.props) Object.assign(slotProps, slotOverride.props);
309
- let slotElement = /* @__PURE__ */ jsx(slotComponent, { ...slotProps });
313
+ let slotElement = options.createPageElement ? options.createPageElement(slotComponent, slotProps) : (() => {
314
+ return /* @__PURE__ */ jsx(slotComponent, { ...slotProps });
315
+ })();
316
+ const hasSlotTreeOverride = slotOverride?.pageModule != null || slotOverride?.layoutModules !== void 0;
310
317
  const interceptLayouts = slotOverride?.layoutModules ?? [];
311
318
  for (let layoutIndex = interceptLayouts.length - 1; layoutIndex >= 0; layoutIndex--) {
312
319
  const interceptLayoutComponent = getDefaultExport(interceptLayouts[layoutIndex]);
313
320
  if (!interceptLayoutComponent) continue;
314
- slotElement = /* @__PURE__ */ jsx(interceptLayoutComponent, {
315
- params: slotThenableParams,
321
+ const InterceptLayoutComponent = interceptLayoutComponent;
322
+ const interceptLayoutParams = resolveSlotLayoutParams(slotOverride?.branchSegments ?? slotRouteSegments, slotOverride?.layoutSegments?.[layoutIndex]?.length ?? slotRouteSegments.length, slotParams);
323
+ slotElement = /* @__PURE__ */ jsx(InterceptLayoutComponent, {
324
+ params: options.makeThenableParams(interceptLayoutParams),
325
+ children: slotElement
326
+ });
327
+ }
328
+ if (!hasSlotTreeOverride) for (let layoutIndex = (slot.configLayouts?.length ?? 0) - 1; layoutIndex >= 0; layoutIndex--) {
329
+ const nestedLayoutComponent = getDefaultExport(slot.configLayouts?.[layoutIndex]);
330
+ if (!nestedLayoutComponent) continue;
331
+ const NestedLayoutComponent = nestedLayoutComponent;
332
+ const nestedLayoutParams = resolveSlotLayoutParams(slotRouteSegments, slot.configLayoutTreePositions?.[layoutIndex] ?? 0, slotParams);
333
+ slotElement = /* @__PURE__ */ jsx(NestedLayoutComponent, {
334
+ params: options.makeThenableParams({
335
+ ...slotOwnerParams,
336
+ ...nestedLayoutParams
337
+ }),
316
338
  children: slotElement
317
339
  });
318
340
  }
319
341
  const slotLayoutComponent = getDefaultExport(slot.layout);
320
342
  if (slotLayoutComponent) slotElement = /* @__PURE__ */ jsx(slotLayoutComponent, {
321
- params: slotThenableParams,
343
+ params: options.makeThenableParams(slotOwnerParams),
322
344
  children: slotElement
323
345
  });
324
346
  const slotLoadingComponent = getDefaultExport(slot.loading);
@@ -1,10 +1,12 @@
1
- import { ThenableParams } from "../shims/thenable-params.js";
1
+ import { ThenableParams, ThenableParamsObserver } from "../shims/thenable-params.js";
2
2
  import { AppPageSearchParams } from "./app-page-head.js";
3
3
 
4
4
  //#region src/server/app-page-search-params-observation.d.ts
5
5
  type AppPageSearchParamsObservationOptions = {
6
+ markDynamic?: boolean;
6
7
  observeReactPromiseStatus?: boolean;
7
8
  };
9
+ declare function createAppPageSearchParamsObserver(options?: AppPageSearchParamsObservationOptions): ThenableParamsObserver;
8
10
  declare function makeObservedAppPageSearchParamsThenable(pageSearchParams: AppPageSearchParams, options?: AppPageSearchParamsObservationOptions): ThenableParams<AppPageSearchParams>;
9
11
  //#endregion
10
- export { makeObservedAppPageSearchParamsThenable };
12
+ export { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable };
@@ -1,15 +1,19 @@
1
- import { markDynamicUsage, markRenderRequestApiUsage, throwIfInsideCacheScope } from "../shims/headers.js";
1
+ import { markDynamicUsage, markRenderRequestApiUsage, throwIfInsideCacheScope, throwIfStaticGenerationAccessError } from "../shims/headers.js";
2
2
  import { makeThenableParams } from "../shims/thenable-params.js";
3
3
  //#region src/server/app-page-search-params-observation.ts
4
- function markAppPageSearchParamsAccess() {
4
+ function markAppPageSearchParamsAccess(markDynamic) {
5
+ throwIfStaticGenerationAccessError();
5
6
  throwIfInsideCacheScope("searchParams");
6
- markDynamicUsage();
7
+ if (markDynamic) markDynamicUsage();
7
8
  markRenderRequestApiUsage("searchParams");
8
9
  }
9
- function makeObservedAppPageSearchParamsThenable(pageSearchParams, options = {}) {
10
- const observer = { observeParamAccess() {
11
- markAppPageSearchParamsAccess();
10
+ function createAppPageSearchParamsObserver(options = {}) {
11
+ return { observeParamAccess() {
12
+ markAppPageSearchParamsAccess(options.markDynamic !== false);
12
13
  } };
14
+ }
15
+ function makeObservedAppPageSearchParamsThenable(pageSearchParams, options = {}) {
16
+ const observer = createAppPageSearchParamsObserver(options);
13
17
  if (options.observeReactPromiseStatus === true) return makeThenableParams(pageSearchParams, {
14
18
  ...observer,
15
19
  observeReactPromiseStatus: true
@@ -17,4 +21,4 @@ function makeObservedAppPageSearchParamsThenable(pageSearchParams, options = {})
17
21
  return makeThenableParams(pageSearchParams, observer);
18
22
  }
19
23
  //#endregion
20
- export { makeObservedAppPageSearchParamsThenable };
24
+ export { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable };
@@ -1,3 +1,4 @@
1
+ import { isNavigationSignalError } from "../utils/navigation-signal.js";
1
2
  import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-cache-busting.js";
2
3
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
3
4
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
@@ -131,7 +132,7 @@ function createAppPageRscErrorTracker(baseOnError) {
131
132
  return capturedSpecialError;
132
133
  },
133
134
  onRenderError(error, requestInfo, errorContext) {
134
- if (error && typeof error === "object" && "digest" in error) {
135
+ if (isNavigationSignalError(error)) {
135
136
  if (capturedSpecialError === null) capturedSpecialError = error;
136
137
  } else capturedError = error;
137
138
  return baseOnError(error, requestInfo, errorContext);
@@ -4,7 +4,7 @@ import { ReactNode } from "react";
4
4
  //#region src/server/app-ppr-fallback-shell-render.d.ts
5
5
  type AppPageBoundaryOnError = (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;
6
6
  type AppPageRenderableElement = ReactNode | Record<string, ReactNode>;
7
- declare function warmPprFallbackShellCaches(options: {
7
+ type WarmPprFallbackShellCachesOptions = {
8
8
  element: AppPageRenderableElement;
9
9
  onError: AppPageBoundaryOnError;
10
10
  renderToReadableStream: (element: AppPageRenderableElement, options: {
@@ -12,6 +12,7 @@ declare function warmPprFallbackShellCaches(options: {
12
12
  signal?: AbortSignal;
13
13
  }) => ReadableStream<Uint8Array>;
14
14
  state: PprFallbackShellState;
15
- }): Promise<void>;
15
+ };
16
+ declare function warmPprFallbackShellCaches(options: WarmPprFallbackShellCachesOptions): Promise<void>;
16
17
  //#endregion
17
- export { warmPprFallbackShellCaches };
18
+ export { WarmPprFallbackShellCachesOptions, warmPprFallbackShellCaches };
@@ -1,6 +1,6 @@
1
1
  import { makeThenableParams } from "../shims/thenable-params.js";
2
- import { markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
3
2
  import { applyRouteHandlerMiddlewareContext, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, buildRouteHandlerCachedResponse } from "./app-route-handler-response.js";
3
+ import { markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
4
4
  import { runAppRouteHandler } from "./app-route-handler-execution.js";
5
5
  //#region src/server/app-route-handler-cache.ts
6
6
  const EMPTY_PARAMS = Object.freeze({});
@@ -7,10 +7,10 @@ import { setNavigationContext } from "../shims/navigation-context-state.js";
7
7
  import { makeThenableParams } from "../shims/thenable-params.js";
8
8
  import "../shims/navigation.js";
9
9
  import { buildPageCacheTags } from "./implicit-tags.js";
10
- import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
11
- import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
12
10
  import { applyRouteHandlerMiddlewareContext } from "./app-route-handler-response.js";
11
+ import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
13
12
  import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
13
+ import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
14
14
  import { executeAppRouteHandler } from "./app-route-handler-execution.js";
15
15
  import { readAppRouteHandlerCacheResponse } from "./app-route-handler-cache.js";
16
16
  import { resolveAppRouteHandlerFetchCacheMode } from "./app-segment-config.js";
@@ -24,6 +24,7 @@ function buildRouteHandlerPageCacheTags(pathname, extraTags, routeSegments) {
24
24
  async function runInRouteHandlerRevalidationContext(options, renderFn) {
25
25
  await runWithRequestContext(createRequestContext({
26
26
  headersContext: createStaticGenerationHeadersContext({
27
+ draftModeEnabled: false,
27
28
  draftModeSecret: options.draftModeSecret,
28
29
  dynamicConfig: options.dynamicConfig,
29
30
  routeKind: "route",
@@ -1,12 +1,14 @@
1
- import { setHeadersContext } from "../shims/headers.js";
2
- import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
3
- import { isPossibleAppRouteActionRequest, resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
1
+ import { isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
2
+ import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
4
3
  import { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss } from "./app-route-handler-response.js";
4
+ import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
5
5
  import { createStaticGenerationHeadersContext, getAppRouteStaticGenerationErrorMessage } from "./app-static-generation.js";
6
+ import { resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
6
7
  //#region src/server/app-route-handler-execution.ts
7
8
  function configureAppRouteStaticGenerationContext(options) {
8
9
  if (options.dynamicConfig === "force-static" || options.dynamicConfig === "error") {
9
10
  setHeadersContext(createStaticGenerationHeadersContext({
11
+ draftModeEnabled: options.draftModeSecret !== void 0 && isDraftModeRequest(options.request, options.draftModeSecret),
10
12
  draftModeSecret: options.draftModeSecret,
11
13
  dynamicConfig: options.dynamicConfig,
12
14
  routeKind: "route",
@@ -1,3 +1,4 @@
1
+ import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
1
2
  import { RouteHandlerHttpMethod, RouteHandlerModule } from "./app-route-handler-runtime.js";
2
3
 
3
4
  //#region src/server/app-route-handler-policy.d.ts
@@ -43,7 +44,6 @@ type AppRouteHandlerSpecialError = {
43
44
  type AppRouteHandlerSpecialErrorOptions = {
44
45
  isAction: boolean;
45
46
  };
46
- declare function isPossibleAppRouteActionRequest(request: Pick<Request, "headers" | "method">): boolean;
47
47
  declare function getAppRouteHandlerRevalidateSeconds(handler: Pick<AppRouteHandlerModule, "revalidate">): number | null;
48
48
  declare function hasAppRouteHandlerDefaultExport(handler: RouteHandlerModule): boolean;
49
49
  declare function resolveAppRouteHandlerMethod(handler: AppRouteHandlerModule, method: string): ResolvedAppRouteHandlerMethod;
@@ -1,12 +1,7 @@
1
- import "./headers.js";
2
1
  import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
2
+ import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
3
3
  import { buildRouteHandlerAllowHeader, collectRouteHandlerMethods } from "./app-route-handler-runtime.js";
4
4
  //#region src/server/app-route-handler-policy.ts
5
- function isPossibleAppRouteActionRequest(request) {
6
- if (request.method.toUpperCase() !== "POST") return false;
7
- const contentType = request.headers.get("content-type");
8
- return request.headers.has("x-rsc-action") || request.headers.has("next-action") || contentType === "application/x-www-form-urlencoded" || contentType?.startsWith("multipart/form-data") === true;
9
- }
10
5
  function getAppRouteHandlerRevalidateSeconds(handler) {
11
6
  const { revalidate } = handler;
12
7
  if (revalidate === false) return Infinity;
@@ -36,11 +36,13 @@ type LazyLoadableSlot = {
36
36
  page?: unknown;
37
37
  default?: unknown;
38
38
  layout?: unknown;
39
+ configLayouts?: readonly unknown[];
39
40
  loading?: unknown;
40
41
  error?: unknown;
41
42
  __loadPage?: LazyModuleThunk | null;
42
43
  __loadDefault?: LazyModuleThunk | null;
43
44
  __loadLayout?: LazyModuleThunk | null;
45
+ __loadConfigLayouts?: LazyModuleLoaderArray | null;
44
46
  __loadLoading?: LazyModuleThunk | null;
45
47
  __loadError?: LazyModuleThunk | null; /** Hydrated only after an intercept matches, not with the slot's base modules. */
46
48
  intercepts?: LazyLoadableIntercept[];
@@ -61,6 +61,7 @@ function ensureAppRouteModulesLoaded(route) {
61
61
  pushFieldLoad(loads, slot, "page", slot.__loadPage);
62
62
  pushFieldLoad(loads, slot, "default", slot.__loadDefault);
63
63
  pushFieldLoad(loads, slot, "layout", slot.__loadLayout);
64
+ pushArrayLoads(loads, slot.configLayouts, slot.__loadConfigLayouts);
64
65
  pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
65
66
  pushFieldLoad(loads, slot, "error", slot.__loadError);
66
67
  }
@@ -5,7 +5,7 @@ import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } fro
5
5
  import { isOpenRedirectShaped } from "./open-redirect.js";
6
6
  import { cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
7
7
  import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
8
- import { resolveStaticAssetSignal } from "./worker-utils.js";
8
+ import { finalizeMissingStaticAssetResponse, resolveStaticAssetSignal } from "./worker-utils.js";
9
9
  import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
10
10
  import rscHandler, { __assetPrefix, __basePath } from "virtual:vinext-rsc-entry";
11
11
  import { registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
@@ -24,7 +24,7 @@ async function handleRequest(request, env, ctx) {
24
24
  } catch {
25
25
  return badRequestResponse();
26
26
  }
27
- if (isNextStaticPath(url.pathname, __workerBasePath, __workerAssetPathPrefix)) return notFoundStaticAssetResponse();
27
+ const missingBuildAsset = isNextStaticPath(url.pathname, __workerBasePath, __workerAssetPathPrefix);
28
28
  {
29
29
  const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);
30
30
  const filteredHeaders = filterInternalHeaders(request.headers);
@@ -35,14 +35,15 @@ async function handleRequest(request, env, ctx) {
35
35
  const handleFn = () => rscHandler(request, ctx);
36
36
  const result = await (ctx ? runWithExecutionContext(ctx, handleFn) : handleFn());
37
37
  if (result instanceof Response) {
38
+ let response = result;
38
39
  if (env?.ASSETS) {
39
40
  const assetFetcher = env.ASSETS;
40
- const assetResponse = await resolveStaticAssetSignal(result, { fetchAsset: (path) => Promise.resolve(assetFetcher.fetch(new Request(new URL(path, request.url)))) });
41
- if (assetResponse) return assetResponse;
41
+ const assetResponse = await resolveStaticAssetSignal(response, { fetchAsset: (path) => Promise.resolve(assetFetcher.fetch(new Request(new URL(path, request.url)))) });
42
+ if (assetResponse) response = assetResponse;
42
43
  }
43
- return result;
44
+ return finalizeMissingStaticAssetResponse(response, missingBuildAsset);
44
45
  }
45
- if (result === null || result === void 0) return notFoundResponse();
46
+ if (result === null || result === void 0) return missingBuildAsset ? notFoundStaticAssetResponse() : notFoundResponse();
46
47
  return new Response(String(result), { status: 200 });
47
48
  }
48
49
  //#endregion
@@ -19,6 +19,17 @@ type CreateRscOnErrorHandlerOptions = {
19
19
  declare function hasDigest(error: unknown): error is {
20
20
  digest: unknown;
21
21
  };
22
+ /**
23
+ * vinext's mirror of Next.js's `getDigestForWellKnownError`: returns the digest
24
+ * string only when the error is a genuine control-flow signal — a redirect,
25
+ * notFound/HTTP-access fallback, bail-out-to-client-side-rendering, or
26
+ * dynamic-server-usage throw. Any other digest (e.g. a hashed digest stamped on
27
+ * a real error, or an obfuscated digest transported from a nested boundary)
28
+ * returns undefined so the caller still reports it as a real error. Mere
29
+ * presence of a `digest` field is NOT enough — that conflation swallowed a class
30
+ * of server render errors with no instrumentation/telemetry.
31
+ */
32
+ declare function getDigestForWellKnownError(error: unknown): string | undefined;
22
33
  /**
23
34
  * djb2 hash matching Next.js's string-hash package for RSC error digests.
24
35
  */
@@ -26,4 +37,4 @@ declare function errorDigest(input: string): string;
26
37
  declare function sanitizeErrorForClient(error: unknown, nodeEnv?: string | undefined): unknown;
27
38
  declare function createRscOnErrorHandler(options: CreateRscOnErrorHandlerOptions): (error: unknown) => string | undefined;
28
39
  //#endregion
29
- export { createRscOnErrorHandler, errorDigest, hasDigest, sanitizeErrorForClient };
40
+ export { createRscOnErrorHandler, errorDigest, getDigestForWellKnownError, hasDigest, sanitizeErrorForClient };
@@ -1,8 +1,26 @@
1
+ import { isNavigationSignalError } from "../utils/navigation-signal.js";
1
2
  import { resolveAppPageSpecialError } from "./app-page-execution.js";
2
3
  //#region src/server/app-rsc-errors.ts
3
4
  function hasDigest(error) {
4
5
  return Boolean(error && typeof error === "object" && "digest" in error);
5
6
  }
7
+ const BAILOUT_TO_CSR_DIGEST = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
8
+ const DYNAMIC_SERVER_USAGE_DIGEST = "DYNAMIC_SERVER_USAGE";
9
+ /**
10
+ * vinext's mirror of Next.js's `getDigestForWellKnownError`: returns the digest
11
+ * string only when the error is a genuine control-flow signal — a redirect,
12
+ * notFound/HTTP-access fallback, bail-out-to-client-side-rendering, or
13
+ * dynamic-server-usage throw. Any other digest (e.g. a hashed digest stamped on
14
+ * a real error, or an obfuscated digest transported from a nested boundary)
15
+ * returns undefined so the caller still reports it as a real error. Mere
16
+ * presence of a `digest` field is NOT enough — that conflation swallowed a class
17
+ * of server render errors with no instrumentation/telemetry.
18
+ */
19
+ function getDigestForWellKnownError(error) {
20
+ if (!hasDigest(error)) return;
21
+ const digest = String(error.digest);
22
+ if (isNavigationSignalError(error) || digest === BAILOUT_TO_CSR_DIGEST || digest === DYNAMIC_SERVER_USAGE_DIGEST) return digest;
23
+ }
6
24
  function getThrownValueMessage(error) {
7
25
  return error instanceof Error ? error.message : String(error);
8
26
  }
@@ -27,14 +45,22 @@ function sanitizeErrorForClient(error, nodeEnv = process.env.NODE_ENV) {
27
45
  function createRscOnErrorHandler(options) {
28
46
  return (error) => {
29
47
  const nodeEnv = options.nodeEnv ?? process.env.NODE_ENV;
30
- if (hasDigest(error)) return String(error.digest);
48
+ const wellKnownDigest = getDigestForWellKnownError(error);
49
+ if (wellKnownDigest !== void 0) return wellKnownDigest;
31
50
  if (nodeEnv !== "production" && error instanceof Error && error.message.includes("Only plain objects, and a few built-ins, can be passed to Client Components")) {
32
51
  console.error("[vinext] RSC serialization error: a non-plain object was passed from a Server Component to a Client Component.\n\nCommon causes:\n * Passing a module namespace (import * as X) directly as a prop.\n Unlike Next.js (webpack), Vite produces real ESM module namespace objects\n which are not serializable. Fix: pass individual values instead,\n e.g. <Comp value={module.value} />\n * Passing a class instance (new Foo()) as a prop.\n Fix: convert to a plain object, e.g. { id: foo.id, name: foo.name }\n * Passing a Date, Map, or Set. Use .toISOString(), [...map.entries()], etc.\n * Passing Object.create(null). Use { ...obj } to restore a prototype.\n\nOriginal error:", error.message);
33
52
  return;
34
53
  }
35
54
  if (options.requestInfo && options.errorContext && error) options.reportRequestError(error instanceof Error ? error : new Error(getThrownValueMessage(error)), options.requestInfo, options.errorContext);
36
- if (nodeEnv === "production" && error) return errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
55
+ if (hasDigest(error)) return String(error.digest);
56
+ if (error) {
57
+ const digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
58
+ if (error instanceof Error) try {
59
+ Object.assign(error, { digest });
60
+ } catch {}
61
+ return digest;
62
+ }
37
63
  };
38
64
  }
39
65
  //#endregion
40
- export { createRscOnErrorHandler, errorDigest, hasDigest, sanitizeErrorForClient };
66
+ export { createRscOnErrorHandler, errorDigest, getDigestForWellKnownError, hasDigest, sanitizeErrorForClient };
@@ -2,21 +2,26 @@ import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config
2
2
  import { ImageConfig } from "./image-optimization.js";
3
3
  import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
4
4
  import { RootParams } from "../shims/root-params.js";
5
- import { MiddlewareModule } from "./middleware-runtime.js";
6
- import { AppMiddlewareContext } from "./app-middleware.js";
5
+ import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware.js";
7
6
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
7
+ import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
8
8
  import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
9
- import { MetadataRouteMakeThenableParams, MetadataRuntimeRoute } from "./metadata-route-response.js";
10
9
  import { ReactFormState } from "react-dom/client";
11
10
 
12
11
  //#region src/server/app-rsc-handler.d.ts
13
12
  type AppPageParams = Record<string, string | string[]>;
14
- type MetadataRoutes = readonly MetadataRuntimeRoute[];
15
- type MakeThenableParams = MetadataRouteMakeThenableParams;
16
13
  type StaticParamsMap = AppPrerenderStaticParamsMap;
17
14
  type RootParamNamesMap = AppPrerenderRootParamNamesMap;
18
15
  type AppRscMiddlewareContext = AppMiddlewareContext;
16
+ type RunAppMiddlewareOptions = {
17
+ cleanPathname: string;
18
+ context: AppRscMiddlewareContext;
19
+ isDataRequest: boolean;
20
+ request: Request;
21
+ };
19
22
  type AppRscHandlerRoute = {
23
+ __loadPage?: unknown;
24
+ __loadRouteHandler?: unknown;
20
25
  isDynamic: boolean;
21
26
  params?: readonly string[];
22
27
  page?: unknown;
@@ -147,7 +152,6 @@ type NavigationContextValue = {
147
152
  type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
148
153
  basePath: string;
149
154
  buildId: string | null;
150
- cacheComponents?: boolean;
151
155
  clearRequestContext: () => void;
152
156
  configHeaders: NextHeader[];
153
157
  configRedirects: NextRedirect[];
@@ -173,18 +177,16 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
173
177
  * Node server and dev included, not just the Cloudflare worker entry.
174
178
  */
175
179
  registerCacheAdapters: (env?: Record<string, unknown>) => void;
176
- handleProgressiveActionRequest: (options: HandleProgressiveActionRequestOptions) => Promise<Response | ProgressiveActionFormStateResult | null>;
177
- handleServerActionRequest: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
180
+ handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions) => Promise<Response | ProgressiveActionFormStateResult | null>;
181
+ handleMetadataRouteRequest?: (cleanPathname: string) => Promise<Response | null>;
182
+ createPprFallbackShells?: (route: Pick<AppRscHandlerRoute, "params" | "pattern" | "rootParamNames">, params: AppPageParams) => AppPagePprFallbackCacheShell[];
183
+ handleServerActionRequest?: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
178
184
  i18nConfig: NextI18nConfig | null;
179
185
  imageConfig?: ImageConfig;
180
186
  isDev: boolean;
181
- isMiddlewareProxy: boolean;
182
187
  loadPrerenderPagesRoutes?: () => Promise<unknown>;
183
- makeThenableParams: MakeThenableParams;
184
188
  matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
185
- metadataRoutes: MetadataRoutes;
186
- middlewareFilePath: string | null;
187
- middlewareModule: MiddlewareModule | null;
189
+ runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
188
190
  publicFiles: ReadonlySet<string>;
189
191
  renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;
190
192
  renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;
@@ -19,6 +19,7 @@ import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, seri
19
19
  import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
20
20
  import { pickRootParams, setRootParams } from "../shims/root-params.js";
21
21
  import { flattenErrorCauses } from "../utils/error-cause.js";
22
+ import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
22
23
  import { buildPageCacheTags } from "./implicit-tags.js";
23
24
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
24
25
  import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
@@ -47,6 +48,11 @@ function isExecutionContextLike(value) {
47
48
  if (!value || typeof value !== "object") return false;
48
49
  return hasProperty(value, "waitUntil") && typeof value.waitUntil === "function";
49
50
  }
51
+ function createMissingServerActionResponse(options, actionId) {
52
+ console.warn(getServerActionNotFoundMessage(actionId));
53
+ options.clearRequestContext();
54
+ return createServerActionNotFoundResponse();
55
+ }
50
56
  function redirectDestinationWithBasePath(destination, basePath) {
51
57
  if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) return destination;
52
58
  return basePath + destination;
@@ -165,19 +171,12 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
165
171
  status: null
166
172
  };
167
173
  let didMiddlewareRewrite = false;
168
- if (options.middlewareModule) {
169
- const { applyAppMiddleware } = await import("./app-middleware.js");
170
- const middlewareResult = await applyAppMiddleware({
171
- basePath: options.basePath,
174
+ if (options.runMiddleware) {
175
+ const middlewareResult = await options.runMiddleware({
172
176
  cleanPathname,
173
177
  context: middlewareContext,
174
- filePath: options.middlewareFilePath ?? void 0,
175
- i18nConfig: options.i18nConfig,
176
178
  isDataRequest,
177
- isProxy: options.isMiddlewareProxy,
178
- module: options.middlewareModule,
179
- request: userlandRequest,
180
- trailingSlash: options.trailingSlash
179
+ request: userlandRequest
181
180
  });
182
181
  if (middlewareResult.kind === "response") return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {
183
182
  basePathState,
@@ -211,13 +210,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
211
210
  if (!imageRedirect) return new Response("Invalid image optimization parameters", { status: 400 });
212
211
  return Response.redirect(new URL(imageRedirect, url.origin).href, 302);
213
212
  }
214
- if (options.metadataRoutes.length > 0) {
215
- const { handleMetadataRouteRequest } = await import("./metadata-route-response.js");
216
- const metadataRouteResponse = await handleMetadataRouteRequest({
217
- metadataRoutes: options.metadataRoutes,
218
- cleanPathname,
219
- makeThenableParams: options.makeThenableParams
220
- });
213
+ if (options.handleMetadataRouteRequest) {
214
+ const metadataRouteResponse = await options.handleMetadataRouteRequest(cleanPathname);
221
215
  if (metadataRouteResponse) {
222
216
  applyConfigHeadersToResponse(metadataRouteResponse.headers, {
223
217
  basePathState,
@@ -255,13 +249,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
255
249
  const contentType = request.headers.get("content-type") || "";
256
250
  const isPostRequest = request.method.toUpperCase() === "POST";
257
251
  let progressiveActionResult = null;
258
- if (isPostRequest && contentType.startsWith("multipart/form-data") && !actionId) progressiveActionResult = await options.handleProgressiveActionRequest({
259
- actionId,
260
- cleanPathname,
261
- contentType,
262
- middlewareContext,
263
- request
264
- });
252
+ if (isPostRequest && contentType.startsWith("multipart/form-data") && !actionId) {
253
+ if (options.handleProgressiveActionRequest) progressiveActionResult = await options.handleProgressiveActionRequest({
254
+ actionId,
255
+ cleanPathname,
256
+ contentType,
257
+ middlewareContext,
258
+ request
259
+ });
260
+ else if (preActionMatch?.route.__loadPage && !preActionMatch.route.__loadRouteHandler) return createMissingServerActionResponse(options, null);
261
+ }
265
262
  if (progressiveActionResult instanceof Response) return progressiveActionResult;
266
263
  const progressiveActionFormState = progressiveActionResult?.kind === "form-state" ? progressiveActionResult : null;
267
264
  const isProgressiveActionRender = progressiveActionFormState !== null;
@@ -269,7 +266,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
269
266
  const failedProgressiveActionResult = progressiveActionFormState && "actionError" in progressiveActionFormState ? progressiveActionFormState : null;
270
267
  const actionFailed = failedProgressiveActionResult !== null;
271
268
  const actionError = failedProgressiveActionResult?.actionError;
272
- const serverActionResponse = isPostRequest && actionId ? await options.handleServerActionRequest({
269
+ const serverActionResponse = isPostRequest && actionId && options.handleServerActionRequest ? await options.handleServerActionRequest({
273
270
  actionId,
274
271
  cleanPathname,
275
272
  contentType,
@@ -281,6 +278,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
281
278
  searchParams: getResolvedSearchParams()
282
279
  }) : null;
283
280
  if (serverActionResponse) return serverActionResponse;
281
+ if (isPostRequest && actionId && !options.handleServerActionRequest) return createMissingServerActionResponse(options, actionId);
284
282
  let match = preActionMatch;
285
283
  const renderPagesForMatchKind = async (matchKind) => {
286
284
  const response = match === null || match.route.isDynamic ? await options.renderPagesFallback?.({
@@ -394,14 +392,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
394
392
  const renderParams = prerenderRouteParams ?? params;
395
393
  const resolvedSearchParams = getResolvedSearchParams();
396
394
  let runtimeFallbackShells = [];
397
- if (options.cacheComponents === true && request.method === "GET" && !isRscRequest && !isPrerenderFallbackShell && route.params) {
398
- const { createAppPprFallbackShells } = await import("./app-ppr-fallback-shell.js");
399
- runtimeFallbackShells = createAppPprFallbackShells({
400
- params: route.params,
401
- pattern: route.pattern,
402
- rootParamNames: route.rootParamNames
403
- }, params);
404
- }
395
+ if (options.createPprFallbackShells && request.method === "GET" && !isRscRequest && !isPrerenderFallbackShell && route.params) runtimeFallbackShells = options.createPprFallbackShells({
396
+ params: route.params,
397
+ pattern: route.pattern,
398
+ rootParamNames: route.rootParamNames
399
+ }, params);
405
400
  options.setNavigationContext({
406
401
  pathname: canonicalPathname,
407
402
  searchParams: resolvedSearchParams,
@@ -22,7 +22,11 @@ import { mergeVaryHeader } from "./middleware-response-headers.js";
22
22
  */
23
23
  function finalizeAppRscResponse(response, request, options) {
24
24
  if (response.status >= 300 && response.status < 400) return response;
25
- if (!response.headers.has("x-vinext-static-file")) mergeVaryHeader(response.headers, VINEXT_RSC_VARY_HEADER);
25
+ if (!response.headers.has("x-vinext-static-file")) {
26
+ const varyHeader = response.headers.get("Vary");
27
+ if (varyHeader === null) response.headers.set("Vary", VINEXT_RSC_VARY_HEADER);
28
+ else if (varyHeader !== VINEXT_RSC_VARY_HEADER) mergeVaryHeader(response.headers, VINEXT_RSC_VARY_HEADER);
29
+ }
26
30
  if (!response.headers.has("Cache-Control")) applyCdnResponseHeaders(response.headers, { cacheControl: "" });
27
31
  if (!options.configHeaders.length) return response;
28
32
  const url = new URL(request.url);