vinext 1.0.0-beta.3 → 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.
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender.d.ts +2 -1
- package/dist/build/prerender.js +12 -2
- package/dist/cli-args.d.ts +2 -1
- package/dist/cli-args.js +10 -0
- package/dist/cli.js +14 -8
- package/dist/client/navigation-runtime.d.ts +6 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/dotenv.d.ts +3 -4
- package/dist/config/dotenv.js +30 -22
- package/dist/config/next-config.d.ts +4 -2
- package/dist/config/next-config.js +3 -0
- package/dist/entries/app-browser-entry.js +1 -1
- package/dist/entries/app-rsc-entry.js +18 -3
- package/dist/entries/pages-server-entry.js +4 -1
- package/dist/index.js +11 -7
- package/dist/plugins/client-reference-dedup.js +7 -5
- package/dist/plugins/sass.js +3 -4
- package/dist/server/api-handler.js +4 -3
- package/dist/server/app-bfcache-identity.js +28 -2
- package/dist/server/app-browser-entry.js +73 -45
- package/dist/server/app-browser-navigation-controller.d.ts +1 -1
- package/dist/server/app-browser-navigation-controller.js +29 -4
- package/dist/server/app-browser-prefetch-response.d.ts +9 -0
- package/dist/server/app-browser-prefetch-response.js +32 -0
- package/dist/server/app-browser-state.d.ts +8 -3
- package/dist/server/app-browser-state.js +9 -3
- package/dist/server/app-page-dispatch.d.ts +1 -1
- package/dist/server/app-page-dispatch.js +6 -2
- package/dist/server/app-page-element-builder.d.ts +2 -1
- package/dist/server/app-page-element-builder.js +1 -0
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +13 -3
- package/dist/server/app-page-request.d.ts +0 -1
- package/dist/server/app-page-request.js +3 -12
- package/dist/server/app-page-response.d.ts +2 -0
- package/dist/server/app-page-response.js +6 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -2
- package/dist/server/app-page-route-wiring.js +61 -13
- package/dist/server/app-pages-bridge.d.ts +2 -1
- package/dist/server/app-pages-bridge.js +2 -1
- package/dist/server/app-rsc-cache-busting.d.ts +7 -0
- package/dist/server/app-rsc-cache-busting.js +6 -0
- package/dist/server/app-rsc-handler.d.ts +2 -0
- package/dist/server/app-rsc-handler.js +9 -4
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.js +65 -4
- package/dist/server/app-server-action-execution.d.ts +1 -1
- package/dist/server/app-visited-response-cache.d.ts +6 -1
- package/dist/server/app-visited-response-cache.js +49 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +61 -38
- package/dist/server/edge-api-runtime.d.ts +10 -1
- package/dist/server/edge-api-runtime.js +29 -1
- package/dist/server/headers.d.ts +3 -1
- package/dist/server/headers.js +3 -1
- package/dist/server/pages-api-route.d.ts +2 -0
- package/dist/server/pages-api-route.js +2 -2
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +6 -4
- package/dist/server/pages-document-asset-props.d.ts +26 -0
- package/dist/server/pages-document-asset-props.js +69 -0
- package/dist/server/pages-node-compat.js +3 -3
- package/dist/server/pages-page-handler.d.ts +1 -0
- package/dist/server/pages-page-handler.js +4 -1
- package/dist/server/pages-page-response.d.ts +2 -0
- package/dist/server/pages-page-response.js +19 -8
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prerender-manifest.d.ts +1 -0
- package/dist/server/prod-server.js +2 -1
- package/dist/server/seed-cache.js +1 -1
- package/dist/server/worker-revalidation-context.js +1 -0
- package/dist/shims/app-router-scroll-state.d.ts +2 -1
- package/dist/shims/app-router-scroll-state.js +7 -2
- package/dist/shims/document.js +15 -2
- package/dist/shims/hash-scroll.d.ts +1 -1
- package/dist/shims/hash-scroll.js +2 -1
- package/dist/shims/link.d.ts +2 -0
- package/dist/shims/link.js +59 -18
- package/dist/shims/metadata.d.ts +11 -17
- package/dist/shims/metadata.js +24 -32
- package/dist/shims/navigation.d.ts +18 -2
- package/dist/shims/navigation.js +69 -20
- package/dist/shims/request-context.d.ts +2 -1
- package/dist/shims/slot.d.ts +2 -1
- package/dist/shims/slot.js +6 -2
- package/dist/shims/streamed-icons.d.ts +9 -0
- package/dist/shims/streamed-icons.js +33 -0
- package/package.json +1 -1
|
@@ -30,6 +30,10 @@ function readRequestCacheLifeForPrerender(options) {
|
|
|
30
30
|
if (options.isEdgeRuntime && options.revalidateSeconds === null) return (options.peekRequestCacheLife?.() ?? options.getRequestCacheLife())?.revalidate !== void 0 ? { revalidate: 0 } : null;
|
|
31
31
|
return options.peekRequestCacheLife?.() ?? options.getRequestCacheLife();
|
|
32
32
|
}
|
|
33
|
+
function resolveConfiguredDynamicStaleTimeSeconds() {
|
|
34
|
+
const seconds = Number(process.env.__NEXT_CLIENT_ROUTER_DYNAMIC_STALETIME);
|
|
35
|
+
return Number.isInteger(seconds) && seconds >= 0 ? seconds : 0;
|
|
36
|
+
}
|
|
33
37
|
function readRequestCacheLifeForCachePolicy(options) {
|
|
34
38
|
const requestCacheLife = options.getRequestCacheLife();
|
|
35
39
|
if (options.isEdgeRuntime && options.revalidateSeconds === null) return null;
|
|
@@ -322,10 +326,11 @@ async function renderAppPageLifecycle(options) {
|
|
|
322
326
|
layoutParamAccess: options.layoutParamAccess
|
|
323
327
|
});
|
|
324
328
|
const shouldBypassRscCacheForSkipTransport = options.isRscRequest && isSkipTransportEnabled(skipDisposition);
|
|
329
|
+
const dynamicStaleTimeSeconds = options.dynamicStaleTimeSeconds ?? (options.isForceDynamic ? resolveConfiguredDynamicStaleTimeSeconds() : void 0);
|
|
325
330
|
const outgoingElement = AppElementsWire.encodeOutgoingPayload({
|
|
326
331
|
element: options.element,
|
|
327
332
|
layoutFlags,
|
|
328
|
-
...
|
|
333
|
+
...dynamicStaleTimeSeconds !== void 0 && options.isPrerender !== true && !options.isForceStatic ? { dynamicStaleTimeSeconds } : {},
|
|
329
334
|
...artifactCompatibility ? { artifactCompatibility } : {},
|
|
330
335
|
renderObservation: payloadRenderObservation,
|
|
331
336
|
skipDisposition: options.isRscRequest ? skipDisposition : void 0
|
|
@@ -385,8 +390,10 @@ async function renderAppPageLifecycle(options) {
|
|
|
385
390
|
revalidateSeconds
|
|
386
391
|
});
|
|
387
392
|
if (shouldBypassRscCacheForSkipTransport) options.isrDebug?.("RSC cache write skipped (skip transport payload)", options.cleanPathname);
|
|
393
|
+
const shouldEmitDynamicStaleTime = dynamicStaleTimeSeconds !== void 0 && options.isPrerender !== true && !options.isForceStatic && (dynamicUsedDuringBuild || options.isForceDynamic || !shouldCaptureRscForCacheMetadata);
|
|
388
394
|
const rscResponse = buildAppPageRscResponse(rscForResponse, {
|
|
389
|
-
|
|
395
|
+
cacheTags: options.isPrerender === true ? options.getPageTags() : void 0,
|
|
396
|
+
dynamicStaleTimeSeconds: shouldEmitDynamicStaleTime ? dynamicStaleTimeSeconds : void 0,
|
|
390
397
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
391
398
|
middlewareContext: options.middlewareContext,
|
|
392
399
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
@@ -474,7 +481,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
474
481
|
}
|
|
475
482
|
return {
|
|
476
483
|
kind,
|
|
477
|
-
...kind === "dynamic" &&
|
|
484
|
+
...kind === "dynamic" && dynamicStaleTimeSeconds !== void 0 && options.isPrerender !== true && !shouldCaptureRscForCacheMetadata ? { dynamicStaleTimeSeconds } : {}
|
|
478
485
|
};
|
|
479
486
|
},
|
|
480
487
|
fontData,
|
|
@@ -564,6 +571,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
564
571
|
});
|
|
565
572
|
if (htmlRender.shellErrorRecovered) {
|
|
566
573
|
const response = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
574
|
+
cacheTags: options.isPrerender === true ? options.getPageTags() : void 0,
|
|
567
575
|
draftCookie,
|
|
568
576
|
linkHeader,
|
|
569
577
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
@@ -581,6 +589,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
581
589
|
const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && !options.isEdgeRuntime && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
|
|
582
590
|
if (htmlResponsePolicy.shouldWriteToCache || shouldSpeculativelyWriteCache) {
|
|
583
591
|
const isrResponse = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
592
|
+
cacheTags: options.isPrerender === true ? options.getPageTags() : void 0,
|
|
584
593
|
draftCookie,
|
|
585
594
|
linkHeader,
|
|
586
595
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
@@ -647,6 +656,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
647
656
|
});
|
|
648
657
|
}
|
|
649
658
|
return buildAppPageHtmlResponse(safeHtmlStream, {
|
|
659
|
+
cacheTags: options.isPrerender === true ? options.getPageTags() : void 0,
|
|
650
660
|
draftCookie,
|
|
651
661
|
linkHeader,
|
|
652
662
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
@@ -33,7 +33,6 @@ type ParallelGenerateStaticParamsBranch = {
|
|
|
33
33
|
routeSegments?: readonly string[] | null;
|
|
34
34
|
};
|
|
35
35
|
type ValidateAppPageDynamicParamsOptions = {
|
|
36
|
-
clearRequestContext: () => void;
|
|
37
36
|
enforceStaticParamsOnly: boolean;
|
|
38
37
|
generateStaticParams?: GenerateStaticParams | GenerateStaticParamsSource | readonly (GenerateStaticParams | GenerateStaticParamsSource | null | undefined)[] | null;
|
|
39
38
|
isDynamicRoute: boolean;
|
|
@@ -212,10 +212,7 @@ function normalizeGenerateStaticParams(generateStaticParams) {
|
|
|
212
212
|
async function validateAppPageDynamicParams(options) {
|
|
213
213
|
if (!options.enforceStaticParamsOnly || !options.isDynamicRoute) return null;
|
|
214
214
|
const generateStaticParamsSources = normalizeGenerateStaticParams(options.generateStaticParams);
|
|
215
|
-
if (generateStaticParamsSources.length === 0)
|
|
216
|
-
options.clearRequestContext();
|
|
217
|
-
return notFoundResponse();
|
|
218
|
-
}
|
|
215
|
+
if (generateStaticParamsSources.length === 0) return notFoundResponse();
|
|
219
216
|
const chainedSources = generateStaticParamsSources.filter((source) => source.chained);
|
|
220
217
|
let chainedStaticParams = null;
|
|
221
218
|
if (chainedSources.length > 0) chainedStaticParams = await generateChainedStaticParams(chainedSources);
|
|
@@ -230,17 +227,11 @@ async function validateAppPageDynamicParams(options) {
|
|
|
230
227
|
const result = await generateIndependentStaticParams(sources, chainedStaticParams, options.params);
|
|
231
228
|
if (result.validated) {
|
|
232
229
|
validatedIndependentResults = true;
|
|
233
|
-
if (!areStaticParamsAllowed(options.params, result.staticParams, true))
|
|
234
|
-
options.clearRequestContext();
|
|
235
|
-
return notFoundResponse();
|
|
236
|
-
}
|
|
230
|
+
if (!areStaticParamsAllowed(options.params, result.staticParams, true)) return notFoundResponse();
|
|
237
231
|
}
|
|
238
232
|
}
|
|
239
233
|
if (chainedStaticParams && !validatedIndependentResults) {
|
|
240
|
-
if (!areStaticParamsAllowed(options.params, chainedStaticParams))
|
|
241
|
-
options.clearRequestContext();
|
|
242
|
-
return notFoundResponse();
|
|
243
|
-
}
|
|
234
|
+
if (!areStaticParamsAllowed(options.params, chainedStaticParams)) return notFoundResponse();
|
|
244
235
|
}
|
|
245
236
|
return null;
|
|
246
237
|
}
|
|
@@ -40,6 +40,7 @@ type AppPageHtmlResponsePolicy = {
|
|
|
40
40
|
shouldWriteToCache: boolean;
|
|
41
41
|
} & AppPageResponsePolicy;
|
|
42
42
|
type BuildAppPageRscResponseOptions = {
|
|
43
|
+
cacheTags?: readonly string[];
|
|
43
44
|
dynamicStaleTimeSeconds?: number;
|
|
44
45
|
isEdgeRuntime?: boolean;
|
|
45
46
|
middlewareContext: AppPageMiddlewareContext;
|
|
@@ -51,6 +52,7 @@ type BuildAppPageRscResponseOptions = {
|
|
|
51
52
|
timing?: AppPageResponseTiming;
|
|
52
53
|
};
|
|
53
54
|
type BuildAppPageHtmlResponseOptions = {
|
|
55
|
+
cacheTags?: readonly string[];
|
|
54
56
|
draftCookie?: string | null; /** Combined preload `Link` header value (React hints + font preloads), already capped. */
|
|
55
57
|
linkHeader?: string;
|
|
56
58
|
isEdgeRuntime?: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
|
|
1
|
+
import { NEXT_CACHE_TAGS_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
|
|
2
2
|
import { NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildRevalidateCacheControl } from "./cache-control.js";
|
|
3
3
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
4
4
|
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
@@ -22,6 +22,9 @@ function applyPrerenderCacheLifeHeader(headers, requestCacheLife) {
|
|
|
22
22
|
if (payload.revalidate === void 0 && payload.expire === void 0) return;
|
|
23
23
|
headers.set(VINEXT_PRERENDER_CACHE_LIFE_HEADER, JSON.stringify(payload));
|
|
24
24
|
}
|
|
25
|
+
function applyPrerenderCacheTagsHeader(headers, cacheTags) {
|
|
26
|
+
if (cacheTags && cacheTags.length > 0) headers.set(NEXT_CACHE_TAGS_HEADER, cacheTags.join(","));
|
|
27
|
+
}
|
|
25
28
|
function resolveAppPageRscResponsePolicy(options) {
|
|
26
29
|
if (options.isDraftMode) return { cacheControl: NO_STORE_CACHE_CONTROL };
|
|
27
30
|
if (options.isForceDynamic || options.dynamicUsedDuringBuild) return { cacheControl: NO_STORE_CACHE_CONTROL };
|
|
@@ -104,6 +107,7 @@ function buildAppPageRscResponse(body, options) {
|
|
|
104
107
|
applyRscCompatibilityIdHeader(headers);
|
|
105
108
|
applyRscDeploymentIdHeader(headers);
|
|
106
109
|
applyPrerenderCacheLifeHeader(headers, options.requestCacheLife);
|
|
110
|
+
applyPrerenderCacheTagsHeader(headers, options.cacheTags);
|
|
107
111
|
applyTimingHeader(headers, options.timing);
|
|
108
112
|
return new Response(body, {
|
|
109
113
|
status: options.middlewareContext.status ?? 200,
|
|
@@ -122,6 +126,7 @@ function buildAppPageHtmlResponse(body, options) {
|
|
|
122
126
|
if (options.linkHeader) headers.set("Link", options.linkHeader);
|
|
123
127
|
mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);
|
|
124
128
|
applyPrerenderCacheLifeHeader(headers, options.requestCacheLife);
|
|
129
|
+
applyPrerenderCacheTagsHeader(headers, options.cacheTags);
|
|
125
130
|
applyTimingHeader(headers, options.timing);
|
|
126
131
|
return new Response(body, {
|
|
127
132
|
status: options.middlewareContext.status ?? 200,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AppRouteSemanticIds } from "../routing/app-route-graph.js";
|
|
2
2
|
import { AppElements, AppElementsInterception, AppElementsSlotBinding } from "./app-elements-wire.js";
|
|
3
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
3
4
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
4
5
|
import { ThenableParamsObserver } from "../shims/thenable-params.js";
|
|
5
6
|
import { Metadata, Viewport } from "../shims/metadata.js";
|
|
6
7
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
7
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.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";
|
|
@@ -136,6 +136,7 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
|
|
|
136
136
|
resolvedMetadata: Metadata | null;
|
|
137
137
|
resolvedMetadataPathname?: string;
|
|
138
138
|
resolvedViewport: Viewport;
|
|
139
|
+
scriptNonce?: string;
|
|
139
140
|
streamingMetadata?: Promise<Metadata | null> | null;
|
|
140
141
|
streamingMetadataOutlet?: Promise<unknown> | null;
|
|
141
142
|
streamingMetadataOutletSuspended?: boolean;
|
|
@@ -173,7 +174,7 @@ declare function createAppPageLayoutEntries<TModule extends AppPageModule, TErro
|
|
|
173
174
|
unauthorizeds?: readonly (TModule | null | undefined)[] | null;
|
|
174
175
|
}): AppPageLayoutEntry<TModule, TErrorModule>[];
|
|
175
176
|
declare function createAppPageSourcePage(routeSegments: readonly string[] | null | undefined): string;
|
|
176
|
-
declare function createAppPageRouteBodyMetadata(metadata: Metadata | null, pathname: string, metadataPlacement: "body" | "head", trailingSlash?: boolean): ReactNode;
|
|
177
|
+
declare function createAppPageRouteBodyMetadata(metadata: Metadata | null, pathname: string, metadataPlacement: "body" | "head", trailingSlash?: boolean, scriptNonce?: string): ReactNode;
|
|
177
178
|
declare function buildAppPageElements<TModule extends AppPageModule, TErrorModule extends AppPageErrorModule>(options: BuildAppPageElementsOptions<TModule, TErrorModule>): AppElements;
|
|
178
179
|
//#endregion
|
|
179
180
|
export { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute, AppPageSlotOverride, buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath, probeAppPageLayoutWithTracking, resolveAppPageChildSegments };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { createAppRenderDependency, registerAppElementRenderDependencies, renderAfterAppDependencies, renderWithAppDependencyBarrier } from "./app-render-dependency.js";
|
|
2
|
-
import { APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
3
|
-
import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "./app-rsc-render-mode.js";
|
|
2
|
+
import { APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
3
|
+
import { APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "./app-rsc-render-mode.js";
|
|
4
4
|
import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY } from "./app-elements.js";
|
|
5
|
+
import { createInlineScriptTag, escapeHtmlAttr } from "./html.js";
|
|
5
6
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
6
7
|
import { ErrorBoundary, ForbiddenBoundary, GlobalErrorBoundary, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
7
8
|
import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
|
|
9
|
+
import DefaultNotFound from "../shims/default-not-found.js";
|
|
8
10
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
9
11
|
import { MetadataHead, ViewportHead, renderMetadataToHtml } from "../shims/metadata.js";
|
|
10
12
|
import { Children as Children$1, ParallelSlot, Slot } from "../shims/slot.js";
|
|
13
|
+
import { StreamedIconsInsertion } from "../shims/streamed-icons.js";
|
|
11
14
|
import { resolveAppPageBranchParams, resolveAppPageSegmentParamScopeKeys, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
12
15
|
import { probeReactServerSubtree } from "./app-page-probe.js";
|
|
13
16
|
import { APP_PAGE_SEGMENT_KEY, resolveAppPageChildSegments, resolveAppPageRouteStateKey, resolveAppPageSegmentStateKey } from "./app-page-segment-state.js";
|
|
@@ -16,6 +19,7 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
|
16
19
|
//#region src/server/app-page-route-wiring.tsx
|
|
17
20
|
const APP_PAGE_LAYOUT_PROBE_CHILD = /* @__PURE__ */ jsx(Fragment, {});
|
|
18
21
|
const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
|
|
22
|
+
const DEFAULT_NOT_FOUND_COMPONENT = DefaultNotFound;
|
|
19
23
|
function resolveSlotLayoutParams(routeSegments, treePosition, params) {
|
|
20
24
|
return resolveAppPageBranchParams(routeSegments, treePosition, params);
|
|
21
25
|
}
|
|
@@ -120,17 +124,23 @@ function createAppPageLoadingEntries(route) {
|
|
|
120
124
|
});
|
|
121
125
|
}
|
|
122
126
|
function getPrefetchLoadingEntry(route) {
|
|
123
|
-
let
|
|
127
|
+
let rootEntry = null;
|
|
128
|
+
let firstNestedEntry = null;
|
|
124
129
|
for (const [index, loadingModule] of (route.loadings ?? []).entries()) {
|
|
125
130
|
if (!getDefaultExport(loadingModule)) continue;
|
|
126
131
|
const treePosition = route.loadingTreePositions?.[index];
|
|
127
132
|
if (treePosition === void 0) continue;
|
|
128
|
-
if (
|
|
133
|
+
if (treePosition === 0) rootEntry ??= {
|
|
134
|
+
loadingModule,
|
|
135
|
+
treePosition
|
|
136
|
+
};
|
|
137
|
+
else if (firstNestedEntry === null || treePosition < firstNestedEntry.treePosition) firstNestedEntry = {
|
|
129
138
|
loadingModule,
|
|
130
139
|
treePosition
|
|
131
140
|
};
|
|
132
141
|
}
|
|
133
|
-
if (
|
|
142
|
+
if (firstNestedEntry) return firstNestedEntry;
|
|
143
|
+
if (rootEntry) return rootEntry;
|
|
134
144
|
return getDefaultExport(route.loading) ? {
|
|
135
145
|
loadingModule: route.loading,
|
|
136
146
|
treePosition: route.routeSegments?.length ?? 0
|
|
@@ -194,6 +204,7 @@ function createAppPageSlotBindings(route, layoutEntries, resolveSlotOverride, op
|
|
|
194
204
|
if (route.childrenSlot) {
|
|
195
205
|
const ownerLayoutId = layoutEntries.find((layoutEntry) => layoutEntry.treePath === route.childrenSlot?.ownerTreePath)?.id;
|
|
196
206
|
bindings.push({
|
|
207
|
+
...route.childrenSlot.state === "active" ? { activeRouteId: options.routeId } : {},
|
|
197
208
|
ownerLayoutId: ownerLayoutId ?? null,
|
|
198
209
|
slotId: route.childrenSlot.id,
|
|
199
210
|
state: route.childrenSlot.state
|
|
@@ -226,16 +237,40 @@ function createAppPageRouteHead(metadata, viewport, pathname, metadataPlacement,
|
|
|
226
237
|
/* @__PURE__ */ jsx(ViewportHead, { viewport })
|
|
227
238
|
] });
|
|
228
239
|
}
|
|
229
|
-
function
|
|
240
|
+
function hasStreamedIcons(metadata) {
|
|
241
|
+
const icons = metadata.icons;
|
|
242
|
+
if (!icons) return false;
|
|
243
|
+
if (typeof icons === "string" || icons instanceof URL || Array.isArray(icons)) return !Array.isArray(icons) || icons.length > 0;
|
|
244
|
+
if ("url" in icons) return true;
|
|
245
|
+
return Boolean(icons.shortcut || icons.icon || icons.apple || icons.other);
|
|
246
|
+
}
|
|
247
|
+
function createStreamedIconKey(pathname, metadataHtml) {
|
|
248
|
+
let hash = 2166136261;
|
|
249
|
+
for (let index = 0; index < metadataHtml.length; index++) {
|
|
250
|
+
hash ^= metadataHtml.charCodeAt(index);
|
|
251
|
+
hash = Math.imul(hash, 16777619);
|
|
252
|
+
}
|
|
253
|
+
return `${pathname}:${(hash >>> 0).toString(36)}`;
|
|
254
|
+
}
|
|
255
|
+
const STREAMED_ICON_KEY_PLACEHOLDER = "vinext-pending-streamed-icon-key";
|
|
256
|
+
const REINSERT_STREAMED_ICONS_SCRIPT = `document.querySelectorAll('body link[rel="icon"], body link[rel="apple-touch-icon"]').forEach(el => document.head.appendChild(el));const a='data-vinext-streamed-icon',o=el=>{const m=el.getAttribute(a),i=m.lastIndexOf(':');return Number(m.slice(i+1))};[...document.querySelectorAll('link['+a+']')].sort((l,r)=>o(l)-o(r)).forEach(el=>document.head.appendChild(el))`;
|
|
257
|
+
function createAppPageRouteBodyMetadata(metadata, pathname, metadataPlacement, trailingSlash, scriptNonce) {
|
|
230
258
|
if (!metadata || metadataPlacement !== "body") return null;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
259
|
+
const streamedIconKey = hasStreamedIcons(metadata) ? STREAMED_ICON_KEY_PLACEHOLDER : void 0;
|
|
260
|
+
const renderedMetadataHtml = renderMetadataToHtml(metadata, pathname, {
|
|
261
|
+
trailingSlash,
|
|
262
|
+
streamedIconKey
|
|
234
263
|
});
|
|
264
|
+
const metadataKey = streamedIconKey ? createStreamedIconKey(pathname, renderedMetadataHtml) : "";
|
|
265
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
266
|
+
hidden: true,
|
|
267
|
+
suppressHydrationWarning: true,
|
|
268
|
+
dangerouslySetInnerHTML: { __html: (streamedIconKey ? renderedMetadataHtml.replaceAll(`<link data-vinext-streamed-icon="${STREAMED_ICON_KEY_PLACEHOLDER}:`, `<link data-vinext-streamed-icon="${escapeHtmlAttr(metadataKey)}:`) : renderedMetadataHtml) + createInlineScriptTag(REINSERT_STREAMED_ICONS_SCRIPT, scriptNonce) }
|
|
269
|
+
}), /* @__PURE__ */ jsx(StreamedIconsInsertion, { metadataKey })] });
|
|
235
270
|
}
|
|
236
271
|
async function AppPageStreamingMetadata(props) {
|
|
237
272
|
try {
|
|
238
|
-
return createAppPageRouteBodyMetadata(await props.metadata, props.pathname, "body", props.trailingSlash);
|
|
273
|
+
return createAppPageRouteBodyMetadata(await props.metadata, props.pathname, "body", props.trailingSlash, props.scriptNonce);
|
|
239
274
|
} catch {
|
|
240
275
|
return null;
|
|
241
276
|
}
|
|
@@ -287,6 +322,7 @@ function buildAppPageElements(options) {
|
|
|
287
322
|
for (const entry of loadingEntries) if (entry.treePosition <= treePosition && (!nearest || entry.treePosition > nearest.treePosition)) nearest = entry;
|
|
288
323
|
return nearest;
|
|
289
324
|
};
|
|
325
|
+
const isPrefetchEmpty = renderMode === APP_RSC_RENDER_MODE_PREFETCH_EMPTY;
|
|
290
326
|
const isPrefetchLoadingShell = renderMode === APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL;
|
|
291
327
|
const prefetchLoadingEntry = isPrefetchLoadingShell ? getPrefetchLoadingEntry(options.route) : null;
|
|
292
328
|
const metadataPlacement = options.metadataPlacement ?? "head";
|
|
@@ -339,13 +375,22 @@ function buildAppPageElements(options) {
|
|
|
339
375
|
slotBindings: createAppPageSlotBindings(options.route, layoutEntries, resolveSlotOverride, {
|
|
340
376
|
interception: renderIdentity?.interception ?? options.interception ?? null,
|
|
341
377
|
interceptionContext,
|
|
378
|
+
routeId,
|
|
342
379
|
routePath: options.routePath
|
|
343
380
|
})
|
|
344
381
|
}) };
|
|
382
|
+
if (isPrefetchEmpty) {
|
|
383
|
+
elements[APP_LAYOUT_IDS_KEY] = [];
|
|
384
|
+
elements[APP_ROOT_LAYOUT_KEY] = null;
|
|
385
|
+
elements[pageElementId] = null;
|
|
386
|
+
elements[routeId] = null;
|
|
387
|
+
return elements;
|
|
388
|
+
}
|
|
345
389
|
if (options.route.staticSiblings && options.route.staticSiblings.length > 0) elements[APP_STATIC_SIBLINGS_KEY] = options.route.staticSiblings;
|
|
346
390
|
if (options.streamingMetadata && streamingMetadataBodyId) elements[streamingMetadataBodyId] = /* @__PURE__ */ jsx(AppPageStreamingMetadata, {
|
|
347
391
|
metadata: options.streamingMetadataTags ?? options.streamingMetadata,
|
|
348
392
|
pathname: options.resolvedMetadataPathname ?? options.routePath,
|
|
393
|
+
scriptNonce: options.scriptNonce,
|
|
349
394
|
trailingSlash: options.trailingSlash
|
|
350
395
|
});
|
|
351
396
|
if (options.streamingMetadataOutlet && streamingMetadataOutletId) elements[streamingMetadataOutletId] = /* @__PURE__ */ jsx(AppPageMetadataOutlet, { metadata: options.streamingMetadataOutlet });
|
|
@@ -468,6 +513,7 @@ function buildAppPageElements(options) {
|
|
|
468
513
|
slotElement = options.createPageElement ? options.createPageElement(slotComponent, slotProps) : (() => {
|
|
469
514
|
return /* @__PURE__ */ jsx(slotComponent, { ...slotProps });
|
|
470
515
|
})();
|
|
516
|
+
if (overrideOrPageComponent) slotElement = /* @__PURE__ */ jsx(Fragment, { children: slotElement }, slotResetKey);
|
|
471
517
|
}
|
|
472
518
|
const branchSegments = slotOverride?.branchSegments ?? slotRouteSegments;
|
|
473
519
|
const branchLayouts = /* @__PURE__ */ new Map();
|
|
@@ -573,7 +619,9 @@ function buildAppPageElements(options) {
|
|
|
573
619
|
routeChildren = /* @__PURE__ */ jsx(AppRouterScrollTarget, { children: routeChildren });
|
|
574
620
|
}
|
|
575
621
|
const lastLayoutErrorModule = errorEntries.length > 0 ? errorEntries[errorEntries.length - 1].errorModule : null;
|
|
576
|
-
const
|
|
622
|
+
const configuredNotFoundComponent = getDefaultExport(options.route.notFound) ?? getDefaultExport(options.rootNotFoundModule);
|
|
623
|
+
const defaultNotFoundOwnerLayoutId = configuredNotFoundComponent === null ? layoutEntries[0]?.id ?? null : null;
|
|
624
|
+
const notFoundComponent = configuredNotFoundComponent ?? (defaultNotFoundOwnerLayoutId === null ? DEFAULT_NOT_FOUND_COMPONENT : null);
|
|
577
625
|
if (notFoundComponent) routeChildren = /* @__PURE__ */ jsx(NotFoundBoundary, {
|
|
578
626
|
resetKey: routeResetKey,
|
|
579
627
|
fallback: /* @__PURE__ */ jsx(notFoundComponent, {}),
|
|
@@ -614,7 +662,7 @@ function buildAppPageElements(options) {
|
|
|
614
662
|
}, segmentResetKey || routeResetKey);
|
|
615
663
|
}
|
|
616
664
|
if (layoutEntry) {
|
|
617
|
-
const layoutNotFoundComponent = getDefaultExport(layoutEntry.notFoundModule);
|
|
665
|
+
const layoutNotFoundComponent = getDefaultExport(layoutEntry.notFoundModule) ?? (layoutEntry.id === defaultNotFoundOwnerLayoutId ? DEFAULT_NOT_FOUND_COMPONENT : null);
|
|
618
666
|
if (layoutNotFoundComponent) segmentChildren = /* @__PURE__ */ jsx(NotFoundBoundary, {
|
|
619
667
|
resetKey: segmentResetKey,
|
|
620
668
|
fallback: /* @__PURE__ */ jsx(layoutNotFoundComponent, {}),
|
|
@@ -680,7 +728,7 @@ function buildAppPageElements(options) {
|
|
|
680
728
|
elements[routeId] = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
681
729
|
createAppPageRouteHead(options.resolvedMetadata, options.resolvedViewport, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash),
|
|
682
730
|
routeChildren,
|
|
683
|
-
createAppPageRouteBodyMetadata(options.resolvedMetadata, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash),
|
|
731
|
+
createAppPageRouteBodyMetadata(options.resolvedMetadata, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash, options.scriptNonce),
|
|
684
732
|
createAppPageStreamingMetadataBody(streamingMetadataBodyId)
|
|
685
733
|
] });
|
|
686
734
|
registerAppElementRenderDependencies(elements, renderDependenciesByElementId);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { AppMiddlewareContext } from "./app-middleware.js";
|
|
2
|
+
import { EdgeApiExecutionRuntime } from "./edge-api-runtime.js";
|
|
2
3
|
|
|
3
4
|
//#region src/server/app-pages-bridge.d.ts
|
|
4
5
|
type PagesEntry = {
|
|
5
|
-
handleApiRoute?: (request: Request, url: string, ctx
|
|
6
|
+
handleApiRoute?: (request: Request, url: string, ctx: unknown, trustedRevalidateOrigin: string | undefined, edgeRuntime: EdgeApiExecutionRuntime) => Promise<Response> | Response;
|
|
6
7
|
matchApiRoute?: (url: string, request: Request) => PagesRouteMatch | null;
|
|
7
8
|
matchPageRoute?: (url: string, request: Request) => PagesRouteMatch | null;
|
|
8
9
|
renderPage?: (request: Request, url: string, query: Record<string, unknown>, parsedUrl: unknown, middlewareRequestHeaders?: Headers | null, options?: {
|
|
@@ -27,7 +27,8 @@ async function renderPagesFallback(options, dependencies) {
|
|
|
27
27
|
if (appRouteMatch !== null) {
|
|
28
28
|
if (apiMatch === null || !pagesRouteHasPriorityOverAppRoute(apiMatch.route, appRouteMatch.route)) return null;
|
|
29
29
|
}
|
|
30
|
-
const
|
|
30
|
+
const executionContext = getRequestExecutionContext();
|
|
31
|
+
const pagesApiResponse = await pagesEntry.handleApiRoute(pagesRequest, pagesUrl, void 0, executionContext?.trustedRevalidateOrigin ?? new URL(pagesRequest.url).origin, executionContext?.hostRuntime ?? "node");
|
|
31
32
|
const draftCookie = getDraftModeCookieHeader();
|
|
32
33
|
return applyDraftModeCookie(applyRouteHandlerMiddlewareContext(pagesApiResponse, middlewareContext), draftCookie);
|
|
33
34
|
}
|
|
@@ -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);
|
|
@@ -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>;
|
|
@@ -328,7 +328,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
328
328
|
searchParams: getResolvedSearchParams(),
|
|
329
329
|
params: {}
|
|
330
330
|
});
|
|
331
|
-
const
|
|
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;
|
|
332
336
|
if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
|
|
333
337
|
if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch) {
|
|
334
338
|
const headers = new Headers();
|
|
@@ -374,8 +378,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
374
378
|
middlewareContext,
|
|
375
379
|
mountedSlotsHeader,
|
|
376
380
|
request,
|
|
381
|
+
scriptNonce,
|
|
377
382
|
routeMatch: preActionMatch,
|
|
378
|
-
routePathname:
|
|
383
|
+
routePathname: preActionRoutePathname,
|
|
379
384
|
searchParams: getResolvedSearchParams()
|
|
380
385
|
}) : null;
|
|
381
386
|
if (serverActionResponse) return serverActionResponse;
|
|
@@ -383,7 +388,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
383
388
|
let match = preActionMatch;
|
|
384
389
|
const renderPagesForMatchKind = async (matchKind) => {
|
|
385
390
|
if (!filesystemRouteEligible) return null;
|
|
386
|
-
const response = match === null || match.route.isDynamic ? await options.renderPagesFallback?.({
|
|
391
|
+
const response = !isInterceptionMatch && (match === null || match.route.isDynamic) ? await options.renderPagesFallback?.({
|
|
387
392
|
appRouteMatch: match ?? null,
|
|
388
393
|
allowRscDocumentFallback: didMiddlewareRewritePathname,
|
|
389
394
|
isDataRequest,
|
|
@@ -409,7 +414,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
409
414
|
options.clearRequestContext();
|
|
410
415
|
return staticPagesFallbackResponse;
|
|
411
416
|
}
|
|
412
|
-
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) {
|
|
413
418
|
const afterFilesRewrite = await applyRewrite({
|
|
414
419
|
basePathState,
|
|
415
420
|
clearRequestContext: options.clearRequestContext,
|
|
@@ -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
|
-
|
|
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,
|
|
@@ -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";
|
|
@@ -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 };
|