vinext 0.2.0 → 1.0.0-beta.0
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 +50 -29
- package/dist/build/client-build-config.d.ts +13 -92
- package/dist/build/client-build-config.js +17 -95
- package/dist/build/css-url-assets.d.ts +3 -1
- package/dist/build/css-url-assets.js +18 -1
- package/dist/build/inject-pregenerated-paths.d.ts +3 -0
- package/dist/build/inject-pregenerated-paths.js +4 -1
- package/dist/build/prerender-paths.d.ts +23 -0
- package/dist/build/prerender-paths.js +296 -0
- package/dist/build/prerender-server-entry.d.ts +1 -0
- package/dist/build/prerender-server-entry.js +49 -0
- package/dist/build/prerender-server-pool.d.ts +44 -0
- package/dist/build/prerender-server-pool.js +194 -0
- package/dist/build/prerender.d.ts +12 -1
- package/dist/build/prerender.js +87 -23
- package/dist/build/run-prerender.js +2 -1
- package/dist/cache/cache-adapters-virtual.d.ts +7 -1
- package/dist/cache/cache-adapters-virtual.js +26 -2
- package/dist/check.d.ts +4 -6
- package/dist/check.js +13 -9
- package/dist/cli.js +34 -54
- package/dist/client/vinext-next-data.d.ts +4 -1
- package/dist/config/config-matchers.js +33 -11
- package/dist/config/next-config.d.ts +36 -6
- package/dist/config/next-config.js +17 -4
- package/dist/config/prerender.d.ts +11 -1
- package/dist/config/prerender.js +19 -1
- package/dist/config/tsconfig-paths.js +5 -1
- package/dist/entries/app-browser-entry.js +5 -1
- package/dist/entries/app-rsc-entry.d.ts +3 -2
- package/dist/entries/app-rsc-entry.js +4 -0
- package/dist/entries/pages-client-entry.js +14 -3
- package/dist/entries/pages-server-entry.js +18 -4
- package/dist/image/image-adapters-virtual.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +549 -152
- package/dist/init-cloudflare.js +12 -3
- package/dist/init-platform.d.ts +10 -1
- package/dist/init-platform.js +78 -12
- package/dist/init.d.ts +11 -3
- package/dist/init.js +129 -31
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/og-assets.js +2 -1
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
- package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
- package/dist/plugins/sass.d.ts +17 -1
- package/dist/plugins/sass.js +74 -1
- package/dist/plugins/styled-jsx.d.ts +16 -0
- package/dist/plugins/styled-jsx.js +149 -0
- package/dist/routing/app-route-graph.js +22 -16
- package/dist/routing/file-matcher.d.ts +8 -1
- package/dist/routing/file-matcher.js +15 -3
- package/dist/server/app-browser-entry.js +44 -14
- package/dist/server/app-browser-navigation-controller.js +5 -2
- package/dist/server/app-browser-server-action-client.js +5 -3
- package/dist/server/app-browser-state.d.ts +1 -0
- package/dist/server/app-browser-state.js +1 -1
- package/dist/server/app-layout-param-observation.d.ts +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +3 -3
- package/dist/server/app-page-cache-render.d.ts +1 -1
- package/dist/server/app-page-cache.js +23 -6
- package/dist/server/app-page-dispatch.d.ts +2 -1
- package/dist/server/app-page-dispatch.js +27 -10
- package/dist/server/app-page-element-builder.js +1 -0
- package/dist/server/app-page-execution.js +2 -1
- package/dist/server/app-page-render-identity.d.ts +1 -0
- package/dist/server/app-page-render-identity.js +2 -1
- package/dist/server/app-page-render.d.ts +3 -1
- package/dist/server/app-page-render.js +67 -16
- package/dist/server/app-page-response.d.ts +7 -0
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-route-wiring.js +3 -3
- package/dist/server/app-page-stream.d.ts +2 -1
- package/dist/server/app-page-stream.js +1 -1
- package/dist/server/app-route-handler-execution.d.ts +1 -1
- package/dist/server/app-route-tree-prefetch.d.ts +43 -0
- package/dist/server/app-route-tree-prefetch.js +187 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +2 -1
- package/dist/server/app-rsc-cache-busting.js +9 -5
- package/dist/server/app-rsc-handler.d.ts +6 -0
- package/dist/server/app-rsc-handler.js +88 -10
- package/dist/server/app-rsc-render-mode.d.ts +3 -5
- package/dist/server/app-rsc-render-mode.js +5 -12
- package/dist/server/app-rsc-request-normalization.d.ts +3 -4
- package/dist/server/app-rsc-request-normalization.js +4 -5
- package/dist/server/app-server-action-execution.js +6 -5
- package/dist/server/app-ssr-entry.js +1 -1
- package/dist/server/cache-control.d.ts +3 -1
- package/dist/server/cache-control.js +13 -1
- package/dist/server/dev-module-runner.js +1 -1
- package/dist/server/dev-origin-check.d.ts +2 -2
- package/dist/server/dev-origin-check.js +2 -2
- package/dist/server/dev-server.d.ts +11 -1
- package/dist/server/dev-server.js +82 -24
- package/dist/server/headers.d.ts +6 -2
- package/dist/server/headers.js +11 -5
- package/dist/server/image-optimization.d.ts +12 -1
- package/dist/server/image-optimization.js +13 -1
- package/dist/server/isr-cache.d.ts +13 -4
- package/dist/server/isr-cache.js +8 -4
- package/dist/server/pages-data-route.d.ts +4 -2
- package/dist/server/pages-data-route.js +18 -4
- package/dist/server/pages-dev-module-url.d.ts +2 -1
- package/dist/server/pages-dev-module-url.js +6 -3
- package/dist/server/pages-node-compat.d.ts +12 -1
- package/dist/server/pages-node-compat.js +50 -1
- package/dist/server/pages-page-data.d.ts +9 -0
- package/dist/server/pages-page-data.js +18 -10
- package/dist/server/pages-page-handler.js +19 -7
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +5 -4
- package/dist/server/pages-request-pipeline.d.ts +8 -6
- package/dist/server/pages-request-pipeline.js +31 -7
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prerender-manifest.d.ts +15 -1
- package/dist/server/prerender-manifest.js +29 -1
- package/dist/server/prod-server.d.ts +10 -7
- package/dist/server/prod-server.js +43 -28
- package/dist/server/request-pipeline.js +1 -1
- package/dist/server/static-file-cache.js +1 -1
- package/dist/shims/cache-handler.js +8 -1
- package/dist/shims/cache.d.ts +1 -1
- package/dist/shims/cache.js +3 -0
- package/dist/shims/cdn-cache.d.ts +2 -7
- package/dist/shims/cdn-cache.js +2 -14
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +77 -52
- package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
- package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
- package/dist/shims/internal/pages-data-target.d.ts +8 -3
- package/dist/shims/internal/pages-data-target.js +9 -4
- package/dist/shims/link.d.ts +1 -1
- package/dist/shims/link.js +179 -42
- package/dist/shims/navigation.d.ts +15 -3
- package/dist/shims/navigation.js +202 -39
- package/dist/shims/request-context.js +18 -0
- package/dist/shims/request-state-types.d.ts +2 -2
- package/dist/shims/router.js +31 -15
- package/dist/shims/unified-request-context.d.ts +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -1
- package/dist/utils/middleware-request-headers.js +1 -1
- package/dist/utils/project.d.ts +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/dist/utils/vite-version.d.ts +4 -12
- package/dist/utils/vite-version.js +39 -21
- package/package.json +31 -13
- package/dist/cloudflare/index.d.ts +0 -3
- package/dist/cloudflare/index.js +0 -3
- package/dist/packages/cloudflare/src/cache/cdn-adapter.runtime.js +0 -102
- package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +0 -126
- package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +0 -435
- package/dist/packages/cloudflare/src/deploy-config.js +0 -150
- package/dist/packages/cloudflare/src/deploy-help.js +0 -55
- package/dist/packages/cloudflare/src/deploy.js +0 -276
- package/dist/packages/cloudflare/src/tpr.d.ts +0 -45
- package/dist/packages/cloudflare/src/tpr.js +0 -561
- package/dist/packages/cloudflare/src/utils/cache-control-metadata.js +0 -20
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createAppRenderDependency, registerAppElementRenderDependencies, renderAfterAppDependencies, renderWithAppDependencyBarrier } from "./app-render-dependency.js";
|
|
2
2
|
import { APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
3
|
-
import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL
|
|
3
|
+
import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "./app-rsc-render-mode.js";
|
|
4
4
|
import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY } from "./app-elements.js";
|
|
5
5
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
6
6
|
import { ErrorBoundary, ForbiddenBoundary, GlobalErrorBoundary, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
@@ -353,7 +353,7 @@ function buildAppPageElements(options) {
|
|
|
353
353
|
children: slotElement
|
|
354
354
|
});
|
|
355
355
|
const slotLoadingComponent = getDefaultExport(slot.loading);
|
|
356
|
-
if (slotLoadingComponent
|
|
356
|
+
if (slotLoadingComponent) slotElement = /* @__PURE__ */ jsx(Suspense, {
|
|
357
357
|
fallback: /* @__PURE__ */ jsx(slotLoadingComponent, {}),
|
|
358
358
|
children: slotElement
|
|
359
359
|
}, slotResetKey);
|
|
@@ -374,7 +374,7 @@ function buildAppPageElements(options) {
|
|
|
374
374
|
else routeChildren = /* @__PURE__ */ jsx(routeLoadingComponent, {});
|
|
375
375
|
else {
|
|
376
376
|
routeChildren = /* @__PURE__ */ jsx(RedirectBoundary, { children: routeChildren });
|
|
377
|
-
if (routeLoadingComponent
|
|
377
|
+
if (routeLoadingComponent) routeChildren = /* @__PURE__ */ jsx(Suspense, {
|
|
378
378
|
fallback: /* @__PURE__ */ jsx(routeLoadingComponent, {}),
|
|
379
379
|
children: routeChildren
|
|
380
380
|
}, routeResetKey);
|
|
@@ -107,7 +107,8 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
107
107
|
value: Promise<ArrayBuffer> | null;
|
|
108
108
|
}; /** Abort signal for a build-time PPR fallback-shell static render. */
|
|
109
109
|
pprFallbackShellSignal?: AbortSignal; /** When true, wait for the full React tree before emitting bytes. */
|
|
110
|
-
waitForAllReady?: boolean; /**
|
|
110
|
+
waitForAllReady?: boolean; /** Override the default shell-error recovery decision passed to handleSsr. */
|
|
111
|
+
fallbackToErrorDocumentOnShellError?: boolean; /** Dev-only: original server error to surface in the browser overlay. */
|
|
111
112
|
initialDevServerError?: unknown;
|
|
112
113
|
/** True when the app supplies a custom global-error.tsx. Disables the
|
|
113
114
|
* default error-document shell fallback so SSR shell errors keep driving
|
|
@@ -68,7 +68,7 @@ async function renderAppPageHtmlStream(options) {
|
|
|
68
68
|
pprFallbackShellSignal: options.pprFallbackShellSignal,
|
|
69
69
|
waitForAllReady: options.waitForAllReady,
|
|
70
70
|
initialDevServerError: options.initialDevServerError,
|
|
71
|
-
fallbackToErrorDocumentOnShellError: options.waitForAllReady !== true && options.hasCustomGlobalError === false,
|
|
71
|
+
fallbackToErrorDocumentOnShellError: options.fallbackToErrorDocumentOnShellError ?? (options.waitForAllReady !== true && options.hasCustomGlobalError === false),
|
|
72
72
|
dynamicStaleTimeSeconds: options.dynamicStaleTimeSeconds,
|
|
73
73
|
getInitialNavigationCacheMetadata: options.getInitialNavigationCacheMetadata
|
|
74
74
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NextI18nConfig } from "../config/next-config.js";
|
|
2
|
-
import { CachedRouteValue } from "../shims/cache-handler.js";
|
|
3
2
|
import { ExecutionContextLike } from "../shims/request-context.js";
|
|
4
3
|
import { NextRequest } from "../shims/server.js";
|
|
4
|
+
import { CachedRouteValue } from "../shims/cache-handler.js";
|
|
5
5
|
import { HeadersAccessPhase } from "../shims/headers.js";
|
|
6
6
|
import { RouteHandlerMiddlewareContext } from "./app-route-handler-response.js";
|
|
7
7
|
import { AppRouteHandlerModule } from "./app-route-handler-policy.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/server/app-route-tree-prefetch.d.ts
|
|
2
|
+
type DynamicParamTypeShort = "d" | "c" | "oc";
|
|
3
|
+
type TreePrefetchParam = {
|
|
4
|
+
type: DynamicParamTypeShort;
|
|
5
|
+
key: null;
|
|
6
|
+
siblings: readonly string[] | null;
|
|
7
|
+
};
|
|
8
|
+
type AppRouteTreePrefetchSlot = {
|
|
9
|
+
configLayouts?: readonly unknown[] | null;
|
|
10
|
+
configLayoutTreePositions?: readonly number[] | null;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
layout?: unknown;
|
|
13
|
+
layoutIndex?: number;
|
|
14
|
+
name: string;
|
|
15
|
+
page?: unknown;
|
|
16
|
+
routeSegments?: readonly string[] | null;
|
|
17
|
+
};
|
|
18
|
+
type AppRouteTreePrefetchRoute = {
|
|
19
|
+
layoutTreePositions?: readonly number[];
|
|
20
|
+
layouts?: readonly unknown[];
|
|
21
|
+
page?: unknown;
|
|
22
|
+
routeSegments: readonly string[];
|
|
23
|
+
slots?: Readonly<Record<string, AppRouteTreePrefetchSlot>> | null;
|
|
24
|
+
};
|
|
25
|
+
type TreePrefetch = {
|
|
26
|
+
name: string;
|
|
27
|
+
param: TreePrefetchParam | null;
|
|
28
|
+
prefetchHints: number;
|
|
29
|
+
slots: null | Record<string, TreePrefetch>;
|
|
30
|
+
};
|
|
31
|
+
type RouteTreePrefetchResponseOptions = {
|
|
32
|
+
buildId?: string | null;
|
|
33
|
+
deploymentId?: string;
|
|
34
|
+
prefetchInlining?: PrefetchInliningConfig;
|
|
35
|
+
};
|
|
36
|
+
type PrefetchInliningConfig = false | {
|
|
37
|
+
maxBundleSize: number;
|
|
38
|
+
maxSize: number;
|
|
39
|
+
};
|
|
40
|
+
declare function isRouteTreePrefetchRequest(request: Request): boolean;
|
|
41
|
+
declare function createRouteTreePrefetchResponse(route: AppRouteTreePrefetchRoute, options?: RouteTreePrefetchResponseOptions): Promise<Response>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { AppRouteTreePrefetchRoute, PrefetchInliningConfig, TreePrefetch, createRouteTreePrefetchResponse, isRouteTreePrefetchRequest };
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
|
|
2
|
+
import { getDeploymentId } from "../utils/deployment-id.js";
|
|
3
|
+
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
4
|
+
//#region src/server/app-route-tree-prefetch.ts
|
|
5
|
+
const PARENT_INLINED_INTO_SELF = 32;
|
|
6
|
+
const INLINED_INTO_CHILD = 64;
|
|
7
|
+
const HEAD_INLINED_INTO_SELF = 128;
|
|
8
|
+
const PAGE_SEGMENT = "__PAGE__";
|
|
9
|
+
const SLOT_SEGMENT = "(__SLOT__)";
|
|
10
|
+
const SEGMENT_INLINE_SIZE = 1;
|
|
11
|
+
const SEGMENT_OUTLINE_SIZE = 4096;
|
|
12
|
+
const DEFAULT_SEGMENT_INLINE_THRESHOLD = 2048;
|
|
13
|
+
const HEAD_INLINE_SIZE = 1;
|
|
14
|
+
const DEFAULT_MAX_INLINE_BUNDLE_SIZE = 10240;
|
|
15
|
+
const NEXT_DID_POSTPONE_HEADER = "x-nextjs-postponed";
|
|
16
|
+
function isRouteTreePrefetchRequest(request) {
|
|
17
|
+
return request.headers.get("RSC") === "1" && request.headers.get("Next-Router-Prefetch") === "1" && request.headers.get("Next-Router-Segment-Prefetch") === "/_tree";
|
|
18
|
+
}
|
|
19
|
+
function createNode(segment, module) {
|
|
20
|
+
const { name, param } = routeTreeSegment(segment);
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
param,
|
|
24
|
+
prefetchSize: estimatePrefetchSize(module) ?? ((module === null || module === void 0) && segment !== PAGE_SEGMENT ? SEGMENT_INLINE_SIZE : null),
|
|
25
|
+
prefetchHints: 0,
|
|
26
|
+
slots: null
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function ensureSlots(node) {
|
|
30
|
+
if (node.slots === null) node.slots = {};
|
|
31
|
+
return node.slots;
|
|
32
|
+
}
|
|
33
|
+
function addChild(node, key, child) {
|
|
34
|
+
ensureSlots(node)[key] = child;
|
|
35
|
+
}
|
|
36
|
+
function routeTreeSegment(segment) {
|
|
37
|
+
if (segment.startsWith(":")) {
|
|
38
|
+
const rest = segment.slice(1);
|
|
39
|
+
if (rest.endsWith("+")) return dynamicRouteTreeSegment(rest.slice(0, -1), "c");
|
|
40
|
+
if (rest.endsWith("*")) return dynamicRouteTreeSegment(rest.slice(0, -1), "oc");
|
|
41
|
+
return dynamicRouteTreeSegment(rest, "d");
|
|
42
|
+
}
|
|
43
|
+
if (segment.startsWith("[[...") && segment.endsWith("]]")) return dynamicRouteTreeSegment(segment.slice(5, -2), "oc");
|
|
44
|
+
if (segment.startsWith("[...") && segment.endsWith("]")) return dynamicRouteTreeSegment(segment.slice(4, -1), "c");
|
|
45
|
+
if (segment.startsWith("[") && segment.endsWith("]")) return dynamicRouteTreeSegment(segment.slice(1, -1), "d");
|
|
46
|
+
return {
|
|
47
|
+
name: segment,
|
|
48
|
+
param: null
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function dynamicRouteTreeSegment(name, type) {
|
|
52
|
+
return {
|
|
53
|
+
name,
|
|
54
|
+
param: {
|
|
55
|
+
key: null,
|
|
56
|
+
siblings: null,
|
|
57
|
+
type
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function explicitPrefetchSize(module) {
|
|
62
|
+
if (typeof module !== "object" || module === null) return null;
|
|
63
|
+
const value = module.prefetchSize;
|
|
64
|
+
if (value === "large") return SEGMENT_OUTLINE_SIZE;
|
|
65
|
+
if (value === "small") return SEGMENT_INLINE_SIZE;
|
|
66
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
67
|
+
}
|
|
68
|
+
function estimatePrefetchSize(module) {
|
|
69
|
+
const explicitSize = explicitPrefetchSize(module);
|
|
70
|
+
if (explicitSize !== null) return explicitSize;
|
|
71
|
+
if (typeof module !== "object" || module === null) return null;
|
|
72
|
+
return typeof module.default === "function" ? SEGMENT_INLINE_SIZE : null;
|
|
73
|
+
}
|
|
74
|
+
function layoutModuleByTreePosition(route) {
|
|
75
|
+
const layouts = route.layouts ?? [];
|
|
76
|
+
const positions = route.layoutTreePositions ?? [];
|
|
77
|
+
const byPosition = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const [index, position] of positions.entries()) byPosition.set(position, layouts[index]);
|
|
79
|
+
return byPosition;
|
|
80
|
+
}
|
|
81
|
+
function modulesByTreePosition(modules, positions) {
|
|
82
|
+
const byPosition = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const [index, position] of (positions ?? []).entries()) byPosition.set(position, modules?.[index]);
|
|
84
|
+
return byPosition;
|
|
85
|
+
}
|
|
86
|
+
async function buildTree(route) {
|
|
87
|
+
const layoutsByPosition = layoutModuleByTreePosition(route);
|
|
88
|
+
const root = createNode("", layoutsByPosition.get(0));
|
|
89
|
+
const nodesByPosition = new Map([[0, root]]);
|
|
90
|
+
let current = root;
|
|
91
|
+
for (const [index, segment] of route.routeSegments.entries()) {
|
|
92
|
+
const position = index + 1;
|
|
93
|
+
const child = createNode(segment, layoutsByPosition.get(position));
|
|
94
|
+
addChild(current, "children", child);
|
|
95
|
+
nodesByPosition.set(position, child);
|
|
96
|
+
current = child;
|
|
97
|
+
}
|
|
98
|
+
addChild(current, "children", createNode(PAGE_SEGMENT, route.page));
|
|
99
|
+
for (const slot of Object.values(route.slots ?? {})) {
|
|
100
|
+
const ownerPosition = slot.layoutIndex === void 0 || slot.layoutIndex < 0 ? route.routeSegments.length : route.layoutTreePositions?.[slot.layoutIndex] ?? route.routeSegments.length;
|
|
101
|
+
const owner = nodesByPosition.get(ownerPosition) ?? current;
|
|
102
|
+
const slotRoot = createNode(SLOT_SEGMENT, slot.layout);
|
|
103
|
+
let slotCurrent = slotRoot;
|
|
104
|
+
const slotConfigLayoutsByPosition = modulesByTreePosition(slot.configLayouts, slot.configLayoutTreePositions);
|
|
105
|
+
const slotRouteSegments = slot.routeSegments ?? [];
|
|
106
|
+
for (const [index, segment] of slotRouteSegments.entries()) {
|
|
107
|
+
const position = index + 1;
|
|
108
|
+
const child = createNode(segment, slotConfigLayoutsByPosition.get(position));
|
|
109
|
+
addChild(slotCurrent, "children", child);
|
|
110
|
+
slotCurrent = child;
|
|
111
|
+
}
|
|
112
|
+
addChild(slotCurrent, "children", createNode(PAGE_SEGMENT, slot.page ?? slot.default));
|
|
113
|
+
addChild(owner, slot.name, slotRoot);
|
|
114
|
+
}
|
|
115
|
+
return root;
|
|
116
|
+
}
|
|
117
|
+
function computePrefetchHints(node, parentGzipSize, headInlineState, config) {
|
|
118
|
+
const currentGzipSize = node.prefetchSize;
|
|
119
|
+
const sizeToInline = currentGzipSize !== null && currentGzipSize < config.maxSize ? currentGzipSize : null;
|
|
120
|
+
let didInlineIntoChild = false;
|
|
121
|
+
let acceptingChildInlinedBytes = 0;
|
|
122
|
+
let smallestChildInlinedBytes = Number.POSITIVE_INFINITY;
|
|
123
|
+
let hasChildren = false;
|
|
124
|
+
for (const child of Object.values(node.slots ?? {})) {
|
|
125
|
+
hasChildren = true;
|
|
126
|
+
const childInlinedBytes = computePrefetchHints(child, didInlineIntoChild ? null : sizeToInline, headInlineState, config);
|
|
127
|
+
if ((child.prefetchHints & PARENT_INLINED_INTO_SELF) !== 0) {
|
|
128
|
+
didInlineIntoChild = true;
|
|
129
|
+
acceptingChildInlinedBytes = childInlinedBytes;
|
|
130
|
+
} else if (!didInlineIntoChild && childInlinedBytes < smallestChildInlinedBytes) smallestChildInlinedBytes = childInlinedBytes;
|
|
131
|
+
}
|
|
132
|
+
if (!hasChildren) smallestChildInlinedBytes = 0;
|
|
133
|
+
let hints = node.prefetchHints;
|
|
134
|
+
if (didInlineIntoChild) hints |= INLINED_INTO_CHILD;
|
|
135
|
+
let inlinedBytes = didInlineIntoChild ? acceptingChildInlinedBytes : smallestChildInlinedBytes;
|
|
136
|
+
const isBundleTerminal = !didInlineIntoChild;
|
|
137
|
+
if (!headInlineState.inlined && isBundleTerminal && node.name === PAGE_SEGMENT && inlinedBytes + HEAD_INLINE_SIZE < config.maxBundleSize) {
|
|
138
|
+
hints |= HEAD_INLINED_INTO_SELF;
|
|
139
|
+
inlinedBytes += HEAD_INLINE_SIZE;
|
|
140
|
+
headInlineState.inlined = true;
|
|
141
|
+
}
|
|
142
|
+
if (parentGzipSize !== null) {
|
|
143
|
+
if (inlinedBytes + parentGzipSize < config.maxBundleSize) {
|
|
144
|
+
hints |= PARENT_INLINED_INTO_SELF;
|
|
145
|
+
inlinedBytes += parentGzipSize;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
node.prefetchHints = hints;
|
|
149
|
+
return inlinedBytes;
|
|
150
|
+
}
|
|
151
|
+
function stripMutableFields(node) {
|
|
152
|
+
const slots = node.slots === null ? null : Object.fromEntries(Object.entries(node.slots).map(([key, child]) => [key, stripMutableFields(child)]));
|
|
153
|
+
return {
|
|
154
|
+
name: node.name,
|
|
155
|
+
param: node.param,
|
|
156
|
+
prefetchHints: node.prefetchHints,
|
|
157
|
+
slots
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function resolvePrefetchInliningConfig(config) {
|
|
161
|
+
if (config) return config;
|
|
162
|
+
return {
|
|
163
|
+
maxBundleSize: DEFAULT_MAX_INLINE_BUNDLE_SIZE,
|
|
164
|
+
maxSize: DEFAULT_SEGMENT_INLINE_THRESHOLD
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function createRouteTreePrefetchResponse(route, options = {}) {
|
|
168
|
+
const tree = await buildTree(route);
|
|
169
|
+
computePrefetchHints(tree, null, { inlined: false }, resolvePrefetchInliningConfig(options.prefetchInlining));
|
|
170
|
+
const headers = new Headers({
|
|
171
|
+
"Cache-Control": "no-store",
|
|
172
|
+
"Content-Type": VINEXT_RSC_CONTENT_TYPE,
|
|
173
|
+
[NEXT_DID_POSTPONE_HEADER]: "2",
|
|
174
|
+
Vary: VINEXT_RSC_VARY_HEADER
|
|
175
|
+
});
|
|
176
|
+
applyRscCompatibilityIdHeader(headers);
|
|
177
|
+
const deploymentId = options.deploymentId ?? getDeploymentId();
|
|
178
|
+
if (deploymentId) headers.set(NEXTJS_DEPLOYMENT_ID_HEADER, deploymentId);
|
|
179
|
+
const payload = {
|
|
180
|
+
tree: stripMutableFields(tree),
|
|
181
|
+
staleTime: -1
|
|
182
|
+
};
|
|
183
|
+
if (options.buildId) payload.buildId = options.buildId;
|
|
184
|
+
return new Response(`0:${JSON.stringify(payload)}\n`, { headers });
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
export { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest };
|
|
@@ -4,8 +4,8 @@ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "../utils/protocol-headers.
|
|
|
4
4
|
import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
5
5
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
6
6
|
import { cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
|
|
7
|
-
import { getImageOptimizer, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
|
|
8
7
|
import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
|
|
8
|
+
import { getImageOptimizer, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
|
|
9
9
|
import { finalizeMissingStaticAssetResponse, resolveStaticAssetSignal } from "./worker-utils.js";
|
|
10
10
|
import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
11
11
|
import rscHandler, { __assetPrefix, __basePath, __imageAllowedWidths, __imageConfig } from "virtual:vinext-rsc-entry";
|
|
@@ -24,6 +24,7 @@ type ResolveInvalidRscCacheBustingRequestOptions = {
|
|
|
24
24
|
};
|
|
25
25
|
declare function getVinextRscCompatibilityId(): string | null;
|
|
26
26
|
declare function applyRscCompatibilityIdHeader(headers: Headers, compatibilityId?: string | null | undefined): void;
|
|
27
|
+
declare function applyRscDeploymentIdHeader(headers: Headers): void;
|
|
27
28
|
declare function isRscCompatibilityIdCompatible(responseCompatibilityId: string | null | undefined, clientCompatibilityId?: string | null | undefined): boolean;
|
|
28
29
|
type RscCompatibilityNavigationDecision = {
|
|
29
30
|
kind: "compatible";
|
|
@@ -61,4 +62,4 @@ declare function createServerActionRequestUrl(href: string): string;
|
|
|
61
62
|
declare function createRscRedirectLocation(location: string, request: Request): Promise<string>;
|
|
62
63
|
declare function resolveInvalidRscCacheBustingRequest(options: ResolveInvalidRscCacheBustingRequestOptions): Promise<Response | null>;
|
|
63
64
|
//#endregion
|
|
64
|
-
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
65
|
+
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
|
|
1
|
+
import { NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
|
|
2
2
|
import { fnv1a64 } from "../utils/hash.js";
|
|
3
3
|
import { parseAppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
4
|
-
import { applyDeploymentIdHeader } from "../utils/deployment-id.js";
|
|
4
|
+
import { applyDeploymentIdHeader, getDeploymentId } from "../utils/deployment-id.js";
|
|
5
5
|
//#region src/server/app-rsc-cache-busting.ts
|
|
6
6
|
/**
|
|
7
7
|
* RSC cache-busting hashes cover the headers that make an RSC payload vary.
|
|
@@ -14,7 +14,6 @@ const VINEXT_RSC_COMPATIBILITY_ID_HEADER = "X-Vinext-RSC-Compatibility-Id";
|
|
|
14
14
|
const VINEXT_RSC_CONTENT_TYPE = "text/x-component";
|
|
15
15
|
const VINEXT_RSC_VARY_HEADER = [
|
|
16
16
|
"RSC",
|
|
17
|
-
"Accept",
|
|
18
17
|
NEXT_ROUTER_STATE_TREE_HEADER,
|
|
19
18
|
NEXT_ROUTER_PREFETCH_HEADER,
|
|
20
19
|
NEXT_ROUTER_SEGMENT_PREFETCH_HEADER,
|
|
@@ -44,6 +43,11 @@ function applyRscCompatibilityIdHeader(headers, compatibilityId = getVinextRscCo
|
|
|
44
43
|
if (normalized) headers.set(VINEXT_RSC_COMPATIBILITY_ID_HEADER, normalized);
|
|
45
44
|
else headers.delete(VINEXT_RSC_COMPATIBILITY_ID_HEADER);
|
|
46
45
|
}
|
|
46
|
+
function applyRscDeploymentIdHeader(headers) {
|
|
47
|
+
const deploymentId = getDeploymentId();
|
|
48
|
+
if (deploymentId) headers.set(NEXTJS_DEPLOYMENT_ID_HEADER, deploymentId);
|
|
49
|
+
else headers.delete(NEXTJS_DEPLOYMENT_ID_HEADER);
|
|
50
|
+
}
|
|
47
51
|
function isRscCompatibilityIdCompatible(responseCompatibilityId, clientCompatibilityId = getVinextRscCompatibilityId()) {
|
|
48
52
|
const normalizedResponseCompatibilityId = normalizeCompatibilityId(responseCompatibilityId);
|
|
49
53
|
const normalizedClientCompatibilityId = normalizeCompatibilityId(clientCompatibilityId);
|
|
@@ -184,7 +188,7 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
184
188
|
const url = new URL(options.request.url);
|
|
185
189
|
const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
|
|
186
190
|
const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);
|
|
187
|
-
if (actualHash === null && expectedHash === "") return null;
|
|
191
|
+
if (actualHash === null && expectedHash === "" && url.pathname.endsWith(".rsc")) return null;
|
|
188
192
|
const acceptedHashes = new Set([expectedHash]);
|
|
189
193
|
if (actualHash !== null && actualHash !== expectedHash) {
|
|
190
194
|
acceptedHashes.add(computeLegacyRscCacheBustingSearchParam(options.request.headers));
|
|
@@ -203,4 +207,4 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
203
207
|
});
|
|
204
208
|
}
|
|
205
209
|
//#endregion
|
|
206
|
-
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
210
|
+
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
@@ -6,6 +6,7 @@ import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware
|
|
|
6
6
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
7
7
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
8
8
|
import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
|
|
9
|
+
import { AppRouteTreePrefetchRoute, PrefetchInliningConfig } from "./app-route-tree-prefetch.js";
|
|
9
10
|
import { ReactFormState } from "react-dom/client";
|
|
10
11
|
|
|
11
12
|
//#region src/server/app-rsc-handler.d.ts
|
|
@@ -24,12 +25,15 @@ type AppRscHandlerRoute = {
|
|
|
24
25
|
__loadPage?: unknown;
|
|
25
26
|
__loadRouteHandler?: unknown;
|
|
26
27
|
isDynamic: boolean;
|
|
28
|
+
layouts?: readonly unknown[];
|
|
29
|
+
layoutTreePositions?: readonly number[];
|
|
27
30
|
params?: readonly string[];
|
|
28
31
|
page?: unknown;
|
|
29
32
|
pattern: string;
|
|
30
33
|
rootParamNames?: readonly string[];
|
|
31
34
|
routeHandler?: unknown;
|
|
32
35
|
routeSegments: readonly string[];
|
|
36
|
+
slots?: AppRouteTreePrefetchRoute["slots"];
|
|
33
37
|
};
|
|
34
38
|
type AppRscRouteMatch<TRoute> = {
|
|
35
39
|
params: AppPageParams;
|
|
@@ -63,6 +67,7 @@ type DispatchMatchedPageOptions<TRoute> = {
|
|
|
63
67
|
staticParamsValidationParams?: AppPageParams;
|
|
64
68
|
rootParams?: RootParams;
|
|
65
69
|
request: Request;
|
|
70
|
+
renderedPathAndSearch?: string | null;
|
|
66
71
|
route: TRoute;
|
|
67
72
|
scriptNonce?: string;
|
|
68
73
|
searchParams: URLSearchParams;
|
|
@@ -189,6 +194,7 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
|
|
|
189
194
|
matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
|
|
190
195
|
runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
|
|
191
196
|
publicFiles: ReadonlySet<string>;
|
|
197
|
+
prefetchInlining?: PrefetchInliningConfig;
|
|
192
198
|
renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;
|
|
193
199
|
renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;
|
|
194
200
|
rootParamNamesByPattern?: RootParamNamesMap;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
|
-
import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "../utils/protocol-headers.js";
|
|
4
|
+
import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
5
5
|
import { ACTION_REVALIDATED_HEADER } from "./headers.js";
|
|
6
6
|
import { isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
7
7
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
@@ -23,6 +23,7 @@ import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } fr
|
|
|
23
23
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
24
24
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
25
25
|
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
26
|
+
import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
|
|
26
27
|
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
27
28
|
import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
|
|
28
29
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
@@ -163,10 +164,10 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
163
164
|
headers: { Location: location }
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
|
-
const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({
|
|
167
|
+
const rscCacheBustingRedirect = hadBasePath ? await resolveInvalidRscCacheBustingRequest({
|
|
167
168
|
isRscRequest,
|
|
168
169
|
request
|
|
169
|
-
});
|
|
170
|
+
}) : null;
|
|
170
171
|
if (rscCacheBustingRedirect) return rscCacheBustingRedirect;
|
|
171
172
|
const normalizedUserlandRequest = requestWithoutRscSuffix(request);
|
|
172
173
|
const userlandRequest = requestWithoutRscCacheBustingSearchParam(normalizedUserlandRequest);
|
|
@@ -200,6 +201,13 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
200
201
|
const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);
|
|
201
202
|
const postMiddlewareRequestContext = buildPostMwRequestContext(userlandRequest);
|
|
202
203
|
let filesystemRouteEligible = hadBasePath || didMiddlewareRewrite;
|
|
204
|
+
const validateClaimedOutsideBasePathRsc = async () => {
|
|
205
|
+
if (hadBasePath || !filesystemRouteEligible) return null;
|
|
206
|
+
return resolveInvalidRscCacheBustingRequest({
|
|
207
|
+
isRscRequest,
|
|
208
|
+
request
|
|
209
|
+
});
|
|
210
|
+
};
|
|
203
211
|
for (const rewrite of options.configRewrites.beforeFiles) {
|
|
204
212
|
const beforeFilesRewrite = await applyRewrite({
|
|
205
213
|
basePathState,
|
|
@@ -215,6 +223,51 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
215
223
|
filesystemRouteEligible = true;
|
|
216
224
|
}
|
|
217
225
|
}
|
|
226
|
+
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
227
|
+
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
228
|
+
const actionId = request.headers.get("x-rsc-action") ?? request.headers.get("next-action");
|
|
229
|
+
const isPostRequest = request.method.toUpperCase() === "POST";
|
|
230
|
+
const contentType = request.headers.get("content-type") || "";
|
|
231
|
+
const isProgressiveActionRequest = isPostRequest && !actionId && contentType.startsWith("multipart/form-data");
|
|
232
|
+
let resolvedLateRewritesForAction = false;
|
|
233
|
+
if (!filesystemRouteEligible && (actionId || isProgressiveActionRequest)) {
|
|
234
|
+
let actionMatch = null;
|
|
235
|
+
for (const rewrite of options.configRewrites.afterFiles) {
|
|
236
|
+
const rewritten = await applyRewrite({
|
|
237
|
+
basePathState,
|
|
238
|
+
clearRequestContext: options.clearRequestContext,
|
|
239
|
+
request: normalizedUserlandRequest,
|
|
240
|
+
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
241
|
+
rewrites: [rewrite]
|
|
242
|
+
}, matchPathname(cleanPathname));
|
|
243
|
+
if (rewritten instanceof Response) return rewritten;
|
|
244
|
+
if (!rewritten) continue;
|
|
245
|
+
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
246
|
+
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
247
|
+
filesystemRouteEligible = true;
|
|
248
|
+
actionMatch = options.matchRoute(cleanPathname);
|
|
249
|
+
if (actionMatch) break;
|
|
250
|
+
}
|
|
251
|
+
if (!actionMatch) for (const rewrite of options.configRewrites.fallback) {
|
|
252
|
+
const rewritten = await applyRewrite({
|
|
253
|
+
basePathState,
|
|
254
|
+
clearRequestContext: options.clearRequestContext,
|
|
255
|
+
request: normalizedUserlandRequest,
|
|
256
|
+
requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
|
|
257
|
+
rewrites: [rewrite]
|
|
258
|
+
}, matchPathname(cleanPathname));
|
|
259
|
+
if (rewritten instanceof Response) return rewritten;
|
|
260
|
+
if (!rewritten) continue;
|
|
261
|
+
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
262
|
+
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
263
|
+
filesystemRouteEligible = true;
|
|
264
|
+
actionMatch = options.matchRoute(cleanPathname);
|
|
265
|
+
if (actionMatch) break;
|
|
266
|
+
}
|
|
267
|
+
resolvedLateRewritesForAction = filesystemRouteEligible;
|
|
268
|
+
}
|
|
269
|
+
const lateActionRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
270
|
+
if (lateActionRscCacheBustingRedirect) return lateActionRscCacheBustingRedirect;
|
|
218
271
|
if (filesystemRouteEligible && isImageOptimizationPath(cleanPathname)) {
|
|
219
272
|
const imageRedirect = resolveDevImageRedirect(url, [...options.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...options.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], options.imageConfig?.qualities, { isDev: options.isDev });
|
|
220
273
|
if (!imageRedirect) return new Response("Invalid image optimization parameters", { status: 400 });
|
|
@@ -255,9 +308,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
255
308
|
});
|
|
256
309
|
const preActionMatch = filesystemRouteEligible ? options.matchRoute(cleanPathname) : null;
|
|
257
310
|
if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
311
|
+
if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch) {
|
|
312
|
+
const headers = new Headers();
|
|
313
|
+
mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
|
|
314
|
+
headers.set("content-type", "application/json");
|
|
315
|
+
headers.set("x-nextjs-rewrite", resolvedUrl);
|
|
316
|
+
options.clearRequestContext();
|
|
317
|
+
return new Response("{}", { headers });
|
|
318
|
+
}
|
|
319
|
+
if (!filesystemRouteEligible && isPostRequest && actionId) {
|
|
320
|
+
options.clearRequestContext();
|
|
321
|
+
return notFoundResponse();
|
|
322
|
+
}
|
|
261
323
|
let progressiveActionResult = null;
|
|
262
324
|
if (filesystemRouteEligible && isPostRequest && contentType.startsWith("multipart/form-data") && !actionId) {
|
|
263
325
|
if (options.handleProgressiveActionRequest) progressiveActionResult = await options.handleProgressiveActionRequest({
|
|
@@ -322,7 +384,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
322
384
|
options.clearRequestContext();
|
|
323
385
|
return staticPagesFallbackResponse;
|
|
324
386
|
}
|
|
325
|
-
if (!match || match.route.isDynamic) for (const rewrite of options.configRewrites.afterFiles) {
|
|
387
|
+
if (!resolvedLateRewritesForAction && (!match || match.route.isDynamic)) for (const rewrite of options.configRewrites.afterFiles) {
|
|
326
388
|
const afterFilesRewrite = await applyRewrite({
|
|
327
389
|
basePathState,
|
|
328
390
|
clearRequestContext: options.clearRequestContext,
|
|
@@ -335,6 +397,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
335
397
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, afterFilesRewrite);
|
|
336
398
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
337
399
|
filesystemRouteEligible = true;
|
|
400
|
+
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
401
|
+
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
338
402
|
match = options.matchRoute(cleanPathname);
|
|
339
403
|
const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
|
|
340
404
|
if (rewrittenStaticPagesResponse) {
|
|
@@ -353,7 +417,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
353
417
|
options.clearRequestContext();
|
|
354
418
|
return dynamicPagesFallbackResponse;
|
|
355
419
|
}
|
|
356
|
-
if (!match) for (const rewrite of options.configRewrites.fallback) {
|
|
420
|
+
if (!resolvedLateRewritesForAction && !match) for (const rewrite of options.configRewrites.fallback) {
|
|
357
421
|
const fallbackRewrite = await applyRewrite({
|
|
358
422
|
basePathState,
|
|
359
423
|
clearRequestContext: options.clearRequestContext,
|
|
@@ -366,6 +430,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
366
430
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
367
431
|
cleanPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
368
432
|
filesystemRouteEligible = true;
|
|
433
|
+
const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
|
|
434
|
+
if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
|
|
369
435
|
match = options.matchRoute(cleanPathname);
|
|
370
436
|
const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
|
|
371
437
|
if (rewrittenStaticPagesResponse) {
|
|
@@ -391,6 +457,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
391
457
|
const response = buildNextDataNotFoundResponse();
|
|
392
458
|
const headers = new Headers(response.headers);
|
|
393
459
|
headers.set("x-nextjs-matched-path", matchPathname(canonicalPathname));
|
|
460
|
+
if (resolvedUrl !== originalResolvedUrl) headers.set("x-nextjs-rewrite", resolvedUrl);
|
|
394
461
|
return new Response("{}", {
|
|
395
462
|
status: 200,
|
|
396
463
|
headers
|
|
@@ -418,11 +485,19 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
418
485
|
}
|
|
419
486
|
const { route, params } = match;
|
|
420
487
|
if (options.ensureRouteLoaded) await options.ensureRouteLoaded(route);
|
|
488
|
+
const resolvedSearchParams = getResolvedSearchParams();
|
|
489
|
+
if (isRouteTreePrefetchRequest(request) && !route.routeHandler) {
|
|
490
|
+
const response = await createRouteTreePrefetchResponse(route, {
|
|
491
|
+
buildId: options.buildId,
|
|
492
|
+
prefetchInlining: options.prefetchInlining
|
|
493
|
+
});
|
|
494
|
+
options.clearRequestContext();
|
|
495
|
+
return applyMiddlewareContextToResponse(response, middlewareContext);
|
|
496
|
+
}
|
|
421
497
|
const prerenderRouteParamsMatch = matchPrerenderRouteParamsPayload(readTrustedPrerenderRouteParams(request), route.pattern, params);
|
|
422
498
|
const prerenderRouteParams = prerenderRouteParamsMatch?.params ?? null;
|
|
423
499
|
const isPrerenderFallbackShell = prerenderRouteParamsMatch?.kind === "fallback-shell";
|
|
424
500
|
const renderParams = prerenderRouteParams ?? params;
|
|
425
|
-
const resolvedSearchParams = getResolvedSearchParams();
|
|
426
501
|
let runtimeFallbackShells = [];
|
|
427
502
|
if (options.createPprFallbackShells && request.method === "GET" && !isRscRequest && !isPrerenderFallbackShell && route.params) runtimeFallbackShells = options.createPprFallbackShells({
|
|
428
503
|
params: route.params,
|
|
@@ -476,6 +551,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
476
551
|
staticParamsValidationParams: prerenderRouteParams === null || isPrerenderFallbackShell ? void 0 : params,
|
|
477
552
|
rootParams,
|
|
478
553
|
request,
|
|
554
|
+
renderedPathAndSearch: resolvedUrl,
|
|
479
555
|
route,
|
|
480
556
|
scriptNonce,
|
|
481
557
|
searchParams: resolvedSearchParams,
|
|
@@ -525,14 +601,16 @@ function createAppRscHandler(options) {
|
|
|
525
601
|
const pagesDataInScope = !options.basePath || hasBasePath(pagesDataUrl.pathname, options.basePath);
|
|
526
602
|
if (pagesDataInScope) pagesDataUrl.pathname = stripBasePath(pagesDataUrl.pathname, options.basePath);
|
|
527
603
|
const pagesDataCandidate = pagesDataInScope ? cloneRequestWithUrl(rawRequest, pagesDataUrl.toString()) : null;
|
|
528
|
-
const pagesDataNormalization = options.renderPagesFallback && pagesDataCandidate ? normalizePagesDataRequest(pagesDataCandidate, options.buildId) : null;
|
|
604
|
+
const pagesDataNormalization = options.renderPagesFallback && pagesDataCandidate ? normalizePagesDataRequest(pagesDataCandidate, options.buildId, "", typeof options.runMiddleware === "function" && options.trailingSlash) : null;
|
|
529
605
|
if (pagesDataNormalization?.notFoundResponse) return pagesDataNormalization.notFoundResponse;
|
|
530
606
|
const isPagesDataRequest = pagesDataNormalization?.isDataReq === true;
|
|
531
607
|
const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);
|
|
608
|
+
const isTrustedSpeculativePrerender = process.env.VINEXT_PRERENDER === "1" && rawRequest.headers.get("x-vinext-prerender-secret") !== null && rawRequest.headers.get("x-vinext-prerender-speculative") === "1";
|
|
532
609
|
const filteredHeaders = filterInternalHeaders(rawRequest.headers);
|
|
533
610
|
if (mwCtx !== null) filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);
|
|
534
611
|
const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
|
|
535
612
|
if (prerenderRouteParamsHeader !== null) filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
|
|
613
|
+
if (isTrustedSpeculativePrerender) filteredHeaders.set(VINEXT_PRERENDER_SPECULATIVE_HEADER, "1");
|
|
536
614
|
let appRequest = rawRequest;
|
|
537
615
|
if (pagesDataNormalization?.isDataReq) {
|
|
538
616
|
const appRequestUrl = new URL(pagesDataNormalization.request.url);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
//#region src/server/app-rsc-render-mode.d.ts
|
|
2
|
-
type AppRscRenderMode = "navigation" | "prefetch-
|
|
2
|
+
type AppRscRenderMode = "navigation" | "prefetch-dynamic-shell" | "prefetch-loading-shell";
|
|
3
3
|
declare const APP_RSC_RENDER_MODE_NAVIGATION = "navigation";
|
|
4
|
+
declare const APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL = "prefetch-dynamic-shell";
|
|
4
5
|
declare const APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL = "prefetch-loading-shell";
|
|
5
|
-
declare const APP_RSC_RENDER_MODE_REFRESH_PRESERVE_UI = "refresh-preserve-ui";
|
|
6
|
-
declare const APP_RSC_RENDER_MODE_ACTION_RERENDER_PRESERVE_UI = "action-rerender-preserve-ui";
|
|
7
|
-
declare function shouldSuppressLoadingBoundaries(mode: AppRscRenderMode): boolean;
|
|
8
6
|
declare function getRscRenderModeCacheVariant(mode: AppRscRenderMode): string | null;
|
|
9
7
|
declare function parseAppRscRenderMode(value: string | null): AppRscRenderMode;
|
|
10
8
|
//#endregion
|
|
11
|
-
export {
|
|
9
|
+
export { APP_RSC_RENDER_MODE_NAVIGATION, APP_RSC_RENDER_MODE_PREFETCH_DYNAMIC_SHELL, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, AppRscRenderMode, getRscRenderModeCacheVariant, parseAppRscRenderMode };
|