vinext 1.4.1 → 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 +1 -1
- package/dist/build/action-owner-manifest.js +1 -0
- package/dist/check.js +1 -1
- package/dist/config/config-matchers.js +2 -2
- package/dist/config/destination-params.js +5 -2
- package/dist/config/next-config.d.ts +16 -1
- package/dist/config/next-config.js +31 -1
- package/dist/entries/app-rsc-entry.js +41 -18
- package/dist/entries/app-rsc-manifest.js +4 -0
- package/dist/entries/pages-server-entry.js +2 -0
- package/dist/index.js +15 -12
- 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/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 +3 -5
- package/dist/server/app-action-forwarding.js +3 -1
- package/dist/server/app-browser-entry.js +21 -4
- 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 +38 -16
- package/dist/server/app-page-boundary-render.js +2 -2
- package/dist/server/app-page-cache-render.js +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +73 -30
- package/dist/server/app-page-element-builder.d.ts +9 -20
- package/dist/server/app-page-element-builder.js +37 -49
- 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 -2
- package/dist/server/app-page-render.js +17 -3
- package/dist/server/app-page-request.d.ts +24 -2
- package/dist/server/app-page-request.js +10 -10
- package/dist/server/app-page-route-wiring.d.ts +10 -0
- package/dist/server/app-page-route-wiring.js +16 -12
- 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-response-stage-entry.js +1 -0
- 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-rsc-handler.d.ts +10 -1
- package/dist/server/app-rsc-handler.js +75 -43
- 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-route-matching.d.ts +14 -0
- package/dist/server/app-rsc-route-matching.js +42 -18
- package/dist/server/app-server-action-execution.js +16 -10
- package/dist/server/cache-control.d.ts +2 -0
- package/dist/server/cache-control.js +3 -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 +23 -22
- package/dist/server/image-optimization.js +12 -2
- package/dist/server/metadata-route-response.js +24 -6
- 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-request-pipeline.js +6 -5
- package/dist/server/pages-request-stage-entry.js +1 -0
- package/dist/server/prod-server.js +17 -9
- package/dist/server/request-pipeline.d.ts +5 -0
- package/dist/server/request-pipeline.js +11 -1
- package/dist/server/response-stage-cacheability.d.ts +7 -0
- package/dist/server/response-stage-cacheability.js +6 -5
- 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/image-props.d.ts +6 -0
- package/dist/shims/image-props.js +39 -3
- package/dist/shims/image.js +3 -3
- package/dist/shims/slot.d.ts +3 -0
- package/dist/shims/slot.js +67 -9
- package/dist/utils/base-path.d.ts +7 -0
- package/dist/utils/base-path.js +11 -1
- package/package.json +1 -1
|
@@ -669,9 +669,11 @@ function buildAppPageElements(options) {
|
|
|
669
669
|
branchAccessBoundaries.set(treePosition, entries);
|
|
670
670
|
}
|
|
671
671
|
const branchErrors = /* @__PURE__ */ new Map();
|
|
672
|
-
|
|
672
|
+
const slotErrorModules = !overrideOrPageComponent ? void 0 : hasSlotTreeOverride ? slotOverride?.errorModules : slot.errors;
|
|
673
|
+
const slotErrorTreePositions = hasSlotTreeOverride ? slotOverride?.errorTreePositions : slot.errorTreePositions;
|
|
674
|
+
for (const [index, errorModule] of (slotErrorModules ?? []).entries()) {
|
|
673
675
|
const component = getErrorBoundaryExport(errorModule);
|
|
674
|
-
const treePosition =
|
|
676
|
+
const treePosition = slotErrorTreePositions?.[index];
|
|
675
677
|
if (component && treePosition !== void 0) branchErrors.set(treePosition, component);
|
|
676
678
|
}
|
|
677
679
|
const resolveSlotNotFoundBoundary = (treePosition) => {
|
|
@@ -753,12 +755,6 @@ function buildAppPageElements(options) {
|
|
|
753
755
|
])).filter((treePosition) => !prefetchSlotLoadingEntry || !isOwnedAtRoutePrefetchCutoff && treePosition <= prefetchSlotLoadingEntry.treePosition).sort((left, right) => left - right);
|
|
754
756
|
for (let index = branchTreePositions.length - 1; index >= 0; index--) {
|
|
755
757
|
const treePosition = branchTreePositions[index];
|
|
756
|
-
const nestedBfcacheSegment = nestedBfcacheSegments.find((segment) => segment.treePosition === treePosition);
|
|
757
|
-
if (nestedBfcacheSegment) slotElement = /* @__PURE__ */ jsx(BfcacheSegmentBoundary, {
|
|
758
|
-
id: nestedBfcacheSegment.id,
|
|
759
|
-
stateKey: nestedBfcacheSegment.stateKey,
|
|
760
|
-
children: slotElement
|
|
761
|
-
});
|
|
762
758
|
const loadingComponents = prefetchSlotLoadingEntry ? [] : branchLoadings.get(treePosition) ?? [];
|
|
763
759
|
for (let loadingIndex = loadingComponents.length - 1; loadingIndex >= 0; loadingIndex--) {
|
|
764
760
|
const LoadingComponent = loadingComponents[loadingIndex];
|
|
@@ -786,6 +782,12 @@ function buildAppPageElements(options) {
|
|
|
786
782
|
fallback: SegmentErrorComponent,
|
|
787
783
|
children: slotElement
|
|
788
784
|
});
|
|
785
|
+
const nestedBfcacheSegment = nestedBfcacheSegments.find((segment) => segment.treePosition === treePosition);
|
|
786
|
+
if (nestedBfcacheSegment) slotElement = /* @__PURE__ */ jsx(BfcacheSegmentBoundary, {
|
|
787
|
+
id: nestedBfcacheSegment.id,
|
|
788
|
+
stateKey: nestedBfcacheSegment.stateKey,
|
|
789
|
+
children: slotElement
|
|
790
|
+
});
|
|
789
791
|
const layoutEntriesAtPosition = branchLayouts.get(treePosition) ?? [];
|
|
790
792
|
for (let layoutIndex = layoutEntriesAtPosition.length - 1; layoutIndex >= 0; layoutIndex--) {
|
|
791
793
|
const layoutEntry = layoutEntriesAtPosition[layoutIndex];
|
|
@@ -878,17 +880,19 @@ function buildAppPageElements(options) {
|
|
|
878
880
|
children: routeChildren
|
|
879
881
|
});
|
|
880
882
|
const firstLayoutWithElementTreePosition = layoutEntries.find((entry) => getDefaultExport(entry.layoutModule) !== null)?.treePosition;
|
|
881
|
-
const
|
|
882
|
-
const
|
|
883
|
+
const siblingInterceptSegmentKeys = options.siblingInterceptSegmentKeys ?? null;
|
|
884
|
+
const keepsSegmentLevelLists = String(process.env.__NEXT_CACHE_COMPONENTS) === "true" && firstLayoutWithElementTreePosition !== void 0 && !options.route.childrenSlot?.synthetic && (options.semanticPageIdentity === void 0 || siblingInterceptSegmentKeys !== null);
|
|
885
|
+
const spineSegmentCount = siblingInterceptSegmentKeys?.length ?? routeSegments.length;
|
|
886
|
+
const spineTreePositions = keepsSegmentLevelLists ? Array.from(/* @__PURE__ */ new Set([...orderedTreePositions, ...Array.from({ length: Math.max(0, spineSegmentCount - firstLayoutWithElementTreePosition) }, (_, offset) => firstLayoutWithElementTreePosition + 1 + offset)])).sort((left, right) => left - right) : orderedTreePositions;
|
|
883
887
|
const renderedTreePositions = isPrefetchLoadingShell ? spineTreePositions.filter(includesPrefetchTreePosition) : spineTreePositions;
|
|
884
888
|
const firstLayoutBelowShell = keepsSegmentLevelLists && isPrefetchLoadingShell ? layoutEntries.find((entry) => !includesPrefetchTreePosition(entry.treePosition) && getDefaultExport(entry.layoutModule) !== null) : void 0;
|
|
885
889
|
let childSegmentElementId = firstLayoutBelowShell?.id ?? pageElementId;
|
|
886
|
-
let childSegmentTreePosition = firstLayoutBelowShell?.treePosition ??
|
|
890
|
+
let childSegmentTreePosition = firstLayoutBelowShell?.treePosition ?? spineSegmentCount + 1;
|
|
887
891
|
const retainChildSegment = (treePosition, children) => treePosition === childSegmentTreePosition - 1 ? /* @__PURE__ */ jsx(BfcacheChildrenBoundary, {
|
|
888
892
|
id: childSegmentElementId,
|
|
889
893
|
children
|
|
890
894
|
}) : /* @__PURE__ */ jsx(BfcacheChildrenBoundary, {
|
|
891
|
-
stateKey: createBfcacheChildSegmentStateKey(resolveAppPageTemplateStateKey(routeSegments, treePosition, options.matchedParams)),
|
|
895
|
+
stateKey: createBfcacheChildSegmentStateKey(siblingInterceptSegmentKeys ? JSON.stringify(siblingInterceptSegmentKeys.slice(0, treePosition + 1)) : resolveAppPageTemplateStateKey(routeSegments, treePosition, options.matchedParams)),
|
|
892
896
|
children
|
|
893
897
|
});
|
|
894
898
|
for (let index = renderedTreePositions.length - 1; index >= 0; index--) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
2
2
|
import "./app-elements.js";
|
|
3
3
|
import { createNestedBfcacheSlotSegmentId, deriveBfcacheSegmentIdentity } from "./bfcache-identity.js";
|
|
4
|
-
import { resolveAppPageRouteStateKey, resolveAppPageSemanticSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
|
|
4
|
+
import { APP_PAGE_DEFAULT_SEGMENT_KEY, APP_PAGE_SEGMENT_KEY, resolveAppPageRouteStateKey, resolveAppPageSemanticSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
|
|
5
5
|
//#region src/server/app-page-segment-plan.ts
|
|
6
6
|
function requireGraphSequenceId(ids, index, kind) {
|
|
7
7
|
const id = ids[index];
|
|
@@ -118,6 +118,14 @@ function createAppPageSegmentPlan(options) {
|
|
|
118
118
|
treePosition
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
|
+
if (semanticSegments.length > 0) {
|
|
122
|
+
const leafKey = slotBinding.state === "default" ? APP_PAGE_DEFAULT_SEGMENT_KEY : APP_PAGE_SEGMENT_KEY;
|
|
123
|
+
semanticSegments.push({
|
|
124
|
+
identityKey: JSON.stringify([...boundSegmentKeys, leafKey]),
|
|
125
|
+
stateKey: leafKey,
|
|
126
|
+
treePosition: branchSegments.length
|
|
127
|
+
});
|
|
128
|
+
}
|
|
121
129
|
}
|
|
122
130
|
const includedInPayload = options.includeSlot(ownerTreePosition, targetTreePosition);
|
|
123
131
|
const graphId = graphIds ? graphIds.slots[slotKey] : slot.id ?? slotId;
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
2
2
|
//#region src/server/app-page-segment-state.d.ts
|
|
3
3
|
export declare const APP_PAGE_SEGMENT_KEY = "__PAGE__";
|
|
4
|
+
export declare const APP_PAGE_DEFAULT_SEGMENT_KEY = "__DEFAULT__";
|
|
4
5
|
export declare function isAppPageRouteGroupSegment(segment: string): boolean;
|
|
5
6
|
export declare function canonicalizeAppPageParams(params: AppPageParams): void;
|
|
7
|
+
/**
|
|
8
|
+
* Rebinds segment state keys and BFCache identities resolved with one set of
|
|
9
|
+
* params to another. Keys are JSON arrays of segment keys, nested to any
|
|
10
|
+
* depth, so each whole segment key is compared with the param tokens
|
|
11
|
+
* `resolveSingleSegmentStateKey` produced for the learned params; only those
|
|
12
|
+
* whose value differs are replaced. Returns null when no token changes.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createAppPageSegmentStateKeyRebinder(fromParams: AppPageParams, toParams: AppPageParams): ((stateKey: string) => string) | null;
|
|
6
15
|
export declare function resolveAppPageChildSegments(routeSegments: readonly string[], treePosition: number, params: AppPageParams): string[];
|
|
7
16
|
export declare function resolveAppPageSegmentStateKey(routeSegments: readonly string[], treePosition: number, params: AppPageParams): string;
|
|
8
17
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isCatchAllSegment, isOptionalCatchAllSegment } from "../routing/utils.js";
|
|
2
2
|
//#region src/server/app-page-segment-state.ts
|
|
3
3
|
const APP_PAGE_SEGMENT_KEY = "__PAGE__";
|
|
4
|
+
const APP_PAGE_DEFAULT_SEGMENT_KEY = "__DEFAULT__";
|
|
4
5
|
function isDynamicSegment(segment) {
|
|
5
6
|
return segment.startsWith("[") && segment.endsWith("]") && !segment.includes(".");
|
|
6
7
|
}
|
|
@@ -49,6 +50,58 @@ function resolveSingleSegmentStateKey(segment, params) {
|
|
|
49
50
|
if (!param) return segment;
|
|
50
51
|
return `${param.name}|${formatSegmentStateParamValue(param, params, segment)}|${param.type}`;
|
|
51
52
|
}
|
|
53
|
+
const SEGMENT_PARAM_TYPES = [
|
|
54
|
+
"d",
|
|
55
|
+
"c",
|
|
56
|
+
"oc"
|
|
57
|
+
];
|
|
58
|
+
function formatSegmentParamPattern(param) {
|
|
59
|
+
if (param.type === "oc") return `[[...${param.name}]]`;
|
|
60
|
+
if (param.type === "c") return `[...${param.name}]`;
|
|
61
|
+
return `[${param.name}]`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Rebinds segment state keys and BFCache identities resolved with one set of
|
|
65
|
+
* params to another. Keys are JSON arrays of segment keys, nested to any
|
|
66
|
+
* depth, so each whole segment key is compared with the param tokens
|
|
67
|
+
* `resolveSingleSegmentStateKey` produced for the learned params; only those
|
|
68
|
+
* whose value differs are replaced. Returns null when no token changes.
|
|
69
|
+
*/
|
|
70
|
+
function createAppPageSegmentStateKeyRebinder(fromParams, toParams) {
|
|
71
|
+
const tokens = /* @__PURE__ */ new Map();
|
|
72
|
+
for (const name of /* @__PURE__ */ new Set([...Object.keys(fromParams), ...Object.keys(toParams)])) for (const type of SEGMENT_PARAM_TYPES) {
|
|
73
|
+
const param = {
|
|
74
|
+
name,
|
|
75
|
+
type
|
|
76
|
+
};
|
|
77
|
+
const fallbackSegment = formatSegmentParamPattern(param);
|
|
78
|
+
const from = formatSegmentStateParamValue(param, fromParams, fallbackSegment);
|
|
79
|
+
const to = formatSegmentStateParamValue(param, toParams, fallbackSegment);
|
|
80
|
+
if (from !== to) tokens.set(`${name}|${from}|${type}`, `${name}|${to}|${type}`);
|
|
81
|
+
}
|
|
82
|
+
if (tokens.size === 0) return null;
|
|
83
|
+
const rebind = (stateKey) => {
|
|
84
|
+
const token = tokens.get(stateKey);
|
|
85
|
+
if (token !== void 0) return token;
|
|
86
|
+
if (!stateKey.startsWith("[")) return stateKey;
|
|
87
|
+
let parts;
|
|
88
|
+
try {
|
|
89
|
+
parts = JSON.parse(stateKey);
|
|
90
|
+
} catch {
|
|
91
|
+
return stateKey;
|
|
92
|
+
}
|
|
93
|
+
if (!Array.isArray(parts)) return stateKey;
|
|
94
|
+
let changed = false;
|
|
95
|
+
const rebound = parts.map((part) => {
|
|
96
|
+
if (typeof part !== "string") return part;
|
|
97
|
+
const next = rebind(part);
|
|
98
|
+
if (next !== part) changed = true;
|
|
99
|
+
return next;
|
|
100
|
+
});
|
|
101
|
+
return changed ? JSON.stringify(rebound) : stateKey;
|
|
102
|
+
};
|
|
103
|
+
return rebind;
|
|
104
|
+
}
|
|
52
105
|
function resolveAppPageChildSegments(routeSegments, treePosition, params) {
|
|
53
106
|
const rawSegments = routeSegments.slice(treePosition);
|
|
54
107
|
const resolvedSegments = [];
|
|
@@ -104,4 +157,4 @@ function resolveAppPageTemplateStateKey(routeSegments, treePosition, params) {
|
|
|
104
157
|
return statePath.length > 0 ? JSON.stringify(statePath) : "";
|
|
105
158
|
}
|
|
106
159
|
//#endregion
|
|
107
|
-
export { APP_PAGE_SEGMENT_KEY, canonicalizeAppPageParams, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPagePatternStateKey, resolveAppPageRouteStateKey, resolveAppPageSegmentStateKey, resolveAppPageSemanticSegmentStateKey, resolveAppPageTemplateStateKey };
|
|
160
|
+
export { APP_PAGE_DEFAULT_SEGMENT_KEY, APP_PAGE_SEGMENT_KEY, canonicalizeAppPageParams, createAppPageSegmentStateKeyRebinder, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPagePatternStateKey, resolveAppPageRouteStateKey, resolveAppPageSegmentStateKey, resolveAppPageSemanticSegmentStateKey, resolveAppPageTemplateStateKey };
|
|
@@ -58,6 +58,7 @@ async function handleResponseStage(request, env, platformCtx, props, dispatchReq
|
|
|
58
58
|
probeMode: props.cacheability.probeMode,
|
|
59
59
|
rawManifest: __cacheabilityManifest,
|
|
60
60
|
recomposesRequestScopedHeaders: props.kind === "app-page" && props.isRscRequest,
|
|
61
|
+
keepsParamsHeader: props.kind === "app-page" && props.interceptionContext !== null,
|
|
61
62
|
registerCacheAdapters: () => registerConfiguredCacheAdapters(env),
|
|
62
63
|
request,
|
|
63
64
|
representation: props.cacheability.representation,
|
|
@@ -67,6 +67,7 @@ type LazyLoadableSlot = {
|
|
|
67
67
|
loading?: unknown;
|
|
68
68
|
loadings?: readonly unknown[];
|
|
69
69
|
error?: unknown;
|
|
70
|
+
errors?: readonly unknown[];
|
|
70
71
|
notFound?: unknown;
|
|
71
72
|
notFounds?: readonly unknown[];
|
|
72
73
|
__loadPage?: LazyModuleThunk | null;
|
|
@@ -76,6 +77,7 @@ type LazyLoadableSlot = {
|
|
|
76
77
|
__loadLoading?: LazyModuleThunk | null;
|
|
77
78
|
__loadLoadings?: LazyModuleLoaderArray | null;
|
|
78
79
|
__loadError?: LazyModuleThunk | null;
|
|
80
|
+
__loadErrors?: LazyModuleLoaderArray | null;
|
|
79
81
|
__loadNotFound?: LazyModuleThunk | null;
|
|
80
82
|
__loadNotFounds?: LazyModuleLoaderArray | null;
|
|
81
83
|
/** Hydrated only after an intercept matches, not with the slot's base modules. */
|
|
@@ -145,6 +145,7 @@ function ensureAppRouteModulesLoaded(route) {
|
|
|
145
145
|
pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
|
|
146
146
|
pushArrayLoads(loads, slot.loadings, slot.__loadLoadings);
|
|
147
147
|
pushFieldLoad(loads, slot, "error", slot.__loadError);
|
|
148
|
+
pushArrayLoads(loads, slot.errors, slot.__loadErrors);
|
|
148
149
|
pushFieldLoad(loads, slot, "notFound", slot.__loadNotFound);
|
|
149
150
|
pushArrayLoads(loads, slot.notFounds, slot.__loadNotFounds);
|
|
150
151
|
}
|
|
@@ -6,6 +6,7 @@ import { ExecutionContextLike } from "../shims/request-context.js";
|
|
|
6
6
|
import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware.js";
|
|
7
7
|
import { RootParams } from "../shims/root-params.js";
|
|
8
8
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
9
|
+
import { AppPageNavigationParamSlot } from "./app-page-navigation-params.js";
|
|
9
10
|
import { PagesRouteDataKind } from "./pages-route-data-kind.js";
|
|
10
11
|
import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
|
|
11
12
|
import { TrustedPrerenderState } from "./prerender-route-params.js";
|
|
@@ -41,9 +42,17 @@ export type AppRscHandlerRoute = {
|
|
|
41
42
|
rootParamNames?: readonly string[];
|
|
42
43
|
routeHandler?: unknown;
|
|
43
44
|
routeSegments: readonly string[];
|
|
44
|
-
slots?: AppRouteTreePrefetchRoute["slots"];
|
|
45
|
+
slots?: Readonly<Record<string, NonNullable<AppRouteTreePrefetchRoute["slots"]>[string] & AppPageNavigationParamSlot>> | null;
|
|
45
46
|
};
|
|
46
47
|
type AppRscRouteMatch<TRoute> = {
|
|
48
|
+
/**
|
|
49
|
+
* For an interception match, the source route and params the interception
|
|
50
|
+
* context names, when they differ from the rendered `route` and `params`:
|
|
51
|
+
* a sibling intercept opened from a deeper source renders the intercepting
|
|
52
|
+
* route itself, while the deeper source is what gets authorized.
|
|
53
|
+
*/
|
|
54
|
+
authorizationParams?: AppPageParams;
|
|
55
|
+
authorizationRoute?: TRoute;
|
|
47
56
|
interceptionSourceIsConcrete?: boolean;
|
|
48
57
|
params: AppPageParams;
|
|
49
58
|
route: TRoute;
|
|
@@ -4,11 +4,11 @@ import { PRERENDER_REVALIDATE_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROU
|
|
|
4
4
|
import { buildRequestHeadersFromMiddlewareResponse, hasMiddlewareRequestHeaderOverrides } from "../utils/middleware-request-headers.js";
|
|
5
5
|
import { requestContextFromRequest } from "../config/request-context.js";
|
|
6
6
|
import { isExternalUrl } from "../utils/external-url.js";
|
|
7
|
-
import {
|
|
7
|
+
import { hasBasePath, restoreBasePath, stripBasePath } from "../utils/base-path.js";
|
|
8
8
|
import "./app-rsc-vary.js";
|
|
9
9
|
import { ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_REWRITTEN_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
|
|
10
10
|
import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
11
|
-
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute, stripRequestUrlFragment } from "./request-pipeline.js";
|
|
11
|
+
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, hasUrlParserDotSegment, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute, stripRequestUrlFragment } from "./request-pipeline.js";
|
|
12
12
|
import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
|
|
13
13
|
import { normalizePathnameForRouteMatch, normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
14
14
|
import { patternToNextFormat } from "../routing/route-validation.js";
|
|
@@ -18,7 +18,7 @@ import { isInterceptionMatchedUrlPath, normalizePath } from "./normalize-path.js
|
|
|
18
18
|
import { normalizeDefaultLocalePathname, shouldRestoreLocaleRootTrailingSlash } from "./pages-i18n.js";
|
|
19
19
|
import { buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
|
|
20
20
|
import { markRouteCacheabilityDynamic, preserveRouteCacheabilityResponsePolicy } from "../shims/cacheability-classification.js";
|
|
21
|
-
import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders, captureCdnResponsePolicyOverrides, isCdnResponsePolicyHeader, reconcileCdnResponseHeadersAfterOuterPolicy } from "./cache-control.js";
|
|
21
|
+
import { NEVER_CACHE_CONTROL, SERVER_ACTION_CACHE_CONTROL, applyCdnResponseHeaders, captureCdnResponsePolicyOverrides, isCdnResponsePolicyHeader, reconcileCdnResponseHeadersAfterOuterPolicy } from "./cache-control.js";
|
|
22
22
|
import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
|
|
23
23
|
import { getDraftModeCookieHeader, getEffectiveRequestCookieHeader, getHeadersContext, hasEffectiveRequestCookieChanges, headersContextFromRequest, isDraftModeEnabled, isDraftModeRequest, runWithHeadersContext } from "../shims/headers.js";
|
|
24
24
|
import { mergeRewriteQuery } from "../utils/query.js";
|
|
@@ -33,11 +33,13 @@ import { setFrameworkRequestRoute, traceFrameworkRequest } from "./request-traci
|
|
|
33
33
|
import { mergeMiddlewareResponseHeaders, mergeMiddlewareResponseHeadersOntoResponse, withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
|
|
34
34
|
import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestUrl, hasRscCacheBustingSearchParam, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
|
|
35
35
|
import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
36
|
+
import { applyAppRscConfigHeaders, finalizeAppRscResponse, isStreamedActionRedirectResponse, markAppRscResponseConfigHeadersApplied, markStreamedActionRedirectResponse } from "./app-rsc-response-finalizer.js";
|
|
36
37
|
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
|
|
37
38
|
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
38
39
|
import "./app-page-response.js";
|
|
39
40
|
import { parseNextHttpErrorDigest } from "./next-error-digest.js";
|
|
40
41
|
import { isAppRouteHandlerRoute } from "./app-rsc-route-matching.js";
|
|
42
|
+
import { resolveAppPageNavigationParams } from "./app-page-navigation-params.js";
|
|
41
43
|
import { traceAppPageRender } from "./app-page-tracing.js";
|
|
42
44
|
import { normalizeInterceptionContextHeader } from "./app-interception-context-header.js";
|
|
43
45
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
@@ -46,7 +48,6 @@ import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
|
46
48
|
import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
|
|
47
49
|
import { createSharedAppCacheIdentity, createSharedAppPageCacheIdentity, createSharedAppRouteCacheIdentity, createSharedHybridPagesCacheIdentity, isStaticCandidateAppPageDispatch, prepareSharedAppPageDispatch, withoutAppPageDispatchQuery } from "./app-worker-stages.js";
|
|
48
50
|
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
49
|
-
import { applyAppRscConfigHeaders, finalizeAppRscResponse, markAppRscResponseConfigHeadersApplied } from "./app-rsc-response-finalizer.js";
|
|
50
51
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
51
52
|
import { hasPagesPreviewCookie } from "./pages-response-stage.js";
|
|
52
53
|
import { runWithPrerenderWorkUnit } from "./prerender-work-unit-setup.js";
|
|
@@ -132,11 +133,8 @@ function readCacheabilityRequestProjection(options) {
|
|
|
132
133
|
};
|
|
133
134
|
return parsedCacheabilityRequestProjection.manifest;
|
|
134
135
|
}
|
|
135
|
-
function
|
|
136
|
-
return
|
|
137
|
-
const decodedDots = segment.replaceAll(/%2e/gi, ".");
|
|
138
|
-
return decodedDots === "." || decodedDots === "..";
|
|
139
|
-
});
|
|
136
|
+
function isSameInterceptionSource(a, b) {
|
|
137
|
+
return b != null && (a.authorizationRoute ?? a.route) === b.route && haveSamePageParams(a.authorizationParams ?? a.params, b.params);
|
|
140
138
|
}
|
|
141
139
|
function applyMiddlewareContextToResponse(response, middlewareContext, appendToPostConfigLink = false) {
|
|
142
140
|
if (!middlewareContext.headers && middlewareContext.status == null) return response;
|
|
@@ -152,6 +150,27 @@ function applyMiddlewareContextToResponse(response, middlewareContext, appendToP
|
|
|
152
150
|
}));
|
|
153
151
|
}
|
|
154
152
|
/**
|
|
153
|
+
* These headers describe the current routed request, not the shared RSC
|
|
154
|
+
* bytes, so they are composed above a transported response stage: a cache HIT
|
|
155
|
+
* cannot replay another query/path and never loses dynamic params. An
|
|
156
|
+
* intercepted response's params include its target's, which this match lacks,
|
|
157
|
+
* so the response stage keeps them under an interception context, in its
|
|
158
|
+
* cache identity.
|
|
159
|
+
*/
|
|
160
|
+
function withRoutedRscHeaders(response, navigationParams, resolvedUrl, keepsRenderedParams) {
|
|
161
|
+
const headers = new Headers(response.headers);
|
|
162
|
+
if (!keepsRenderedParams || !headers.has("X-Vinext-Params")) {
|
|
163
|
+
if (Object.keys(navigationParams).length > 0) headers.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(navigationParams)));
|
|
164
|
+
else headers.delete(VINEXT_PARAMS_HEADER);
|
|
165
|
+
}
|
|
166
|
+
headers.set(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, encodeURIComponent(resolvedUrl));
|
|
167
|
+
return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
|
|
168
|
+
headers,
|
|
169
|
+
status: response.status,
|
|
170
|
+
statusText: response.statusText
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
155
174
|
* Next.js answers a Link's segment prefetch of a page whose notFound(),
|
|
156
175
|
* forbidden() or unauthorized() it stored with a 200, so its router renders
|
|
157
176
|
* the page's fallback without loading the document. A shared response stage
|
|
@@ -257,10 +276,10 @@ function requestWithoutRscCacheBustingSearchParam(request) {
|
|
|
257
276
|
stripRscCacheBustingSearchParam(url);
|
|
258
277
|
return cloneRequestWithUrl(request, url.toString());
|
|
259
278
|
}
|
|
260
|
-
/** Send a response with
|
|
261
|
-
function withNeverCacheControl(response) {
|
|
279
|
+
/** Send a response with a never-cache policy, rebuilding immutable headers. */
|
|
280
|
+
function withNeverCacheControl(response, cacheControl = NEVER_CACHE_CONTROL) {
|
|
262
281
|
const applyNoStore = (headers) => {
|
|
263
|
-
applyCdnResponseHeaders(headers, { cacheControl
|
|
282
|
+
applyCdnResponseHeaders(headers, { cacheControl });
|
|
264
283
|
};
|
|
265
284
|
let markedResponse = response;
|
|
266
285
|
try {
|
|
@@ -283,6 +302,19 @@ function withUnmatchedRouteCacheControl(response) {
|
|
|
283
302
|
unmatchedRouteResponses.add(markedResponse);
|
|
284
303
|
return markedResponse;
|
|
285
304
|
}
|
|
305
|
+
const serverActionResponses = /* @__PURE__ */ new WeakSet();
|
|
306
|
+
function markServerActionResponse(response) {
|
|
307
|
+
serverActionResponses.add(response);
|
|
308
|
+
return response;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* A fetch action's redirect that streams its target's render keeps the
|
|
312
|
+
* target's policy, as in Next.js. Every other action response is never cached.
|
|
313
|
+
*/
|
|
314
|
+
function withServerActionCacheControl(response) {
|
|
315
|
+
if (isStreamedActionRedirectResponse(response)) return response;
|
|
316
|
+
return withNeverCacheControl(response, SERVER_ACTION_CACHE_CONTROL);
|
|
317
|
+
}
|
|
286
318
|
async function handleAppRscRequest(options, request, preMiddlewareRequestContext, middlewareContext, isDataRequest, isMiddlewareDataRequest, pagesDataRequest, dispatchInternalRequest, allowInternalRscDocumentFallback, dispatchResponseStage, responseStageProbeMode = null, setInterceptionResponseUncacheable = () => {}) {
|
|
287
319
|
const handlerStart = process.env.NODE_ENV !== "production" ? performance.now() : 0;
|
|
288
320
|
if (process.env.NODE_ENV !== "production") {
|
|
@@ -339,7 +371,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
339
371
|
const provesConcreteInterceptionSource = (sourceMatch, sourceContext = interceptionContextHeader) => {
|
|
340
372
|
if (sourceMatch === null) return false;
|
|
341
373
|
if (sourceMatch.interceptionSourceIsConcrete !== void 0) return sourceMatch.interceptionSourceIsConcrete;
|
|
342
|
-
return sourceContext !== null && (options.matchRequestRoute ?? options.matchRoute)(sourceContext)?.route === sourceMatch.route;
|
|
374
|
+
return sourceContext !== null && (options.matchRequestRoute ?? options.matchRoute)(sourceContext)?.route === (sourceMatch.authorizationRoute ?? sourceMatch.route);
|
|
343
375
|
};
|
|
344
376
|
if (provesConcreteInterceptionSource(hadBasePath && hasRawInterceptionContext && interceptionContextHeader !== null ? options.matchInterceptRoute?.(requestPathname, interceptionContextHeader, interceptionIdHeader) ?? null : null)) setInterceptionResponseUncacheable(false);
|
|
345
377
|
if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths" || pathname === "/__vinext/prerender/metadata-routes") {
|
|
@@ -510,16 +542,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
510
542
|
statusText: response.statusText
|
|
511
543
|
});
|
|
512
544
|
}
|
|
513
|
-
|
|
514
|
-
const headers = new Headers(response.headers);
|
|
515
|
-
if (Object.keys(props.params).length > 0) headers.set(VINEXT_PARAMS_HEADER, encodeURIComponent(JSON.stringify(props.params)));
|
|
516
|
-
else headers.delete(VINEXT_PARAMS_HEADER);
|
|
517
|
-
headers.set(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, encodeURIComponent(props.resolvedUrl));
|
|
518
|
-
return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
|
|
519
|
-
headers,
|
|
520
|
-
status: response.status,
|
|
521
|
-
statusText: response.statusText
|
|
522
|
-
}));
|
|
545
|
+
return response;
|
|
523
546
|
} : void 0;
|
|
524
547
|
const responseStageRequest = (stageRequest = request) => {
|
|
525
548
|
const activeHeaders = getHeadersContext()?.headers;
|
|
@@ -629,10 +652,13 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
629
652
|
const isPostRequest = request.method.toUpperCase() === "POST";
|
|
630
653
|
const contentType = request.headers.get("content-type") || "";
|
|
631
654
|
const isProgressiveActionRequest = isPostRequest && !actionId && contentType.startsWith("multipart/form-data");
|
|
632
|
-
const serveImageEndpointIfMatched = () => {
|
|
633
|
-
if (!filesystemRouteEligible || !resolvedPathnameHasBasePath || !isImageOptimizationPath(cleanPathname)) return null;
|
|
655
|
+
const serveImageEndpointIfMatched = async () => {
|
|
656
|
+
if (!filesystemRouteEligible || !resolvedPathnameHasBasePath || !isImageOptimizationPath(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname)) return null;
|
|
634
657
|
const imageUrl = new URL(resolvedUrl, url);
|
|
635
|
-
const imageRedirect = resolveDevImageRedirect(imageUrl, [...options.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...options.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], options.imageConfig?.qualities, {
|
|
658
|
+
const imageRedirect = resolveDevImageRedirect(imageUrl, [...options.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...options.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], options.imageConfig?.qualities, {
|
|
659
|
+
isDev: options.isDev,
|
|
660
|
+
localPatterns: options.imageConfig?.localPatterns
|
|
661
|
+
});
|
|
636
662
|
const middlewareHeaders = new Headers();
|
|
637
663
|
mergeMiddlewareResponseHeaders(middlewareHeaders, middlewareContext.headers);
|
|
638
664
|
if (!imageRedirect) return new Response("Invalid image optimization parameters", {
|
|
@@ -641,12 +667,12 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
641
667
|
});
|
|
642
668
|
const overrideHeaders = middlewareContext.requestHeaders ?? middlewareContext.headers;
|
|
643
669
|
return markImageOptimizationSignal(Response.redirect(new URL(imageRedirect, url.origin).href, 302), {
|
|
644
|
-
middlewareHeaders,
|
|
670
|
+
middlewareHeaders: new Headers(await loadPreHandlerResponseHeaders()),
|
|
645
671
|
requestHeaders: overrideHeaders ? buildRequestHeadersFromMiddlewareResponse(request.headers, overrideHeaders) : null,
|
|
646
672
|
search: imageUrl.search
|
|
647
673
|
});
|
|
648
674
|
};
|
|
649
|
-
const imageEndpointResponse = serveImageEndpointIfMatched();
|
|
675
|
+
const imageEndpointResponse = await serveImageEndpointIfMatched();
|
|
650
676
|
if (imageEndpointResponse) return imageEndpointResponse;
|
|
651
677
|
const metadataRouteResponse = await renderMetadataRouteIfMatched();
|
|
652
678
|
if (metadataRouteResponse) return composeResponseStageResponse(metadataRouteResponse);
|
|
@@ -689,7 +715,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
689
715
|
bypassInterceptionContextCache = true;
|
|
690
716
|
setInterceptionResponseUncacheable(true);
|
|
691
717
|
};
|
|
692
|
-
if (interceptionSourceMatch !== null && interceptionContextHeader !== null && interceptionSourcePathname !== null && !(interceptionSourceMatch
|
|
718
|
+
if (interceptionSourceMatch !== null && interceptionContextHeader !== null && interceptionSourcePathname !== null && !isSameInterceptionSource(interceptionSourceMatch, directPreActionMatch)) {
|
|
693
719
|
const sourceRequestPathname = options.skipTrailingSlashRedirect ? interceptionContextHeader : normalizeTrailingSlashPathname(interceptionContextHeader, options.trailingSlash) ?? interceptionContextHeader;
|
|
694
720
|
const decodedSourceRequestPathname = options.skipTrailingSlashRedirect ? interceptionSourcePathname : normalizeTrailingSlashPathname(interceptionSourcePathname, options.trailingSlash) ?? interceptionSourcePathname;
|
|
695
721
|
const adoptRewrittenInterceptionSource = (rewrittenPathname) => {
|
|
@@ -699,7 +725,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
699
725
|
interceptionSourceContext = rewrittenPathname;
|
|
700
726
|
}
|
|
701
727
|
const rewrittenSourceMatch = options.matchRoute(rewrittenPathname);
|
|
702
|
-
return interceptionSourceMatch !== null &&
|
|
728
|
+
return interceptionSourceMatch !== null && isSameInterceptionSource(interceptionSourceMatch, rewrittenSourceMatch);
|
|
703
729
|
};
|
|
704
730
|
if (configMatchers?.matchRedirect(matchPathname(sourceRequestPathname), options.configRedirects, preMiddlewareRequestContext, currentBasePathState(), dispatchResponseStage ? void 0 : markConditionalRedirectCacheability)) {
|
|
705
731
|
options.clearRequestContext();
|
|
@@ -709,7 +735,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
709
735
|
if (runMiddleware) {
|
|
710
736
|
const sourceUrl = new URL(userlandRequest.url);
|
|
711
737
|
sourceUrl.search = new URL(resolvedUrl, url).search;
|
|
712
|
-
const sourceUrlPathname = resolvedPathnameHasBasePath
|
|
738
|
+
const sourceUrlPathname = resolvedPathnameHasBasePath ? restoreBasePath(sourceRequestPathname, options.basePath) : sourceRequestPathname;
|
|
713
739
|
sourceUrl.pathname = sourceUrlPathname;
|
|
714
740
|
if (sourceUrl.pathname !== sourceUrlPathname) {
|
|
715
741
|
options.clearRequestContext();
|
|
@@ -798,7 +824,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
798
824
|
}
|
|
799
825
|
return !didRewriteSource || adoptRewrittenInterceptionSource(sourceRulesPathname);
|
|
800
826
|
};
|
|
801
|
-
if (!rewriteSource(options.configRewrites.beforeFiles, false) || interceptionSourceMatch.route.isDynamic && !rewriteSource(options.configRewrites.afterFiles, true)) {
|
|
827
|
+
if (!rewriteSource(options.configRewrites.beforeFiles, false) || (interceptionSourceMatch.authorizationRoute ?? interceptionSourceMatch.route).isDynamic && !rewriteSource(options.configRewrites.afterFiles, true)) {
|
|
802
828
|
options.clearRequestContext();
|
|
803
829
|
return notFoundResponse();
|
|
804
830
|
}
|
|
@@ -844,7 +870,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
844
870
|
const handleServerAction = async (routeMatch, routePathname) => {
|
|
845
871
|
if (!filesystemRouteEligible || !isPostRequest || !actionId) return null;
|
|
846
872
|
if (routeMatch && isAppRouteHandlerRoute(routeMatch.route)) return null;
|
|
847
|
-
if (!options.handleServerActionRequest) return createMissingServerActionResponse(options, actionId);
|
|
873
|
+
if (!options.handleServerActionRequest) return markServerActionResponse(createMissingServerActionResponse(options, actionId));
|
|
848
874
|
const sourceConfigHeaders = new Headers();
|
|
849
875
|
await applyAppRscConfigHeaders(sourceConfigHeaders, request, {
|
|
850
876
|
basePath: options.basePath,
|
|
@@ -855,7 +881,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
855
881
|
recordCacheability: dispatchResponseStage === void 0,
|
|
856
882
|
requestContext: preMiddlewareRequestContext
|
|
857
883
|
});
|
|
858
|
-
|
|
884
|
+
const serverActionResponse = await options.handleServerActionRequest({
|
|
859
885
|
actionId,
|
|
860
886
|
cleanPathname,
|
|
861
887
|
contentType,
|
|
@@ -871,13 +897,14 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
871
897
|
sourceConfigHeaders,
|
|
872
898
|
searchParams: getResolvedSearchParams()
|
|
873
899
|
});
|
|
900
|
+
return serverActionResponse && markServerActionResponse(serverActionResponse);
|
|
874
901
|
};
|
|
875
902
|
let progressiveActionHandled = false;
|
|
876
903
|
let progressiveActionFormState = null;
|
|
877
904
|
const handleProgressiveAction = async (routeMatch, unrenderedRouteMatch) => {
|
|
878
905
|
if (!filesystemRouteEligible || !isProgressiveActionRequest) return null;
|
|
879
906
|
if (routeMatch && isAppRouteHandlerRoute(routeMatch.route)) return null;
|
|
880
|
-
if (!options.handleProgressiveActionRequest) return unrenderedRouteMatch?.route.__loadPage && !unrenderedRouteMatch.route.__loadRouteHandler ? createMissingServerActionResponse(options, null) : null;
|
|
907
|
+
if (!options.handleProgressiveActionRequest) return unrenderedRouteMatch?.route.__loadPage && !unrenderedRouteMatch.route.__loadRouteHandler ? markServerActionResponse(createMissingServerActionResponse(options, null)) : null;
|
|
881
908
|
const progressiveActionResult = await options.handleProgressiveActionRequest({
|
|
882
909
|
actionId,
|
|
883
910
|
cleanPathname,
|
|
@@ -886,7 +913,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
886
913
|
request,
|
|
887
914
|
routeMatch
|
|
888
915
|
});
|
|
889
|
-
if (progressiveActionResult instanceof Response) return progressiveActionResult;
|
|
916
|
+
if (progressiveActionResult instanceof Response) return markServerActionResponse(progressiveActionResult);
|
|
890
917
|
if (progressiveActionResult?.kind !== "form-state") return null;
|
|
891
918
|
if ("actionError" in progressiveActionResult && middlewareContext.status === null && progressiveActionHttpFallbackStatus(progressiveActionResult.actionError) === null) middlewareContext.status = 500;
|
|
892
919
|
return progressiveActionResult;
|
|
@@ -1018,7 +1045,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1018
1045
|
filesystemRouteEligible = resolvedPathnameHasBasePath;
|
|
1019
1046
|
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
1020
1047
|
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
1021
|
-
const rewrittenImageEndpointResponse = serveImageEndpointIfMatched();
|
|
1048
|
+
const rewrittenImageEndpointResponse = await serveImageEndpointIfMatched();
|
|
1022
1049
|
if (rewrittenImageEndpointResponse) return rewrittenImageEndpointResponse;
|
|
1023
1050
|
const rewrittenMetadataResponse = await renderMetadataRouteIfMatched();
|
|
1024
1051
|
if (rewrittenMetadataResponse) return composeResponseStageResponse(rewrittenMetadataResponse);
|
|
@@ -1066,7 +1093,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1066
1093
|
filesystemRouteEligible = resolvedPathnameHasBasePath;
|
|
1067
1094
|
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
1068
1095
|
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
1069
|
-
const rewrittenImageEndpointResponse = serveImageEndpointIfMatched();
|
|
1096
|
+
const rewrittenImageEndpointResponse = await serveImageEndpointIfMatched();
|
|
1070
1097
|
if (rewrittenImageEndpointResponse) return rewrittenImageEndpointResponse;
|
|
1071
1098
|
const rewrittenMetadataResponse = await renderMetadataRouteIfMatched();
|
|
1072
1099
|
if (rewrittenMetadataResponse) return composeResponseStageResponse(rewrittenMetadataResponse);
|
|
@@ -1088,7 +1115,10 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1088
1115
|
if (interceptionCacheProofInvalidated && interceptionSourceContext !== null) {
|
|
1089
1116
|
const finalInterceptionTargetPathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
|
|
1090
1117
|
const finalInterceptionSourceMatch = filesystemRouteEligible && match !== null ? options.matchInterceptRoute?.(finalInterceptionTargetPathname, interceptionSourceContext, interceptionIdHeader) ?? null : null;
|
|
1091
|
-
const hasVerifiedFinalInterceptionSource = hasVerifiedInterceptionSource && interceptionSourceMatch !== null && provesConcreteInterceptionSource(finalInterceptionSourceMatch) && finalInterceptionSourceMatch
|
|
1118
|
+
const hasVerifiedFinalInterceptionSource = hasVerifiedInterceptionSource && interceptionSourceMatch !== null && provesConcreteInterceptionSource(finalInterceptionSourceMatch) && finalInterceptionSourceMatch !== null && finalInterceptionSourceMatch.route === interceptionSourceMatch.route && haveSamePageParams(finalInterceptionSourceMatch.params, interceptionSourceMatch.params) && isSameInterceptionSource(finalInterceptionSourceMatch, {
|
|
1119
|
+
params: interceptionSourceMatch.authorizationParams ?? interceptionSourceMatch.params,
|
|
1120
|
+
route: interceptionSourceMatch.authorizationRoute ?? interceptionSourceMatch.route
|
|
1121
|
+
});
|
|
1092
1122
|
if (interceptionIdHeader !== null && !hasVerifiedFinalInterceptionSource) {
|
|
1093
1123
|
options.clearRequestContext();
|
|
1094
1124
|
setInterceptionResponseUncacheable(true);
|
|
@@ -1291,7 +1321,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1291
1321
|
routePattern: route.pattern,
|
|
1292
1322
|
routePathname: responseStageRoutePathname,
|
|
1293
1323
|
scriptNonce: scriptNonce ?? null
|
|
1294
|
-
}).then(composeResponseStageResponse) : await options.dispatchMatchedPage({
|
|
1324
|
+
}).then((response) => transportedResponseStage && isRscRequest ? withRoutedRscHeaders(response, resolveAppPageNavigationParams(route, params, cleanPathname), resolvedUrl, interceptionSourceContext !== null) : response).then(composeResponseStageResponse) : await options.dispatchMatchedPage({
|
|
1295
1325
|
bypassInterceptionContextCache,
|
|
1296
1326
|
cachePathname,
|
|
1297
1327
|
cleanPathname,
|
|
@@ -1324,7 +1354,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
1324
1354
|
searchParams: resolvedSearchParams,
|
|
1325
1355
|
renderMode
|
|
1326
1356
|
}), isRscRequest && request.headers.get("Next-Router-Prefetch") === "1" && request.headers.has("Next-Router-Segment-Prefetch"));
|
|
1327
|
-
if (progressiveActionFormState) return applyProgressiveActionSideEffects(pageResponse, progressiveActionFormState);
|
|
1357
|
+
if (progressiveActionFormState) return markServerActionResponse(applyProgressiveActionSideEffects(pageResponse, progressiveActionFormState));
|
|
1328
1358
|
return pageResponse;
|
|
1329
1359
|
}
|
|
1330
1360
|
function progressiveActionHttpFallbackStatus(actionError) {
|
|
@@ -1393,7 +1423,7 @@ function createAppRscRequestHandler(options) {
|
|
|
1393
1423
|
let appRequest = rawRequest;
|
|
1394
1424
|
if (pagesDataNormalization?.isDataReq) {
|
|
1395
1425
|
const appRequestUrl = new URL(pagesDataNormalization.request.url);
|
|
1396
|
-
appRequestUrl.pathname =
|
|
1426
|
+
appRequestUrl.pathname = restoreBasePath(appRequestUrl.pathname, options.basePath);
|
|
1397
1427
|
appRequest = cloneRequestWithUrl(pagesDataCandidate, appRequestUrl.toString());
|
|
1398
1428
|
}
|
|
1399
1429
|
const request = cloneRequestWithHeaders(appRequest, filteredHeaders);
|
|
@@ -1436,6 +1466,7 @@ function createAppRscRequestHandler(options) {
|
|
|
1436
1466
|
recordCacheability: dispatchResponseStage === void 0,
|
|
1437
1467
|
requestContext: preMiddlewareRequestContext
|
|
1438
1468
|
});
|
|
1469
|
+
if (serverActionResponses.has(response)) return withServerActionCacheControl(response);
|
|
1439
1470
|
return interceptionResponseUncacheable || unmatchedRouteResponses.has(response) ? withNeverCacheControl(response) : response;
|
|
1440
1471
|
}, {
|
|
1441
1472
|
cacheComponents: options.createPprFallbackShells !== void 0,
|
|
@@ -1448,7 +1479,8 @@ function createAppRscRequestHandler(options) {
|
|
|
1448
1479
|
await closeAfterResponse(requestContext);
|
|
1449
1480
|
throw error;
|
|
1450
1481
|
}
|
|
1451
|
-
|
|
1482
|
+
const closedResponse = closeAfterResponseWithBody(response, requestContext);
|
|
1483
|
+
return isStreamedActionRedirectResponse(response) ? markStreamedActionRedirectResponse(closedResponse) : closedResponse;
|
|
1452
1484
|
};
|
|
1453
1485
|
const appRscHandler = async function appRscHandler(rawRequest, ctx, allowInternalRscDocumentFallback = false, dispatchResponseStage, responseStageProbeMode = null, transportedPrerenderState, detachedTrace = false) {
|
|
1454
1486
|
options.registerCacheAdapters();
|
|
@@ -32,6 +32,9 @@ type FinalizeAppRscResponseOptions = {
|
|
|
32
32
|
};
|
|
33
33
|
/** Mark a response whose final target pipeline has already applied config headers. */
|
|
34
34
|
export declare function markAppRscResponseConfigHeadersApplied(response: Response): Response;
|
|
35
|
+
/** Mark a Server Action redirect that streams its target's render, and so keeps its policy. */
|
|
36
|
+
export declare function markStreamedActionRedirectResponse(response: Response): Response;
|
|
37
|
+
export declare function isStreamedActionRedirectResponse(response: Response): boolean;
|
|
35
38
|
/** Apply only the matching next.config headers for an App Router request. */
|
|
36
39
|
export declare function applyAppRscConfigHeaders(headers: Headers, request: Request, options: FinalizeAppRscResponseOptions): Promise<void>;
|
|
37
40
|
/**
|
|
@@ -25,6 +25,15 @@ function markAppRscResponseConfigHeadersApplied(response) {
|
|
|
25
25
|
configHeadersAlreadyApplied.add(response);
|
|
26
26
|
return response;
|
|
27
27
|
}
|
|
28
|
+
const streamedActionRedirects = /* @__PURE__ */ new WeakSet();
|
|
29
|
+
/** Mark a Server Action redirect that streams its target's render, and so keeps its policy. */
|
|
30
|
+
function markStreamedActionRedirectResponse(response) {
|
|
31
|
+
streamedActionRedirects.add(response);
|
|
32
|
+
return response;
|
|
33
|
+
}
|
|
34
|
+
function isStreamedActionRedirectResponse(response) {
|
|
35
|
+
return streamedActionRedirects.has(response);
|
|
36
|
+
}
|
|
28
37
|
/** Apply only the matching next.config headers for an App Router request. */
|
|
29
38
|
async function applyAppRscConfigHeaders(headers, request, options) {
|
|
30
39
|
if (!HAS_CONFIG_HEADERS || !options.configHeaders.length) return;
|
|
@@ -73,6 +82,7 @@ async function finalizeAppRscResponse(response, request, options) {
|
|
|
73
82
|
if (!response.headers.has("Cache-Control")) {
|
|
74
83
|
applyCdnResponseHeaders(response.headers, { cacheControl: "" });
|
|
75
84
|
captureRouteCacheabilityResponsePolicy(captureCdnResponsePolicyHeaders(response.headers));
|
|
85
|
+
if (isStaticFileSignal(response)) response.headers.delete("Cache-Control");
|
|
76
86
|
}
|
|
77
87
|
if (configHeadersAlreadyApplied.has(response)) {
|
|
78
88
|
normalizeExplicitNonCacheablePolicy(response.headers);
|
|
@@ -84,4 +94,4 @@ async function finalizeAppRscResponse(response, request, options) {
|
|
|
84
94
|
return response;
|
|
85
95
|
}
|
|
86
96
|
//#endregion
|
|
87
|
-
export { applyAppRscConfigHeaders, finalizeAppRscResponse, markAppRscResponseConfigHeadersApplied };
|
|
97
|
+
export { applyAppRscConfigHeaders, finalizeAppRscResponse, isStreamedActionRedirectResponse, markAppRscResponseConfigHeadersApplied, markStreamedActionRedirectResponse };
|