vinext 1.4.0 → 1.4.2
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/README.md +21 -21
- package/dist/build/action-owner-manifest.js +1 -0
- package/dist/build/prerender.js +3 -2
- package/dist/check.js +4 -7
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +19 -3
- package/dist/config/config-matchers.js +4 -2
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +55 -2
- package/dist/config/next-config.d.ts +22 -1
- package/dist/config/next-config.js +49 -4
- package/dist/entries/app-rsc-entry.js +41 -19
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/pages-server-entry.js +5 -1
- package/dist/index.js +44 -32
- package/dist/init-cloudflare.js +18 -2
- package/dist/plugins/css-target.d.ts +18 -0
- package/dist/plugins/css-target.js +93 -0
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/routing/app-route-graph.d.ts +10 -0
- package/dist/routing/app-route-graph.js +15 -1
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +5 -6
- package/dist/server/app-action-forwarding.js +3 -1
- package/dist/server/app-browser-entry.js +28 -7
- package/dist/server/app-browser-rsc-redirect.js +3 -3
- package/dist/server/app-browser-server-action-client.js +2 -2
- package/dist/server/app-browser-visible-commit.js +2 -2
- package/dist/server/app-elements.d.ts +3 -0
- package/dist/server/app-elements.js +14 -1
- package/dist/server/app-fallback-renderer.js +2 -2
- package/dist/server/app-optimistic-routing.d.ts +12 -1
- package/dist/server/app-optimistic-routing.js +40 -19
- package/dist/server/app-page-boundary-render.js +7 -12
- package/dist/server/app-page-cache-render.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -2
- package/dist/server/app-page-dispatch.js +73 -31
- package/dist/server/app-page-element-builder.d.ts +9 -20
- package/dist/server/app-page-element-builder.js +40 -52
- package/dist/server/app-page-execution.js +9 -6
- package/dist/server/app-page-intercept-segment-config.d.ts +56 -0
- package/dist/server/app-page-intercept-segment-config.js +90 -0
- package/dist/server/app-page-navigation-params.d.ts +23 -0
- package/dist/server/app-page-navigation-params.js +49 -0
- package/dist/server/app-page-render.d.ts +5 -3
- package/dist/server/app-page-render.js +31 -17
- package/dist/server/app-page-request.d.ts +24 -2
- package/dist/server/app-page-request.js +10 -10
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +10 -0
- package/dist/server/app-page-route-wiring.js +34 -13
- package/dist/server/app-page-segment-plan.js +9 -1
- package/dist/server/app-page-segment-state.d.ts +9 -0
- package/dist/server/app-page-segment-state.js +54 -1
- package/dist/server/app-page-stream.d.ts +10 -8
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-response-stage-entry.js +1 -0
- package/dist/server/app-route-handler-execution.js +3 -2
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +11 -7
- package/dist/server/app-route-module-loader.d.ts +2 -0
- package/dist/server/app-route-module-loader.js +1 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +10 -10
- package/dist/server/app-rsc-cache-busting.js +27 -68
- package/dist/server/app-rsc-error-handler.js +1 -1
- package/dist/server/app-rsc-errors.js +4 -1
- package/dist/server/app-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +126 -103
- package/dist/server/app-rsc-request-normalization.d.ts +10 -12
- package/dist/server/app-rsc-request-normalization.js +11 -14
- package/dist/server/app-rsc-response-finalizer.d.ts +3 -0
- package/dist/server/app-rsc-response-finalizer.js +11 -1
- package/dist/server/app-rsc-response-stage.js +4 -12
- package/dist/server/app-rsc-route-matching.d.ts +14 -0
- package/dist/server/app-rsc-route-matching.js +42 -18
- package/dist/server/app-server-action-execution.js +24 -14
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +13 -8
- package/dist/server/app-worker-stages.d.ts +12 -3
- package/dist/server/app-worker-stages.js +37 -4
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cache-control.d.ts +2 -0
- package/dist/server/cache-control.js +3 -1
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +2 -1
- package/dist/server/image-local-patterns.d.ts +21 -0
- package/dist/server/image-local-patterns.js +59 -0
- package/dist/server/image-optimization.d.ts +28 -22
- package/dist/server/image-optimization.js +17 -2
- package/dist/server/isr-cache.js +4 -1
- package/dist/server/metadata-route-response.js +25 -7
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +7 -3
- package/dist/server/nitro-public-files-plugin.js +20 -8
- package/dist/server/pages-data-route.d.ts +5 -1
- package/dist/server/pages-data-route.js +14 -6
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +2 -0
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +17 -6
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-pipeline.js +6 -5
- package/dist/server/pages-request-stage-entry.js +25 -4
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +59 -17
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +14 -4
- package/dist/server/request-pipeline.js +33 -15
- package/dist/server/response-stage-cacheability.d.ts +7 -0
- package/dist/server/response-stage-cacheability.js +6 -5
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/server/worker-image-optimization.d.ts +2 -2
- package/dist/server/worker-image-optimization.js +18 -3
- package/dist/server/worker-utils.d.ts +8 -0
- package/dist/server/worker-utils.js +19 -2
- package/dist/shims/cache-request-state.d.ts +6 -6
- package/dist/shims/cache-request-state.js +6 -36
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +77 -47
- package/dist/shims/cache.d.ts +10 -5
- package/dist/shims/cache.js +35 -22
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/fetch-cache.js +6 -2
- package/dist/shims/headers.d.ts +2 -1
- package/dist/shims/headers.js +5 -3
- package/dist/shims/image-props.d.ts +6 -0
- package/dist/shims/image-props.js +39 -3
- package/dist/shims/image.js +3 -3
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/link.js +5 -10
- package/dist/shims/navigation.js +2 -3
- package/dist/shims/request-state-types.d.ts +2 -1
- package/dist/shims/slot.d.ts +9 -2
- package/dist/shims/slot.js +76 -11
- package/dist/shims/unified-request-context.d.ts +6 -0
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/base-path.d.ts +7 -0
- package/dist/utils/base-path.js +11 -1
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { closeAfterResponse, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import "../utils/protocol-headers.js";
|
|
3
3
|
import { VINEXT_INTERCEPTION_ID_HEADER, VINEXT_RSC_VARY_HEADER } from "./app-rsc-vary.js";
|
|
4
|
-
import { VINEXT_MOUNTED_LAYOUTS_HEADER } from "./headers.js";
|
|
4
|
+
import { VINEXT_MOUNTED_LAYOUTS_HEADER, VINEXT_PARAMS_HEADER } from "./headers.js";
|
|
5
5
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
6
6
|
import { runInWorkStoreScope } from "../shims/internal/work-store-scope.js";
|
|
7
7
|
import { beginRouteCacheability, isRouteCacheabilityIdentityProbe, isRouteCacheabilityProbe, markRouteCacheabilityPatternDynamic, readRouteCacheabilityState } from "../shims/cacheability-classification.js";
|
|
@@ -21,16 +21,17 @@ import { resolveUncacheableCacheControl } from "./app-page-response.js";
|
|
|
21
21
|
import { buildRscRedirectFlightStream } from "./app-rsc-redirect-flight.js";
|
|
22
22
|
import { buildAppPageSpecialErrorResponse, resolveAppPageCaughtNotFoundBoundaries, resolveAppPageShellSpecialError, resolveAppPageSpecialError, resolveAppPageSpecialErrorStoredHeaders } from "./app-page-execution.js";
|
|
23
23
|
import { resolveAppPageLayoutHttpAccessBoundary, resolveAppPageParentHttpAccessBoundary, resolveAppPageRootHttpAccessBoundaryTreePosition } from "./app-page-boundary.js";
|
|
24
|
+
import { resolveAppPageNavigationParams } from "./app-page-navigation-params.js";
|
|
25
|
+
import { createAppPageRscErrorTracker } from "./app-page-stream.js";
|
|
24
26
|
import { isAppClientReference } from "./app-render-dependency.js";
|
|
25
27
|
import { resolveAppPageTraceOperation } from "./app-page-tracing.js";
|
|
26
|
-
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
27
|
-
import { resolveAppPageNavigationParams } from "./app-page-element-builder.js";
|
|
28
|
-
import { createAppPageRscErrorTracker } from "./app-page-stream.js";
|
|
29
28
|
import { getDefaultHttpAccessFallbackModule } from "./default-http-access-fallback-modules.js";
|
|
29
|
+
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
30
30
|
import { consumeAppPageRenderObservationState, discardAppPageRenderState } from "./app-page-render-observation.js";
|
|
31
31
|
import { buildAppPageTags } from "./implicit-tags.js";
|
|
32
32
|
import { resolveAppPageMethodResponse } from "./app-page-method.js";
|
|
33
|
-
import {
|
|
33
|
+
import { resolveAppPageInterceptSegmentConfig } from "./app-page-intercept-segment-config.js";
|
|
34
|
+
import { buildAppPageElement, resolveAppPageIntercept, resolveAppPageInterceptState, resolveAppPageInterceptionRerenderTarget, validateAppPageDynamicParams } from "./app-page-request.js";
|
|
34
35
|
import { applyIneligibleRouteCachePolicy, renderAppPageLifecycle } from "./app-page-render.js";
|
|
35
36
|
//#region src/server/app-page-dispatch.ts
|
|
36
37
|
function getActiveLoadingTreePositions(route) {
|
|
@@ -146,12 +147,48 @@ function hasNoManifestAdmissionState(routePattern) {
|
|
|
146
147
|
}, admission.representation, admission.routePathname) === null;
|
|
147
148
|
}
|
|
148
149
|
async function dispatchAppPage(options) {
|
|
149
|
-
const dispatch = () => runWithFetchDedupe(() => dispatchAppPageInner(options));
|
|
150
|
+
const dispatch = () => runWithFetchDedupe(async () => dispatchAppPageInner(await withResolvedIntercept(options)));
|
|
150
151
|
let response;
|
|
151
152
|
if (!options.pprFallbackShell || !options.pprRuntime) response = await dispatch();
|
|
152
153
|
else response = await options.pprRuntime.run(options.pprFallbackShell, dispatch);
|
|
153
154
|
return options.isRscRequest ? response : traceResponseStart(response);
|
|
154
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Resolves the request's intercept once, for the render and its cache reads.
|
|
158
|
+
*
|
|
159
|
+
* Next.js renders an interception as its own route even when its source is the
|
|
160
|
+
* matched route (`app/shots/[id]` beside `app/shots/@modal/(.)[id]`, from
|
|
161
|
+
* `/shots/1` to `/shots/2`). vinext renders that through the matched route's
|
|
162
|
+
* own page render, so the interception's segment config replaces the route's
|
|
163
|
+
* before that render reads it.
|
|
164
|
+
*/
|
|
165
|
+
async function withResolvedIntercept(options) {
|
|
166
|
+
const interceptState = await resolveAppPageInterceptState({
|
|
167
|
+
cleanPathname: options.cleanPathname,
|
|
168
|
+
currentRoute: options.route,
|
|
169
|
+
findIntercept: options.findIntercept,
|
|
170
|
+
getSourceRoute: options.getSourceRoute,
|
|
171
|
+
interceptState: options.interceptState,
|
|
172
|
+
isRscRequest: options.isRscRequest
|
|
173
|
+
});
|
|
174
|
+
if (interceptState.kind !== "current-route") return {
|
|
175
|
+
...options,
|
|
176
|
+
interceptState
|
|
177
|
+
};
|
|
178
|
+
const config = resolveAppPageInterceptSegmentConfig(options.route, toInterceptOptions(options.interceptionContext, interceptState.intercept));
|
|
179
|
+
return {
|
|
180
|
+
...options,
|
|
181
|
+
interceptState,
|
|
182
|
+
dynamicConfig: config.dynamicConfig,
|
|
183
|
+
dynamicStaleTimeSeconds: config.dynamicStaleTimeSeconds,
|
|
184
|
+
fetchCache: config.fetchCacheMode,
|
|
185
|
+
hasAnyGenerateStaticParams: config.hasAnyGenerateStaticParams,
|
|
186
|
+
hasGenerateStaticParams: config.hasGenerateStaticParams,
|
|
187
|
+
isEdgeRuntime: config.isEdgeRuntime,
|
|
188
|
+
isStaticGenerationEdgeRuntime: config.isStaticGenerationEdgeRuntime,
|
|
189
|
+
revalidateSeconds: config.revalidateSeconds
|
|
190
|
+
};
|
|
191
|
+
}
|
|
155
192
|
async function dispatchAppPageInner(options) {
|
|
156
193
|
const route = options.route;
|
|
157
194
|
beginRouteCacheability("app-page", route.pattern);
|
|
@@ -206,6 +243,7 @@ async function dispatchAppPageInner(options) {
|
|
|
206
243
|
isDynamicError,
|
|
207
244
|
isForceDynamic,
|
|
208
245
|
isForceStatic,
|
|
246
|
+
isPrerender,
|
|
209
247
|
isProduction: options.isProduction,
|
|
210
248
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
211
249
|
isRscRequest: options.isRscRequest,
|
|
@@ -280,6 +318,7 @@ async function dispatchAppPageInner(options) {
|
|
|
280
318
|
getSourceRoute(sourceRouteIndex) {
|
|
281
319
|
return options.getSourceRoute(sourceRouteIndex);
|
|
282
320
|
},
|
|
321
|
+
interceptState: options.interceptState,
|
|
283
322
|
isRscRequest: options.isRscRequest,
|
|
284
323
|
toInterceptOpts(intercept) {
|
|
285
324
|
return toInterceptOptions(options.interceptionContext, intercept);
|
|
@@ -320,9 +359,10 @@ async function dispatchAppPageInner(options) {
|
|
|
320
359
|
isDynamicRscRequest: options.pprRuntime !== void 0 && options.isRscRequest && options.request.headers.get("Next-Router-Prefetch") !== "1" && options.renderedConcreteUrlPaths?.has(options.cleanPathname) !== true,
|
|
321
360
|
renderFreshPageForCache: async ({ renderDocument }) => {
|
|
322
361
|
const revalidationTarget = await resolveCacheRenderTarget();
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
const
|
|
362
|
+
const revalidationInterceptConfig = revalidationTarget.interceptOpts ? resolveAppPageInterceptSegmentConfig(revalidationTarget.route, revalidationTarget.interceptOpts) : null;
|
|
363
|
+
const revalidationDynamicConfig = revalidationInterceptConfig ? revalidationInterceptConfig.dynamicConfig : options.resolveRouteDynamicConfig?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? dynamicConfig : void 0);
|
|
364
|
+
const revalidationConfigRevalidateSeconds = revalidationInterceptConfig ? revalidationTarget.route === route ? currentRevalidateSeconds : revalidationInterceptConfig.revalidateSeconds : options.resolveRouteRevalidateSeconds?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? currentRevalidateSeconds : null);
|
|
365
|
+
const revalidationRouteRevalidateSeconds = revalidationTarget.route === route ? void 0 : revalidationConfigRevalidateSeconds ?? (revalidationDynamicConfig === "force-static" || revalidationDynamicConfig === "error" || options.isProduction && options.pprRuntime === void 0 && (revalidationInterceptConfig?.isStaticEligible ?? options.resolveRouteStaticEligible(revalidationTarget.route)) ? Infinity : null);
|
|
326
366
|
const revalidationRouteHead = {
|
|
327
367
|
observeSearchParams: revalidationDynamicConfig !== "force-static",
|
|
328
368
|
searchParams: new URLSearchParams(),
|
|
@@ -332,7 +372,7 @@ async function dispatchAppPageInner(options) {
|
|
|
332
372
|
return runAppPageRevalidationContext({
|
|
333
373
|
cleanPathname: options.cleanPathname,
|
|
334
374
|
displayPathname: options.displayPathname,
|
|
335
|
-
currentFetchCacheMode: options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
|
|
375
|
+
currentFetchCacheMode: revalidationInterceptConfig ? revalidationInterceptConfig.fetchCacheMode : options.resolveRouteFetchCacheMode?.(revalidationTarget.route) ?? (revalidationTarget.route === route ? options.fetchCache ?? null : null),
|
|
336
376
|
currentFetchRevalidate: revalidationConfigRevalidateSeconds,
|
|
337
377
|
draftModeSecret: options.draftModeSecret,
|
|
338
378
|
dynamicConfig: revalidationDynamicConfig,
|
|
@@ -459,6 +499,7 @@ async function dispatchAppPageInner(options) {
|
|
|
459
499
|
isDynamicError,
|
|
460
500
|
isForceDynamic,
|
|
461
501
|
isForceStatic,
|
|
502
|
+
isPrerender,
|
|
462
503
|
isProduction: options.isProduction,
|
|
463
504
|
isProgressiveActionRender: options.isProgressiveActionRender === true,
|
|
464
505
|
isRscRequest: options.isRscRequest,
|
|
@@ -475,9 +516,9 @@ async function dispatchAppPageInner(options) {
|
|
|
475
516
|
}
|
|
476
517
|
const fallbackShellResponse = options.pprRuntime ? await options.pprRuntime.tryServe(options, currentRevalidateSeconds, isDraftMode, isForceStatic, isForceDynamic) : null;
|
|
477
518
|
if (fallbackShellResponse) return fallbackShellResponse;
|
|
478
|
-
let
|
|
479
|
-
let
|
|
480
|
-
let
|
|
519
|
+
let interceptConfig = null;
|
|
520
|
+
let isInterceptKnownDynamic = false;
|
|
521
|
+
let isInterceptRequestIndependent = false;
|
|
481
522
|
const renderedRouteHead = {
|
|
482
523
|
observeSearchParams: !isForceStatic,
|
|
483
524
|
searchParams: pageSearchParams,
|
|
@@ -489,26 +530,27 @@ async function dispatchAppPageInner(options) {
|
|
|
489
530
|
};
|
|
490
531
|
const interceptResult = await resolveAppPageIntercept({
|
|
491
532
|
async buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams) {
|
|
492
|
-
|
|
493
|
-
|
|
533
|
+
interceptConfig ??= resolveAppPageInterceptSegmentConfig(interceptRoute, interceptOpts);
|
|
534
|
+
const interceptDynamicConfig = interceptConfig.dynamicConfig;
|
|
535
|
+
if (interceptDynamicConfig === "force-static" || interceptDynamicConfig === "error") {
|
|
494
536
|
const { createStaticGenerationHeadersContext } = await import("./app-static-generation.js");
|
|
495
537
|
setHeadersContext(createStaticGenerationHeadersContext({
|
|
496
538
|
draftModeEnabled: isDraftMode,
|
|
497
539
|
draftModeSecret: options.draftModeSecret,
|
|
498
|
-
dynamicConfig:
|
|
540
|
+
dynamicConfig: interceptDynamicConfig,
|
|
499
541
|
routeKind: "page",
|
|
500
542
|
routePattern: interceptRoute.pattern
|
|
501
543
|
}));
|
|
502
544
|
} else setHeadersContext(requestHeadersContext);
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
setCurrentFetchCacheMode(
|
|
506
|
-
setCurrentFetchRevalidate(
|
|
507
|
-
setCurrentForceDynamicFetchDefault(
|
|
545
|
+
isInterceptKnownDynamic = interceptDynamicConfig === "force-dynamic" || interceptConfig.revalidateSeconds === 0;
|
|
546
|
+
isInterceptRequestIndependent = interceptDynamicConfig === "force-static" || interceptDynamicConfig === "error";
|
|
547
|
+
setCurrentFetchCacheMode(interceptConfig.fetchCacheMode);
|
|
548
|
+
setCurrentFetchRevalidate(interceptConfig.revalidateSeconds);
|
|
549
|
+
setCurrentForceDynamicFetchDefault(interceptDynamicConfig === "force-dynamic");
|
|
508
550
|
return options.buildPageElement(interceptRoute, interceptParams, interceptOpts, interceptSearchParams, {
|
|
509
|
-
isForceStatic:
|
|
510
|
-
observeMetadataSearchParamsAccess:
|
|
511
|
-
observePageSearchParamsAccess:
|
|
551
|
+
isForceStatic: interceptDynamicConfig === "force-static",
|
|
552
|
+
observeMetadataSearchParamsAccess: interceptDynamicConfig !== "force-static",
|
|
553
|
+
observePageSearchParamsAccess: interceptDynamicConfig !== "force-static",
|
|
512
554
|
isUncacheableRender,
|
|
513
555
|
serveStreamingMetadata: placeGeneratedMetadataInBody,
|
|
514
556
|
placeStreamedMetadataInHead: options.renderWholeDocument === true,
|
|
@@ -526,18 +568,20 @@ async function dispatchAppPageInner(options) {
|
|
|
526
568
|
getSourceRoute(sourceRouteIndex) {
|
|
527
569
|
return options.getSourceRoute(sourceRouteIndex);
|
|
528
570
|
},
|
|
571
|
+
interceptState: options.interceptState,
|
|
529
572
|
isRscRequest: options.isRscRequest,
|
|
530
573
|
resolveNavigationParams(sourceRoute, navigationParams, pathname, interceptOpts) {
|
|
531
574
|
return resolveAppPageNavigationParams(sourceRoute, navigationParams, pathname, interceptOpts);
|
|
532
575
|
},
|
|
533
|
-
renderInterceptResponse(sourceRoute, interceptElement) {
|
|
576
|
+
renderInterceptResponse(sourceRoute, interceptElement, navigationParams) {
|
|
534
577
|
const interceptOnError = options.createRscOnErrorHandler(options.cleanPathname, sourceRoute.pattern);
|
|
535
578
|
const interceptStream = options.renderToReadableStream(interceptElement, { onError: interceptOnError });
|
|
536
579
|
const interceptHeaders = new Headers({
|
|
537
580
|
"Content-Type": VINEXT_RSC_CONTENT_TYPE,
|
|
538
581
|
Vary: VINEXT_RSC_VARY_HEADER
|
|
539
582
|
});
|
|
540
|
-
if (
|
|
583
|
+
if (Object.keys(navigationParams).length > 0) interceptHeaders.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(navigationParams)));
|
|
584
|
+
if (!(options.pprRuntime !== void 0 || interceptConfig?.isStaticEligible === true) || isDraftMode || isInterceptKnownDynamic || options.isProduction && !isInterceptRequestIndependent) interceptHeaders.set("Cache-Control", resolveUncacheableCacheControl(options.isProduction));
|
|
541
585
|
mergeMiddlewareResponseHeaders(interceptHeaders, options.middlewareContext.headers);
|
|
542
586
|
applyRscCompatibilityIdHeader(interceptHeaders);
|
|
543
587
|
applyRscDeploymentIdHeader(interceptHeaders);
|
|
@@ -546,11 +590,10 @@ async function dispatchAppPageInner(options) {
|
|
|
546
590
|
headers: interceptHeaders
|
|
547
591
|
});
|
|
548
592
|
},
|
|
549
|
-
async resolveSearchParams(sourceRoute, searchParams) {
|
|
593
|
+
async resolveSearchParams(sourceRoute, searchParams, interceptOpts) {
|
|
550
594
|
await options.ensureRouteLoaded?.(sourceRoute);
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return interceptDynamicConfig === "force-static" ? new URLSearchParams() : searchParams;
|
|
595
|
+
interceptConfig = resolveAppPageInterceptSegmentConfig(sourceRoute, interceptOpts);
|
|
596
|
+
return interceptConfig.dynamicConfig === "force-static" ? new URLSearchParams() : searchParams;
|
|
554
597
|
},
|
|
555
598
|
searchParams: options.searchParams,
|
|
556
599
|
setNavigationContext: options.setNavigationContext,
|
|
@@ -692,7 +735,6 @@ async function dispatchAppPageInner(options) {
|
|
|
692
735
|
return renderPageSpecialError(options, specialError, serveStreamingMetadata, interceptResult.interceptOpts, renderOptions?.isCacheCandidate === true, renderOptions?.caughtDocument, renderedRouteHead);
|
|
693
736
|
},
|
|
694
737
|
renderToReadableStream: options.renderToReadableStream,
|
|
695
|
-
hasCustomGlobalError: options.hasCustomGlobalError,
|
|
696
738
|
prerenderToReadableStream: options.prerenderToReadableStream,
|
|
697
739
|
routePattern: route.pattern,
|
|
698
740
|
scriptNonce: options.scriptNonce,
|
|
@@ -116,24 +116,6 @@ export type BuildPageElementsOptions<TModule extends AppPageModule = AppPageModu
|
|
|
116
116
|
htmlLimitedBots?: string;
|
|
117
117
|
scriptNonce?: string;
|
|
118
118
|
};
|
|
119
|
-
type AppPageNavigationParamModule = {
|
|
120
|
-
default?: unknown;
|
|
121
|
-
};
|
|
122
|
-
type AppPageNavigationParamSlot = {
|
|
123
|
-
default?: AppPageNavigationParamModule | null;
|
|
124
|
-
page?: AppPageNavigationParamModule | null;
|
|
125
|
-
slotPatternParts?: readonly string[] | null;
|
|
126
|
-
slotParamNames?: readonly string[] | null;
|
|
127
|
-
};
|
|
128
|
-
type AppPageNavigationParamRoute = {
|
|
129
|
-
params?: readonly string[] | null;
|
|
130
|
-
slots?: Readonly<Record<string, AppPageNavigationParamSlot>> | null;
|
|
131
|
-
};
|
|
132
|
-
type AppPageNavigationParamInterceptOptions = {
|
|
133
|
-
interceptPage?: unknown;
|
|
134
|
-
interceptParams?: AppPageParams | null;
|
|
135
|
-
interceptSlotKey?: string | null;
|
|
136
|
-
};
|
|
137
119
|
/**
|
|
138
120
|
* Build the App Router element tree for a matched route.
|
|
139
121
|
*
|
|
@@ -151,6 +133,15 @@ type AppPageNavigationParamInterceptOptions = {
|
|
|
151
133
|
* {@link https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-metadata.tsx|create-metadata.tsx}.
|
|
152
134
|
*/
|
|
153
135
|
export declare function buildPageElements<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule>(options: BuildPageElementsOptions<TModule, TErrorModule>): Promise<AppElements>;
|
|
136
|
+
/**
|
|
137
|
+
* The state key of each segment a sibling intercept's levels retain, from the
|
|
138
|
+
* app root down to the segment its element renders, so its Activity lists key
|
|
139
|
+
* like Next.js's for the intercepting route: the marker segment carries its
|
|
140
|
+
* marker, and a dynamic marker segment keys per value. The intercepting
|
|
141
|
+
* route's own layouts and boundaries render inside its page element, so the
|
|
142
|
+
* levels stop above the first of them.
|
|
143
|
+
*/
|
|
144
|
+
export declare function resolveSiblingInterceptSegmentKeys(sourcePageSegments: readonly string[] | null | undefined, routeSegments: readonly string[] | null | undefined, opts: AppPageInterceptOptions | null | undefined, routeParams: AppPageParams, interceptParams: AppPageParams): readonly string[] | null;
|
|
154
145
|
export declare const APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS: readonly [{
|
|
155
146
|
readonly prefix: "(...)";
|
|
156
147
|
readonly levels: number;
|
|
@@ -172,7 +163,5 @@ export declare const APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS: readonly [{
|
|
|
172
163
|
*/
|
|
173
164
|
export declare function resolveInterceptedSlotIdentitySegments(sourcePageSegments: readonly string[] | null | undefined, slotKey: string): readonly AppPageSemanticSegment[] | null;
|
|
174
165
|
export declare function resolveInterceptedSlotSegments(sourcePageSegments: readonly string[] | null | undefined, slotKey: string): readonly string[] | null;
|
|
175
|
-
export declare function resolveSlotParamOverrides(route: AppPageNavigationParamRoute, routePath: string): Readonly<Record<string, AppPageParams>> | null;
|
|
176
|
-
export declare function resolveAppPageNavigationParams(route: AppPageNavigationParamRoute, routeParams: AppPageParams, routePath: string, opts?: AppPageNavigationParamInterceptOptions | null): AppPageParams;
|
|
177
166
|
//#endregion
|
|
178
167
|
export type { AppPageErrorModule, AppPageRouteWiringRoute };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { isPromiseLike } from "../utils/promise.js";
|
|
2
2
|
import { APP_RSC_RENDER_MODE_NAVIGATION } from "./app-rsc-render-mode.js";
|
|
3
|
-
import { matchRoutePattern } from "../routing/route-pattern.js";
|
|
4
3
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
5
4
|
import "./app-elements.js";
|
|
6
|
-
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPagePatternStateKey, resolveAppPageRouteStateKey } from "./app-page-segment-state.js";
|
|
5
|
+
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPagePatternStateKey, resolveAppPageRouteStateKey, resolveAppPageSemanticSegmentStateKey } from "./app-page-segment-state.js";
|
|
7
6
|
import { ErrorBoundary, ForbiddenBoundary, NotFoundBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
8
7
|
import { withUseCacheLayoutMarker, withUseCachePageMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
9
8
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
@@ -12,15 +11,16 @@ import { createAppPageMetadataSearchParamsObserver, makeObservedAppPageSearchPar
|
|
|
12
11
|
import { resolveAppPageBranchParams } from "./app-page-params.js";
|
|
13
12
|
import { collectAppPageSearchParams, hasAppPageDynamicMetadata, prepareAppPageHead, resolveActiveParallelRouteHeadInputs, resolveInterceptLayoutsBesidePage, slotInterceptKeepsSourceHead } from "./app-page-head.js";
|
|
14
13
|
import { createRouteNotFoundHeadPlanOptions, recoverAppPageRouteHead } from "./app-page-http-access-fallback-metadata.js";
|
|
15
|
-
import { ClientPageRoot } from "../shims/client-page-root.js";
|
|
16
14
|
import "./app-rsc-route-matching.js";
|
|
15
|
+
import { resolveSlotParamOverrides } from "./app-page-navigation-params.js";
|
|
17
16
|
import { createAppPageRenderDependency, invokeAppComponent, isAppClientReference, isAppRenderSuspension, isReactOwnedAppComponent, renderAfterAppDependencies } from "./app-render-dependency.js";
|
|
18
17
|
import { sanitizeErrorForClient } from "./app-rsc-errors.js";
|
|
19
18
|
import { resolveAppPageModuleTraceSegment, traceCreateComponentTree, traceGetLayoutOrPageModule } from "./app-page-tracing.js";
|
|
20
19
|
import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath, resolveAppPageLoadingModuleAtOrAbove } from "./app-page-route-wiring.js";
|
|
21
20
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
22
|
-
import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
23
21
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
22
|
+
import { ClientPageRoot } from "../shims/client-page-root.js";
|
|
23
|
+
import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
24
24
|
import { Fragment, Suspense, cache, createElement } from "react";
|
|
25
25
|
//#region src/server/app-page-element-builder.ts
|
|
26
26
|
/**
|
|
@@ -429,6 +429,7 @@ async function buildPageElements(options) {
|
|
|
429
429
|
routePath,
|
|
430
430
|
semanticPageIdentity,
|
|
431
431
|
semanticInterceptionTargetRouteId: opts?.interceptTargetRouteGraphId ?? null,
|
|
432
|
+
siblingInterceptSegmentKeys: isSiblingIntercept ? resolveSiblingInterceptSegmentKeys(sourcePageSegments, route.routeSegments, opts, params, effectiveParams) : null,
|
|
432
433
|
sourcePageSegments,
|
|
433
434
|
rootNotFoundModule: rootNotFoundModule ?? null,
|
|
434
435
|
rootForbiddenModule: rootForbiddenModule ?? null,
|
|
@@ -451,9 +452,9 @@ async function buildPageElements(options) {
|
|
|
451
452
|
* slot-scoped params, which `app-page-route-wiring` then hands to the
|
|
452
453
|
* slot page instead of the route's matched params.
|
|
453
454
|
*
|
|
454
|
-
* `routePath` is the already-normalized request pathname (basePath stripped
|
|
455
|
-
*
|
|
456
|
-
*
|
|
455
|
+
* `routePath` is the already-normalized request pathname (basePath stripped).
|
|
456
|
+
* Re-parsing `request.url` here would re-introduce the basePath and silently
|
|
457
|
+
* break the match for any app that configures one.
|
|
457
458
|
*/
|
|
458
459
|
function buildSlotOverrides(route, routeParams, routePath, opts, interceptMetadataOutlet) {
|
|
459
460
|
const overrides = {};
|
|
@@ -487,6 +488,37 @@ function buildSlotOverrides(route, routeParams, routePath, opts, interceptMetada
|
|
|
487
488
|
}
|
|
488
489
|
return Object.keys(overrides).length > 0 ? overrides : null;
|
|
489
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* The state key of each segment a sibling intercept's levels retain, from the
|
|
493
|
+
* app root down to the segment its element renders, so its Activity lists key
|
|
494
|
+
* like Next.js's for the intercepting route: the marker segment carries its
|
|
495
|
+
* marker, and a dynamic marker segment keys per value. The intercepting
|
|
496
|
+
* route's own layouts and boundaries render inside its page element, so the
|
|
497
|
+
* levels stop above the first of them.
|
|
498
|
+
*/
|
|
499
|
+
function resolveSiblingInterceptSegmentKeys(sourcePageSegments, routeSegments, opts, routeParams, interceptParams) {
|
|
500
|
+
if (!sourcePageSegments || !routeSegments) return null;
|
|
501
|
+
const markerIndex = sourcePageSegments.findIndex((segment) => APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS.some(({ prefix }) => segment.startsWith(prefix)));
|
|
502
|
+
if (markerIndex < 0) return null;
|
|
503
|
+
if (routeSegments.length !== markerIndex || routeSegments.some((segment, index) => segment !== sourcePageSegments[index])) return null;
|
|
504
|
+
const branchTreePositions = [
|
|
505
|
+
...(opts?.interceptLayouts ?? []).flatMap((layoutModule, index) => layoutModule?.default ? [opts?.interceptLayoutSegments?.[index]?.length ?? 0] : []),
|
|
506
|
+
...opts?.interceptLoadingTreePositions ?? [],
|
|
507
|
+
...opts?.interceptNotFoundTreePositions ?? [],
|
|
508
|
+
...opts?.interceptForbiddenTreePositions ?? [],
|
|
509
|
+
...opts?.interceptUnauthorizedTreePositions ?? [],
|
|
510
|
+
...opts?.interceptErrorTreePositions ?? []
|
|
511
|
+
];
|
|
512
|
+
const segmentCount = Math.max(markerIndex, Math.min(sourcePageSegments.length, markerIndex + Math.min(...branchTreePositions) - 1));
|
|
513
|
+
return sourcePageSegments.slice(0, segmentCount).map((segment, index) => {
|
|
514
|
+
const marker = index === markerIndex ? APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS.find(({ prefix }) => segment.startsWith(prefix)) : void 0;
|
|
515
|
+
return resolveAppPageSemanticSegmentStateKey({
|
|
516
|
+
marker: marker?.prefix ?? null,
|
|
517
|
+
paramSource: "route",
|
|
518
|
+
segment: marker ? segment.slice(marker.prefix.length) : segment
|
|
519
|
+
}, index < markerIndex ? routeParams : interceptParams);
|
|
520
|
+
});
|
|
521
|
+
}
|
|
490
522
|
const APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS = [
|
|
491
523
|
{
|
|
492
524
|
prefix: "(...)",
|
|
@@ -581,49 +613,5 @@ function resolveInterceptedSlotSegments(sourcePageSegments, slotKey) {
|
|
|
581
613
|
routeSegments.push(...sourcePageSegments.slice(markerIndex + 1).filter(isVisibleInterceptedSlotSegment));
|
|
582
614
|
return routeSegments;
|
|
583
615
|
}
|
|
584
|
-
function resolveSlotParamOverrides(route, routePath) {
|
|
585
|
-
const overrides = {};
|
|
586
|
-
const slots = route.slots;
|
|
587
|
-
if (slots) {
|
|
588
|
-
let urlParts = null;
|
|
589
|
-
const routeParamSet = collectParamNameSet(route.params);
|
|
590
|
-
for (const [slotKey, slot] of Object.entries(slots)) {
|
|
591
|
-
const patternParts = slot.slotPatternParts;
|
|
592
|
-
const paramNames = slot.slotParamNames;
|
|
593
|
-
if (!patternParts || patternParts.length === 0) continue;
|
|
594
|
-
if (paramNames && paramNames.every((name) => routeParamSet.has(name))) continue;
|
|
595
|
-
if (urlParts === null) urlParts = routePath.split("/").filter(Boolean);
|
|
596
|
-
const matched = matchRoutePattern(urlParts, patternParts);
|
|
597
|
-
if (!matched) continue;
|
|
598
|
-
overrides[slotKey] = matched;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
return Object.keys(overrides).length > 0 ? overrides : null;
|
|
602
|
-
}
|
|
603
|
-
function mergeAppPageParams(target, source) {
|
|
604
|
-
for (const [key, value] of Object.entries(source)) target[key] = value;
|
|
605
|
-
}
|
|
606
|
-
function isDefaultExportModule(module) {
|
|
607
|
-
return typeof module === "object" && module !== null;
|
|
608
|
-
}
|
|
609
|
-
function hasDefaultExport(module) {
|
|
610
|
-
if (!isDefaultExportModule(module)) return false;
|
|
611
|
-
return module?.default !== null && module?.default !== void 0;
|
|
612
|
-
}
|
|
613
|
-
function resolveAppPageNavigationParams(route, routeParams, routePath, opts) {
|
|
614
|
-
const navigationParams = { ...routeParams };
|
|
615
|
-
const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
|
|
616
|
-
for (const [slotKey, slot] of Object.entries(route.slots ?? {})) {
|
|
617
|
-
const isInterceptedSlot = opts?.interceptSlotKey === slotKey && opts.interceptSlotKey !== "__vinext_page_intercept" && hasDefaultExport(opts.interceptPage);
|
|
618
|
-
if (!isInterceptedSlot && !hasDefaultExport(slot.page) && !hasDefaultExport(slot.default)) continue;
|
|
619
|
-
mergeAppPageParams(navigationParams, isInterceptedSlot ? opts?.interceptParams ?? routeParams : slotParamOverrides?.[slotKey] ?? routeParams);
|
|
620
|
-
}
|
|
621
|
-
return navigationParams;
|
|
622
|
-
}
|
|
623
|
-
function collectParamNameSet(params) {
|
|
624
|
-
const set = /* @__PURE__ */ new Set();
|
|
625
|
-
if (params) for (const name of params) set.add(name);
|
|
626
|
-
return set;
|
|
627
|
-
}
|
|
628
616
|
//#endregion
|
|
629
|
-
export { APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS, buildPageElements,
|
|
617
|
+
export { APP_PAGE_INTERCEPTION_MARKER_TRAVERSALS, buildPageElements, resolveInterceptedSlotIdentitySegments, resolveInterceptedSlotSegments, resolveSiblingInterceptSegmentKeys };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { VINEXT_RSC_REDIRECT_HEADER, VINEXT_RSC_REDIRECT_TYPE_HEADER } from "./headers.js";
|
|
2
2
|
import { copyLinkHeaderProvenance, getFrameworkLinkHeader, markFrameworkLinkHeaders } from "./app-response-header-provenance.js";
|
|
3
3
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
4
|
-
import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, createRscRedirectLocation } from "./app-rsc-cache-busting.js";
|
|
4
|
+
import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, createRscRedirectLocation, toPathAbsolutePathname } from "./app-rsc-cache-busting.js";
|
|
5
5
|
import { isHTTPAccessFallbackError, isThrownNavigationError } from "../shims/navigation-errors.js";
|
|
6
6
|
import { applyEdgeRuntimeHeader } from "./app-page-response.js";
|
|
7
7
|
import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
|
|
@@ -298,9 +298,11 @@ function toHeaderSafeUrlReference(location) {
|
|
|
298
298
|
* header-safe, so a protocol-relative or scheme-relative target still resolves
|
|
299
299
|
* against the page each client fetched. A relative target resolves against the
|
|
300
300
|
* request's path to a path-only form, which the client resolves against its
|
|
301
|
-
* own origin
|
|
302
|
-
*
|
|
303
|
-
*
|
|
301
|
+
* own origin; a resolved pathname that begins with "//" keeps a "/." prefix
|
|
302
|
+
* so that form stays a path rather than naming another host. Resolving
|
|
303
|
+
* against two placeholder origins tells these apart the way the URL parser
|
|
304
|
+
* does, never depends on the request's origin, and cannot mistake an absolute
|
|
305
|
+
* target naming one placeholder for a relative one.
|
|
304
306
|
*/
|
|
305
307
|
function resolveRedirectTargets(location, requestUrl) {
|
|
306
308
|
try {
|
|
@@ -310,9 +312,10 @@ function resolveRedirectTargets(location, requestUrl) {
|
|
|
310
312
|
headerUrl: toHeaderSafeUrlReference(location)
|
|
311
313
|
};
|
|
312
314
|
const { pathname, search, hash } = first.resolved;
|
|
315
|
+
const target = `${toPathAbsolutePathname(pathname)}${search}${hash}`;
|
|
313
316
|
return {
|
|
314
|
-
digestUrl:
|
|
315
|
-
headerUrl:
|
|
317
|
+
digestUrl: target,
|
|
318
|
+
headerUrl: target
|
|
316
319
|
};
|
|
317
320
|
} catch {
|
|
318
321
|
return {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { FetchCacheMode } from "../shims/fetch-cache-state.js";
|
|
2
|
+
import "../shims/fetch-cache.js";
|
|
3
|
+
//#region src/server/app-page-intercept-segment-config.d.ts
|
|
4
|
+
type SegmentModule = Record<string, unknown>;
|
|
5
|
+
type AppPageInterceptSegmentConfigSlot = {
|
|
6
|
+
configLayouts?: readonly (SegmentModule | null | undefined)[] | null;
|
|
7
|
+
configLayoutTreePositions?: readonly number[] | null;
|
|
8
|
+
default?: SegmentModule | null;
|
|
9
|
+
layout?: SegmentModule | null;
|
|
10
|
+
layoutIndex?: number;
|
|
11
|
+
name?: string;
|
|
12
|
+
ownerTreePosition?: number | null;
|
|
13
|
+
page?: SegmentModule | null;
|
|
14
|
+
routeSegments?: readonly string[] | null;
|
|
15
|
+
};
|
|
16
|
+
/** The parts of the route an interception renders under that its config reads. */
|
|
17
|
+
export type AppPageInterceptSegmentConfigRoute = {
|
|
18
|
+
layouts?: readonly (SegmentModule | null | undefined)[];
|
|
19
|
+
layoutTreePositions?: readonly number[];
|
|
20
|
+
routeSegments?: readonly string[];
|
|
21
|
+
slots?: Readonly<Record<string, AppPageInterceptSegmentConfigSlot>> | null;
|
|
22
|
+
};
|
|
23
|
+
/** The parts of the interception's options its config reads. */
|
|
24
|
+
export type AppPageInterceptSegmentConfigOptions = {
|
|
25
|
+
interceptBranchSegments?: readonly string[] | null;
|
|
26
|
+
interceptLayoutSegments?: readonly (readonly string[])[] | null;
|
|
27
|
+
interceptLayouts?: readonly unknown[] | null;
|
|
28
|
+
interceptPage?: unknown;
|
|
29
|
+
interceptSlotKey: string;
|
|
30
|
+
interceptSourcePageSegments?: readonly string[] | null;
|
|
31
|
+
};
|
|
32
|
+
export type AppPageInterceptSegmentConfig = {
|
|
33
|
+
dynamicConfig: string | undefined;
|
|
34
|
+
dynamicStaleTimeSeconds: number | undefined;
|
|
35
|
+
fetchCacheMode: FetchCacheMode | null;
|
|
36
|
+
/** Whether any segment of the interception exports `generateStaticParams`. */
|
|
37
|
+
hasAnyGenerateStaticParams: boolean;
|
|
38
|
+
/** Whether one sits at or below the interception's last dynamic segment. */
|
|
39
|
+
hasGenerateStaticParams: boolean;
|
|
40
|
+
/** Whether the interception's own segments choose the edge runtime. */
|
|
41
|
+
isEdgeRuntime: boolean;
|
|
42
|
+
isStaticEligible: boolean;
|
|
43
|
+
isStaticGenerationEdgeRuntime: boolean;
|
|
44
|
+
revalidateSeconds: number | null;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Next.js renders an interception as its own route, whose loader tree holds
|
|
48
|
+
* the owner's layouts and the intercepting page, never the source's page, so
|
|
49
|
+
* its segment config comes from those modules alone. A sibling intercept's
|
|
50
|
+
* branch takes the children position below its owner folder; a slot
|
|
51
|
+
* intercept's branch takes its slot, beside the other slots of the owner's
|
|
52
|
+
* layouts, and children renders the owner's default.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveAppPageInterceptSegmentConfig(route: AppPageInterceptSegmentConfigRoute, interceptOpts: AppPageInterceptSegmentConfigOptions): AppPageInterceptSegmentConfig;
|
|
55
|
+
//#endregion
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { collectAppPageStaticGenerationRuntimes, collectAppPageStaticParamsWalkSegments, hasAppPageGenerateStaticParamsAtLastDynamicSegment, isAppPageStaticEligible, isEdgeRuntime, resolveAppPageSegmentConfig, resolveAppPageStaticGenerationRuntime } from "./app-segment-config.js";
|
|
2
|
+
import { SIBLING_PAGE_INTERCEPT_SLOT_KEY } from "./app-rsc-route-matching.js";
|
|
3
|
+
//#region src/server/app-page-intercept-segment-config.ts
|
|
4
|
+
/**
|
|
5
|
+
* Next.js renders an interception as its own route, whose loader tree holds
|
|
6
|
+
* the owner's layouts and the intercepting page, never the source's page, so
|
|
7
|
+
* its segment config comes from those modules alone. A sibling intercept's
|
|
8
|
+
* branch takes the children position below its owner folder; a slot
|
|
9
|
+
* intercept's branch takes its slot, beside the other slots of the owner's
|
|
10
|
+
* layouts, and children renders the owner's default.
|
|
11
|
+
*/
|
|
12
|
+
function resolveAppPageInterceptSegmentConfig(route, interceptOpts) {
|
|
13
|
+
const routeLayouts = route.layouts ?? [];
|
|
14
|
+
const routeSegments = route.routeSegments ?? [];
|
|
15
|
+
const isSiblingIntercept = interceptOpts.interceptSlotKey === SIBLING_PAGE_INTERCEPT_SLOT_KEY;
|
|
16
|
+
const interceptedSlot = isSiblingIntercept ? void 0 : route.slots?.[interceptOpts.interceptSlotKey];
|
|
17
|
+
const branchSegments = interceptOpts.interceptBranchSegments ?? [];
|
|
18
|
+
const interceptLayouts = interceptOpts.interceptLayouts ?? [];
|
|
19
|
+
const interceptLayoutPositions = (interceptOpts.interceptLayoutSegments ?? []).map((segments) => segments.length);
|
|
20
|
+
const ownerPosition = isSiblingIntercept ? interceptOpts.interceptSourcePageSegments ? interceptOpts.interceptSourcePageSegments.length - branchSegments.length : routeSegments.length : interceptedSlot?.ownerTreePosition ?? route.layoutTreePositions?.[interceptedSlot?.layoutIndex ?? -1] ?? routeSegments.length;
|
|
21
|
+
const ownerLayoutIndexes = routeLayouts.flatMap((_, index) => (route.layoutTreePositions?.[index] ?? 0) <= ownerPosition ? [index] : []);
|
|
22
|
+
const ownerLayouts = ownerLayoutIndexes.map((index) => routeLayouts[index]);
|
|
23
|
+
const ownerLayoutPositions = ownerLayoutIndexes.map((index) => route.layoutTreePositions?.[index] ?? 0);
|
|
24
|
+
const ownerSegments = routeSegments.slice(0, ownerPosition);
|
|
25
|
+
const page = interceptOpts.interceptPage;
|
|
26
|
+
const retainedBranches = Object.entries(route.slots ?? {}).flatMap(([slotKey, slot]) => slotKey !== interceptOpts.interceptSlotKey && (slot.ownerTreePosition ?? route.layoutTreePositions?.[slot.layoutIndex ?? 0] ?? 0) <= ownerPosition ? [{
|
|
27
|
+
configLayouts: slot.page ? slot.configLayouts : null,
|
|
28
|
+
configLayoutTreePositions: slot.page ? slot.configLayoutTreePositions : null,
|
|
29
|
+
isDefault: !slot.page,
|
|
30
|
+
layout: slot.page ? slot.layout : null,
|
|
31
|
+
name: slot.name,
|
|
32
|
+
ownerTreePosition: slot.ownerTreePosition,
|
|
33
|
+
page: slot.page ?? slot.default,
|
|
34
|
+
routeSegments: slot.routeSegments
|
|
35
|
+
}] : []);
|
|
36
|
+
const tree = isSiblingIntercept ? {
|
|
37
|
+
layouts: [...ownerLayouts, ...interceptLayouts],
|
|
38
|
+
layoutTreePositions: [...ownerLayoutPositions, ...interceptLayoutPositions.map((position) => ownerPosition + position)],
|
|
39
|
+
page,
|
|
40
|
+
parallelBranches: retainedBranches,
|
|
41
|
+
routeSegments: [...ownerSegments, ...branchSegments]
|
|
42
|
+
} : {
|
|
43
|
+
layouts: ownerLayouts,
|
|
44
|
+
layoutTreePositions: ownerLayoutPositions,
|
|
45
|
+
page: null,
|
|
46
|
+
parallelBranches: [...retainedBranches, {
|
|
47
|
+
configLayouts: interceptLayouts,
|
|
48
|
+
configLayoutTreePositions: interceptLayoutPositions,
|
|
49
|
+
layout: interceptedSlot?.layout,
|
|
50
|
+
name: interceptedSlot?.name,
|
|
51
|
+
ownerTreePosition: ownerPosition,
|
|
52
|
+
page,
|
|
53
|
+
routeSegments: branchSegments
|
|
54
|
+
}],
|
|
55
|
+
routeSegments: ownerSegments
|
|
56
|
+
};
|
|
57
|
+
const config = resolveAppPageSegmentConfig({
|
|
58
|
+
layouts: [
|
|
59
|
+
...ownerLayouts,
|
|
60
|
+
...isSiblingIntercept ? [] : [interceptedSlot?.layout],
|
|
61
|
+
...interceptLayouts
|
|
62
|
+
],
|
|
63
|
+
page,
|
|
64
|
+
parallelBranches: retainedBranches,
|
|
65
|
+
parallelPages: retainedBranches.map((branch) => branch.page)
|
|
66
|
+
});
|
|
67
|
+
const walkSegments = collectAppPageStaticParamsWalkSegments(tree);
|
|
68
|
+
const hasGenerateStaticParams = hasAppPageGenerateStaticParamsAtLastDynamicSegment(tree);
|
|
69
|
+
const isDynamicRoute = walkSegments.some((segment) => segment.dynamic);
|
|
70
|
+
const isStaticGenerationEdgeRuntime = isEdgeRuntime(resolveAppPageStaticGenerationRuntime(collectAppPageStaticGenerationRuntimes(tree)));
|
|
71
|
+
return {
|
|
72
|
+
dynamicConfig: config.dynamicConfig,
|
|
73
|
+
dynamicStaleTimeSeconds: config.dynamicStaleTimeSeconds,
|
|
74
|
+
fetchCacheMode: config.fetchCache ?? null,
|
|
75
|
+
hasAnyGenerateStaticParams: walkSegments.some((segment) => segment.generateStaticParams),
|
|
76
|
+
hasGenerateStaticParams,
|
|
77
|
+
isEdgeRuntime: isEdgeRuntime(config.runtime),
|
|
78
|
+
isStaticEligible: isAppPageStaticEligible({
|
|
79
|
+
dynamicConfig: config.dynamicConfig,
|
|
80
|
+
hasGenerateStaticParams,
|
|
81
|
+
isDynamicRoute,
|
|
82
|
+
isStaticGenerationEdgeRuntime,
|
|
83
|
+
revalidateSeconds: config.revalidateSeconds
|
|
84
|
+
}),
|
|
85
|
+
isStaticGenerationEdgeRuntime,
|
|
86
|
+
revalidateSeconds: config.revalidateSeconds
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { resolveAppPageInterceptSegmentConfig };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AppPageParams } from "./app-page-boundary.js";
|
|
2
|
+
//#region src/server/app-page-navigation-params.d.ts
|
|
3
|
+
export type AppPageNavigationParamSlot = {
|
|
4
|
+
__loadDefault?: unknown;
|
|
5
|
+
__loadPage?: unknown;
|
|
6
|
+
default?: unknown;
|
|
7
|
+
page?: unknown;
|
|
8
|
+
slotPatternParts?: readonly string[] | null;
|
|
9
|
+
slotParamNames?: readonly string[] | null;
|
|
10
|
+
};
|
|
11
|
+
type AppPageNavigationParamRoute = {
|
|
12
|
+
params?: readonly string[] | null;
|
|
13
|
+
slots?: Readonly<Record<string, AppPageNavigationParamSlot>> | null;
|
|
14
|
+
};
|
|
15
|
+
type AppPageNavigationParamInterceptOptions = {
|
|
16
|
+
interceptPage?: unknown;
|
|
17
|
+
interceptParams?: AppPageParams | null;
|
|
18
|
+
interceptSlotKey?: string | null;
|
|
19
|
+
};
|
|
20
|
+
export declare function resolveSlotParamOverrides(route: AppPageNavigationParamRoute, routePath: string): Readonly<Record<string, AppPageParams>> | null;
|
|
21
|
+
export declare function resolveAppPageNavigationParams(route: AppPageNavigationParamRoute, routeParams: AppPageParams, routePath: string, opts?: AppPageNavigationParamInterceptOptions | null): AppPageParams;
|
|
22
|
+
//#endregion
|
|
23
|
+
export {};
|