vinext 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +27 -1
- package/dist/build/client-build-config.js +58 -1
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +8 -0
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/config/config-matchers.d.ts +20 -1
- package/dist/config/config-matchers.js +35 -1
- package/dist/config/next-config.d.ts +16 -3
- package/dist/config/next-config.js +30 -2
- package/dist/deploy.js +40 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +54 -4
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-server-entry.js +9 -1
- package/dist/index.js +162 -217
- package/dist/plugins/postcss.js +18 -14
- package/dist/plugins/require-context.d.ts +6 -0
- package/dist/plugins/require-context.js +184 -0
- package/dist/routing/app-route-graph.d.ts +12 -1
- package/dist/routing/app-route-graph.js +137 -5
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +16 -1
- package/dist/server/api-handler.js +4 -0
- package/dist/server/app-browser-entry.js +84 -39
- package/dist/server/app-browser-interception-context.d.ts +2 -1
- package/dist/server/app-browser-interception-context.js +15 -2
- package/dist/server/app-browser-navigation-controller.d.ts +11 -1
- package/dist/server/app-browser-navigation-controller.js +77 -1
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- package/dist/server/app-browser-state.d.ts +3 -0
- package/dist/server/app-browser-state.js +6 -3
- package/dist/server/app-browser-visible-commit.js +9 -7
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -1
- package/dist/server/app-page-boundary-render.js +41 -19
- package/dist/server/app-page-dispatch.d.ts +6 -0
- package/dist/server/app-page-dispatch.js +3 -1
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +22 -10
- package/dist/server/app-page-render.d.ts +6 -0
- package/dist/server/app-page-render.js +5 -3
- package/dist/server/app-page-request.d.ts +8 -6
- package/dist/server/app-page-request.js +12 -9
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.js +2 -1
- package/dist/server/app-page-stream.d.ts +37 -2
- package/dist/server/app-page-stream.js +36 -3
- package/dist/server/app-pages-bridge.d.ts +16 -0
- package/dist/server/app-pages-bridge.js +23 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +3 -2
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +4 -3
- package/dist/server/app-rsc-route-matching.d.ts +20 -1
- package/dist/server/app-rsc-route-matching.js +29 -4
- package/dist/server/app-server-action-execution.d.ts +11 -1
- package/dist/server/app-server-action-execution.js +68 -10
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +17 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +54 -31
- package/dist/server/isr-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- package/dist/server/navigation-planner.js +5 -3
- package/dist/server/navigation-trace.d.ts +1 -1
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +4 -0
- package/dist/server/pages-page-data.d.ts +10 -7
- package/dist/server/pages-page-data.js +4 -2
- package/dist/server/pages-page-handler.d.ts +9 -2
- package/dist/server/pages-page-handler.js +29 -16
- package/dist/server/pages-page-response.d.ts +11 -2
- package/dist/server/pages-page-response.js +8 -1
- package/dist/server/pages-readiness.d.ts +36 -0
- package/dist/server/pages-readiness.js +21 -0
- package/dist/server/pages-request-pipeline.d.ts +99 -0
- package/dist/server/pages-request-pipeline.js +209 -0
- package/dist/server/pages-revalidate.d.ts +15 -0
- package/dist/server/pages-revalidate.js +19 -0
- package/dist/server/prod-server.d.ts +6 -2
- package/dist/server/prod-server.js +101 -217
- package/dist/server/socket-error-backstop.d.ts +19 -1
- package/dist/server/socket-error-backstop.js +77 -4
- package/dist/shims/app-router-scroll.js +22 -4
- package/dist/shims/cache-runtime.js +31 -1
- package/dist/shims/error-boundary.d.ts +21 -11
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/fetch-cache.d.ts +14 -1
- package/dist/shims/fetch-cache.js +18 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -1
- package/dist/shims/internal/link-status-registry.d.ts +43 -0
- package/dist/shims/internal/link-status-registry.js +42 -0
- package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
- package/dist/shims/internal/route-pattern-for-warning.js +40 -0
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/link.js +20 -6
- package/dist/shims/navigation.d.ts +2 -2
- package/dist/shims/navigation.js +63 -7
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +2 -0
- package/dist/shims/router.d.ts +6 -3
- package/dist/shims/router.js +128 -21
- package/dist/utils/client-build-manifest.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +30 -5
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- package/package.json +5 -1
|
@@ -90,8 +90,8 @@ async function validateAppPageDynamicParams(options) {
|
|
|
90
90
|
* `setNavigationContext` + element build + Response wrap) and the server-action
|
|
91
91
|
* POST path (entries/app-rsc-entry.ts), which runs its own response pipeline.
|
|
92
92
|
*/
|
|
93
|
-
function resolveAppPageInterceptMatch(options) {
|
|
94
|
-
const interceptState = resolveAppPageInterceptState(options);
|
|
93
|
+
async function resolveAppPageInterceptMatch(options) {
|
|
94
|
+
const interceptState = await resolveAppPageInterceptState(options);
|
|
95
95
|
if (interceptState.kind !== "source-route") return null;
|
|
96
96
|
return {
|
|
97
97
|
interceptOpts: options.toInterceptOpts(interceptState.intercept),
|
|
@@ -100,11 +100,12 @@ function resolveAppPageInterceptMatch(options) {
|
|
|
100
100
|
sourceRoute: interceptState.sourceRoute
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
-
function resolveAppPageInterceptState(options) {
|
|
103
|
+
async function resolveAppPageInterceptState(options) {
|
|
104
104
|
if (!options.isRscRequest) return { kind: "none" };
|
|
105
105
|
const intercept = options.findIntercept(options.cleanPathname);
|
|
106
106
|
if (!intercept) return { kind: "none" };
|
|
107
|
-
|
|
107
|
+
if (intercept.__pageLoader && intercept.page == null) intercept.page = await intercept.__pageLoader();
|
|
108
|
+
const sourceRoute = await options.getSourceRoute(intercept.sourceRouteIndex);
|
|
108
109
|
if (!sourceRoute) return { kind: "none" };
|
|
109
110
|
if (sourceRoute === options.currentRoute) return {
|
|
110
111
|
kind: "current-route",
|
|
@@ -116,8 +117,8 @@ function resolveAppPageInterceptState(options) {
|
|
|
116
117
|
sourceRoute
|
|
117
118
|
};
|
|
118
119
|
}
|
|
119
|
-
function resolveAppPageInterceptionRerenderTarget(options) {
|
|
120
|
-
const interceptState = resolveAppPageInterceptState({
|
|
120
|
+
async function resolveAppPageInterceptionRerenderTarget(options) {
|
|
121
|
+
const interceptState = await resolveAppPageInterceptState({
|
|
121
122
|
cleanPathname: options.cleanPathname,
|
|
122
123
|
currentRoute: options.currentRoute,
|
|
123
124
|
findIntercept: options.findIntercept,
|
|
@@ -143,7 +144,7 @@ function resolveAppPageActionRerenderTarget(options) {
|
|
|
143
144
|
return resolveAppPageInterceptionRerenderTarget(options);
|
|
144
145
|
}
|
|
145
146
|
async function resolveAppPageIntercept(options) {
|
|
146
|
-
const interceptState = resolveAppPageInterceptState({
|
|
147
|
+
const interceptState = await resolveAppPageInterceptState({
|
|
147
148
|
cleanPathname: options.cleanPathname,
|
|
148
149
|
currentRoute: options.currentRoute,
|
|
149
150
|
findIntercept: options.findIntercept,
|
|
@@ -153,15 +154,17 @@ async function resolveAppPageIntercept(options) {
|
|
|
153
154
|
toInterceptOpts: options.toInterceptOpts
|
|
154
155
|
});
|
|
155
156
|
if (interceptState.kind === "source-route") {
|
|
157
|
+
const renderRoute = interceptState.sourceRoute;
|
|
158
|
+
const renderParams = pickRouteParams(interceptState.intercept.matchedParams, options.getRouteParamNames(interceptState.sourceRoute));
|
|
156
159
|
options.setNavigationContext({
|
|
157
160
|
params: interceptState.intercept.matchedParams,
|
|
158
161
|
pathname: options.cleanPathname,
|
|
159
162
|
searchParams: options.searchParams
|
|
160
163
|
});
|
|
161
|
-
const interceptElement = await options.buildPageElement(
|
|
164
|
+
const interceptElement = await options.buildPageElement(renderRoute, renderParams, options.toInterceptOpts(interceptState.intercept), options.searchParams, options.layoutParamAccess);
|
|
162
165
|
return {
|
|
163
166
|
interceptOpts: void 0,
|
|
164
|
-
response: await options.renderInterceptResponse(
|
|
167
|
+
response: await options.renderInterceptResponse(renderRoute, interceptElement)
|
|
165
168
|
};
|
|
166
169
|
}
|
|
167
170
|
return {
|
|
@@ -45,8 +45,8 @@ type BuildAppPageRscResponseOptions = {
|
|
|
45
45
|
timing?: AppPageResponseTiming;
|
|
46
46
|
};
|
|
47
47
|
type BuildAppPageHtmlResponseOptions = {
|
|
48
|
-
draftCookie?: string | null;
|
|
49
|
-
|
|
48
|
+
draftCookie?: string | null; /** Combined preload `Link` header value (React hints + font preloads), already capped. */
|
|
49
|
+
linkHeader?: string;
|
|
50
50
|
isEdgeRuntime?: boolean;
|
|
51
51
|
middlewareContext: AppPageMiddlewareContext;
|
|
52
52
|
policy: AppPageResponsePolicy;
|
|
@@ -108,7 +108,7 @@ function buildAppPageHtmlResponse(body, options) {
|
|
|
108
108
|
if (options.policy.cacheControl) headers.set("Cache-Control", options.policy.cacheControl);
|
|
109
109
|
if (options.policy.cacheState) setCacheStateHeaders(headers, options.policy.cacheState);
|
|
110
110
|
if (options.draftCookie) headers.append("Set-Cookie", options.draftCookie);
|
|
111
|
-
if (options.
|
|
111
|
+
if (options.linkHeader) headers.set("Link", options.linkHeader);
|
|
112
112
|
mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);
|
|
113
113
|
applyTimingHeader(headers, options.timing);
|
|
114
114
|
return new Response(body, {
|
|
@@ -329,7 +329,7 @@ function buildAppPageElements(options) {
|
|
|
329
329
|
}
|
|
330
330
|
let routeChildren = /* @__PURE__ */ jsx(LayoutSegmentProvider, {
|
|
331
331
|
segmentMap: { children: [] },
|
|
332
|
-
children: /* @__PURE__ */ jsx(
|
|
332
|
+
children: /* @__PURE__ */ jsx(Slot, { id: pageId })
|
|
333
333
|
});
|
|
334
334
|
if (isPrefetchLoadingShell) if (routeLoadingComponent === null) routeChildren = null;
|
|
335
335
|
else routeChildren = /* @__PURE__ */ jsx(routeLoadingComponent, {});
|
|
@@ -339,6 +339,7 @@ function buildAppPageElements(options) {
|
|
|
339
339
|
fallback: /* @__PURE__ */ jsx(routeLoadingComponent, {}),
|
|
340
340
|
children: routeChildren
|
|
341
341
|
}, routeResetKey);
|
|
342
|
+
routeChildren = /* @__PURE__ */ jsx(AppRouterScrollTarget, { children: routeChildren });
|
|
342
343
|
}
|
|
343
344
|
const lastLayoutErrorModule = errorEntries.length > 0 ? errorEntries[errorEntries.length - 1].errorModule : null;
|
|
344
345
|
const notFoundComponent = getDefaultExport(options.route.notFound) ?? getDefaultExport(options.rootNotFoundModule);
|
|
@@ -18,8 +18,30 @@ type AppSsrRenderResult = {
|
|
|
18
18
|
htmlStream: ReadableStream<Uint8Array>;
|
|
19
19
|
metadataReady: Promise<void>;
|
|
20
20
|
capturedRscData: Promise<ArrayBuffer> | null;
|
|
21
|
+
/**
|
|
22
|
+
* Preload `Link` header value emitted by React during SSR (via `onHeaders`),
|
|
23
|
+
* already capped to `reactMaxHeadersLength`. Empty/undefined when React
|
|
24
|
+
* emitted no preload headers (or emission was disabled with `0`).
|
|
25
|
+
*/
|
|
26
|
+
linkHeader?: string;
|
|
21
27
|
};
|
|
22
28
|
declare function isAppSsrRenderResult(value: unknown): value is AppSsrRenderResult;
|
|
29
|
+
/**
|
|
30
|
+
* Combine the React-emitted preload `Link` header with vinext's font preload
|
|
31
|
+
* `Link` header, capping the result to `reactMaxHeadersLength`.
|
|
32
|
+
*
|
|
33
|
+
* React already caps its own portion, but vinext emits font preloads through a
|
|
34
|
+
* separate channel. Mirroring Next.js — where every preload flows through a
|
|
35
|
+
* single capped `onHeaders` callback — we cap the *combined* header here,
|
|
36
|
+
* keeping only whole entries that fit and dropping the rest once the limit is
|
|
37
|
+
* exceeded. `0` disables emission entirely (matches React); `undefined` falls
|
|
38
|
+
* back to the React default of 6000.
|
|
39
|
+
*
|
|
40
|
+
* React's hints (scripts/modules/styles) come first so that under a tight cap
|
|
41
|
+
* the render-critical entries survive and trailing font preloads are dropped
|
|
42
|
+
* first.
|
|
43
|
+
*/
|
|
44
|
+
declare function buildAppPageLinkHeader(reactLinkHeader: string | undefined, fontLinkHeader: string | undefined, maxHeadersLength: number | undefined): string;
|
|
23
45
|
type AppPageSsrHandler = {
|
|
24
46
|
handleSsr: (rscStream: ReadableStream<Uint8Array>, navigationContext: NavigationContext | null, fontData: AppPageFontData, options?: {
|
|
25
47
|
formState?: ReactFormState | null;
|
|
@@ -30,6 +52,12 @@ type AppPageSsrHandler = {
|
|
|
30
52
|
* in the SSR head. Sourced from `experimental.clientTraceMetadata`.
|
|
31
53
|
*/
|
|
32
54
|
clientTraceMetadata?: readonly string[];
|
|
55
|
+
/**
|
|
56
|
+
* Maximum total length (in characters) of the preload `Link` header
|
|
57
|
+
* emitted during SSR. `0` disables emission. From `reactMaxHeadersLength`
|
|
58
|
+
* in `next.config`.
|
|
59
|
+
*/
|
|
60
|
+
reactMaxHeadersLength?: number;
|
|
33
61
|
rootParams?: RootParams;
|
|
34
62
|
sideStream?: ReadableStream<Uint8Array>;
|
|
35
63
|
capturedRscDataRef?: {
|
|
@@ -52,6 +80,12 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
52
80
|
* the SSR head. Undefined or empty disables emission.
|
|
53
81
|
*/
|
|
54
82
|
clientTraceMetadata?: readonly string[];
|
|
83
|
+
/**
|
|
84
|
+
* Maximum total length (in characters) of the preload `Link` header emitted
|
|
85
|
+
* during SSR. `0` disables emission. From `reactMaxHeadersLength` in
|
|
86
|
+
* `next.config`.
|
|
87
|
+
*/
|
|
88
|
+
reactMaxHeadersLength?: number;
|
|
55
89
|
rootParams?: RootParams;
|
|
56
90
|
ssrHandler: AppPageSsrHandler;
|
|
57
91
|
/** Pre-split side stream for fused embed+capture (#981). When set,
|
|
@@ -74,7 +108,8 @@ type AppPageHtmlStreamRecoveryResult = {
|
|
|
74
108
|
htmlStream: ReadableStream<Uint8Array> | null;
|
|
75
109
|
response: Response | null;
|
|
76
110
|
metadataReady: Promise<void>;
|
|
77
|
-
capturedRscData: Promise<ArrayBuffer> | null;
|
|
111
|
+
capturedRscData: Promise<ArrayBuffer> | null; /** React-emitted preload `Link` header (already capped). */
|
|
112
|
+
linkHeader?: string;
|
|
78
113
|
};
|
|
79
114
|
type RenderAppPageHtmlStreamWithRecoveryOptions<TSpecialError> = {
|
|
80
115
|
onShellRendered?: () => void;
|
|
@@ -113,4 +148,4 @@ declare function renderAppPageHtmlStreamWithRecovery<TSpecialError>(options: Ren
|
|
|
113
148
|
declare function createAppPageRscErrorTracker(baseOnError: (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown): AppPageRscErrorTracker;
|
|
114
149
|
declare function shouldRerenderAppPageWithGlobalError(options: ShouldRerenderAppPageWithGlobalErrorOptions): boolean;
|
|
115
150
|
//#endregion
|
|
116
|
-
export { AppPageFontData, AppPageSsrHandler, AppSsrRenderResult, createAppPageFontData, createAppPageRscErrorTracker, deferUntilStreamConsumed, isAppSsrRenderResult, renderAppPageHtmlResponse, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery, shouldRerenderAppPageWithGlobalError };
|
|
151
|
+
export { AppPageFontData, AppPageSsrHandler, AppSsrRenderResult, buildAppPageLinkHeader, createAppPageFontData, createAppPageRscErrorTracker, deferUntilStreamConsumed, isAppSsrRenderResult, renderAppPageHtmlResponse, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery, shouldRerenderAppPageWithGlobalError };
|
|
@@ -14,6 +14,37 @@ function normalizeAppSsrRenderResult(raw, fallbackCapturedRscData = null) {
|
|
|
14
14
|
capturedRscData: fallbackCapturedRscData
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Combine the React-emitted preload `Link` header with vinext's font preload
|
|
19
|
+
* `Link` header, capping the result to `reactMaxHeadersLength`.
|
|
20
|
+
*
|
|
21
|
+
* React already caps its own portion, but vinext emits font preloads through a
|
|
22
|
+
* separate channel. Mirroring Next.js — where every preload flows through a
|
|
23
|
+
* single capped `onHeaders` callback — we cap the *combined* header here,
|
|
24
|
+
* keeping only whole entries that fit and dropping the rest once the limit is
|
|
25
|
+
* exceeded. `0` disables emission entirely (matches React); `undefined` falls
|
|
26
|
+
* back to the React default of 6000.
|
|
27
|
+
*
|
|
28
|
+
* React's hints (scripts/modules/styles) come first so that under a tight cap
|
|
29
|
+
* the render-critical entries survive and trailing font preloads are dropped
|
|
30
|
+
* first.
|
|
31
|
+
*/
|
|
32
|
+
function buildAppPageLinkHeader(reactLinkHeader, fontLinkHeader, maxHeadersLength) {
|
|
33
|
+
const limit = typeof maxHeadersLength === "number" ? maxHeadersLength : 6e3;
|
|
34
|
+
if (limit <= 0) return "";
|
|
35
|
+
const entries = [];
|
|
36
|
+
for (const source of [reactLinkHeader, fontLinkHeader]) {
|
|
37
|
+
if (!source) continue;
|
|
38
|
+
for (const entry of source.split(", ")) if (entry.length > 0) entries.push(entry);
|
|
39
|
+
}
|
|
40
|
+
let header = "";
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const next = header.length === 0 ? entry : `${header}, ${entry}`;
|
|
43
|
+
if (next.length > limit) break;
|
|
44
|
+
header = next;
|
|
45
|
+
}
|
|
46
|
+
return header;
|
|
47
|
+
}
|
|
17
48
|
function createAppPageFontData(options) {
|
|
18
49
|
return {
|
|
19
50
|
links: options.getLinks(),
|
|
@@ -27,6 +58,7 @@ async function renderAppPageHtmlStream(options) {
|
|
|
27
58
|
scriptNonce: options.scriptNonce,
|
|
28
59
|
basePath: options.basePath,
|
|
29
60
|
clientTraceMetadata: options.clientTraceMetadata,
|
|
61
|
+
reactMaxHeadersLength: options.reactMaxHeadersLength,
|
|
30
62
|
rootParams: options.rootParams,
|
|
31
63
|
sideStream: options.sideStream,
|
|
32
64
|
capturedRscDataRef: options.capturedRscDataRef,
|
|
@@ -89,13 +121,14 @@ async function renderAppPageHtmlResponse(options) {
|
|
|
89
121
|
}
|
|
90
122
|
async function renderAppPageHtmlStreamWithRecovery(options) {
|
|
91
123
|
try {
|
|
92
|
-
const { htmlStream, metadataReady, capturedRscData } = normalizeAppSsrRenderResult(await options.renderHtmlStream());
|
|
124
|
+
const { htmlStream, metadataReady, capturedRscData, linkHeader } = normalizeAppSsrRenderResult(await options.renderHtmlStream());
|
|
93
125
|
options.onShellRendered?.();
|
|
94
126
|
return {
|
|
95
127
|
htmlStream,
|
|
96
128
|
response: null,
|
|
97
129
|
metadataReady,
|
|
98
|
-
capturedRscData
|
|
130
|
+
capturedRscData,
|
|
131
|
+
linkHeader
|
|
99
132
|
};
|
|
100
133
|
} catch (error) {
|
|
101
134
|
const specialError = options.resolveSpecialError(error);
|
|
@@ -137,4 +170,4 @@ function shouldRerenderAppPageWithGlobalError(options) {
|
|
|
137
170
|
return Boolean(options.capturedError) && !options.hasLocalBoundary;
|
|
138
171
|
}
|
|
139
172
|
//#endregion
|
|
140
|
-
export { createAppPageFontData, createAppPageRscErrorTracker, deferUntilStreamConsumed, isAppSsrRenderResult, renderAppPageHtmlResponse, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery, shouldRerenderAppPageWithGlobalError };
|
|
173
|
+
export { buildAppPageLinkHeader, createAppPageFontData, createAppPageRscErrorTracker, deferUntilStreamConsumed, isAppSsrRenderResult, renderAppPageHtmlResponse, renderAppPageHtmlStream, renderAppPageHtmlStreamWithRecovery, shouldRerenderAppPageWithGlobalError };
|
|
@@ -10,6 +10,22 @@ type RenderPagesFallbackDependencies = {
|
|
|
10
10
|
buildRequestHeaders: (requestHeaders: Headers, middlewareRequestHeaders: Headers) => Headers | null;
|
|
11
11
|
decodePathParams: (pathname: string) => string;
|
|
12
12
|
applyRouteHandlerMiddlewareContext: (response: Response, middlewareContext: AppMiddlewareContext) => Response;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the `__prerender_bypass` Set-Cookie header emitted by a
|
|
15
|
+
* `draftMode().enable()`/`disable()` call inside middleware, if any. Reading
|
|
16
|
+
* it clears it. Mirrors how App Router route handlers and page renders surface
|
|
17
|
+
* the middleware-enabled draft cookie so the same flow works when the request
|
|
18
|
+
* falls through to a Pages Router route.
|
|
19
|
+
*
|
|
20
|
+
* Note: this closes the draft-mode flow for production (Cloudflare Workers /
|
|
21
|
+
* Node), where middleware runs inline in the same RSC handler context that
|
|
22
|
+
* builds this fallback. In hybrid *dev*, middleware runs in a separate Vite
|
|
23
|
+
* Pages SSR runner and `draftMode()` inside middleware is not yet permitted
|
|
24
|
+
* there (it throws a scope error before any cookie is set), so this getter
|
|
25
|
+
* returns `null` and no cookie is appended. That dev limitation is pre-existing
|
|
26
|
+
* and tracked separately from #1520.
|
|
27
|
+
*/
|
|
28
|
+
getDraftModeCookieHeader: () => string | null | undefined;
|
|
13
29
|
};
|
|
14
30
|
type RenderPagesFallbackOptions = {
|
|
15
31
|
isRscRequest: boolean;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
async function renderPagesFallback(options, dependencies) {
|
|
6
6
|
const { isRscRequest, middlewareContext, request, url } = options;
|
|
7
|
-
const { loadPagesEntry, buildRequestHeaders, decodePathParams, applyRouteHandlerMiddlewareContext } = dependencies;
|
|
7
|
+
const { loadPagesEntry, buildRequestHeaders, decodePathParams, applyRouteHandlerMiddlewareContext, getDraftModeCookieHeader } = dependencies;
|
|
8
8
|
if (isRscRequest) return null;
|
|
9
9
|
const pagesEntry = await loadPagesEntry();
|
|
10
10
|
const pagesRequestHeaders = middlewareContext.requestHeaders ? buildRequestHeaders(request.headers, middlewareContext.requestHeaders) : null;
|
|
@@ -24,11 +24,31 @@ async function renderPagesFallback(options, dependencies) {
|
|
|
24
24
|
const pagesPathname = url.pathname;
|
|
25
25
|
if (pagesPathname.startsWith("/api/") || pagesPathname === "/api") {
|
|
26
26
|
if (typeof pagesEntry.handleApiRoute !== "function") return null;
|
|
27
|
-
|
|
27
|
+
const pagesApiResponse = await pagesEntry.handleApiRoute(pagesRequest, pagesUrl);
|
|
28
|
+
const draftCookie = getDraftModeCookieHeader();
|
|
29
|
+
return applyDraftModeCookie(applyRouteHandlerMiddlewareContext(pagesApiResponse, middlewareContext), draftCookie);
|
|
28
30
|
}
|
|
29
31
|
if (typeof pagesEntry.renderPage !== "function") return null;
|
|
30
32
|
const pagesRes = await pagesEntry.renderPage(pagesRequest, pagesUrl, {}, void 0, middlewareContext.requestHeaders);
|
|
31
|
-
|
|
33
|
+
if (pagesRes.status === 404) return null;
|
|
34
|
+
return applyDraftModeCookie(pagesRes, getDraftModeCookieHeader());
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Append a middleware-emitted `__prerender_bypass` Set-Cookie header to a Pages
|
|
38
|
+
* Router fallback response. Returns the response unchanged when there is no
|
|
39
|
+
* draft cookie to add. App Router route handlers/page renders surface this same
|
|
40
|
+
* cookie via `finalizeRouteHandlerResponse`/the page response builder; this
|
|
41
|
+
* keeps draft-mode parity for requests that fall through to the Pages Router.
|
|
42
|
+
*/
|
|
43
|
+
function applyDraftModeCookie(response, draftCookie) {
|
|
44
|
+
if (!draftCookie) return response;
|
|
45
|
+
const headers = new Headers(response.headers);
|
|
46
|
+
headers.append("Set-Cookie", draftCookie);
|
|
47
|
+
return new Response(response.body, {
|
|
48
|
+
status: response.status,
|
|
49
|
+
statusText: response.statusText,
|
|
50
|
+
headers
|
|
51
|
+
});
|
|
32
52
|
}
|
|
33
53
|
//#endregion
|
|
34
54
|
export { renderPagesFallback };
|
|
@@ -18,6 +18,7 @@ type ReadAppRouteHandlerCacheOptions = {
|
|
|
18
18
|
getCollectedFetchTags: () => string[];
|
|
19
19
|
handlerFn: AppRouteHandlerFunction;
|
|
20
20
|
i18n?: NextI18nConfig | null;
|
|
21
|
+
trailingSlash?: boolean;
|
|
21
22
|
isAutoHead: boolean;
|
|
22
23
|
isrDebug?: AppRouteDebugLogger;
|
|
23
24
|
isrGet: RouteHandlerCacheGetter;
|
|
@@ -39,6 +39,7 @@ async function readAppRouteHandlerCacheResponse(options) {
|
|
|
39
39
|
dynamicConfig: options.dynamicConfig,
|
|
40
40
|
handlerFn: options.handlerFn,
|
|
41
41
|
i18n: options.i18n,
|
|
42
|
+
trailingSlash: options.trailingSlash,
|
|
42
43
|
markDynamicUsage: options.markDynamicUsage,
|
|
43
44
|
params: options.params === null ? null : makeThenableParams(options.params),
|
|
44
45
|
request: new Request(options.requestUrl, { method: "GET" }),
|
|
@@ -30,6 +30,7 @@ type DispatchAppRouteHandlerOptions = {
|
|
|
30
30
|
isrGet: RouteHandlerCacheGetter;
|
|
31
31
|
isrRouteKey: (pathname: string) => string;
|
|
32
32
|
isrSet: RouteHandlerCacheSetter;
|
|
33
|
+
trailingSlash?: boolean;
|
|
33
34
|
middlewareContext: RouteHandlerMiddlewareContext;
|
|
34
35
|
middlewareRequestHeaders?: Headers | null;
|
|
35
36
|
/**
|
|
@@ -77,6 +77,7 @@ async function dispatchAppRouteHandler(options) {
|
|
|
77
77
|
getCollectedFetchTags,
|
|
78
78
|
handlerFn: resolvedHandlerFn,
|
|
79
79
|
i18n: options.i18n,
|
|
80
|
+
trailingSlash: options.trailingSlash,
|
|
80
81
|
isAutoHead,
|
|
81
82
|
isrDebug: options.isrDebug,
|
|
82
83
|
isrGet: options.isrGet,
|
|
@@ -127,6 +128,7 @@ async function dispatchAppRouteHandler(options) {
|
|
|
127
128
|
handler,
|
|
128
129
|
handlerFn: resolvedHandlerFn,
|
|
129
130
|
i18n: options.i18n,
|
|
131
|
+
trailingSlash: options.trailingSlash,
|
|
130
132
|
isAutoHead,
|
|
131
133
|
isProduction,
|
|
132
134
|
isrDebug: options.isrDebug,
|
|
@@ -42,6 +42,7 @@ type RunAppRouteHandlerOptions = {
|
|
|
42
42
|
dynamicConfig?: string;
|
|
43
43
|
handlerFn: AppRouteHandlerFunction;
|
|
44
44
|
i18n?: NextI18nConfig | null;
|
|
45
|
+
trailingSlash?: boolean;
|
|
45
46
|
markDynamicUsage: MarkAppRouteDynamicUsageFn;
|
|
46
47
|
middlewareRequestHeaders?: Headers | null;
|
|
47
48
|
/**
|
|
@@ -21,6 +21,7 @@ async function runAppRouteHandler(options) {
|
|
|
21
21
|
const trackedRequest = createTrackedAppRouteRequest(options.request, {
|
|
22
22
|
basePath: options.basePath,
|
|
23
23
|
i18n: options.i18n,
|
|
24
|
+
trailingSlash: options.trailingSlash,
|
|
24
25
|
middlewareHeaders: options.middlewareRequestHeaders,
|
|
25
26
|
onDynamicAccess() {
|
|
26
27
|
options.markDynamicUsage();
|
|
@@ -24,6 +24,7 @@ type AppRouteRequestMode = "auto" | "force-static" | "error";
|
|
|
24
24
|
type TrackedAppRouteRequestOptions = {
|
|
25
25
|
basePath?: string;
|
|
26
26
|
i18n?: NextI18nConfig | null;
|
|
27
|
+
trailingSlash?: boolean;
|
|
27
28
|
middlewareHeaders?: Headers | null;
|
|
28
29
|
onDynamicAccess?: (access: AppRouteDynamicRequestAccess) => void;
|
|
29
30
|
requestMode?: AppRouteRequestMode;
|
|
@@ -43,10 +43,11 @@ function bindMethodIfNeeded(value, target) {
|
|
|
43
43
|
return typeof value === "function" ? value.bind(target) : value;
|
|
44
44
|
}
|
|
45
45
|
function buildNextConfig(options) {
|
|
46
|
-
if (!options.basePath && !options.i18n) return null;
|
|
46
|
+
if (!options.basePath && !options.i18n && !options.trailingSlash) return null;
|
|
47
47
|
return {
|
|
48
48
|
basePath: options.basePath,
|
|
49
|
-
i18n: options.i18n ?? void 0
|
|
49
|
+
i18n: options.i18n ?? void 0,
|
|
50
|
+
trailingSlash: options.trailingSlash
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
function rebuildRequestWithHeaders(input, headers) {
|
|
@@ -30,6 +30,7 @@ type AppRscRouteMatch<TRoute> = {
|
|
|
30
30
|
type DispatchMatchedPageOptions<TRoute> = {
|
|
31
31
|
clientReuseManifest: ClientReuseManifestParseResult;
|
|
32
32
|
cleanPathname: string;
|
|
33
|
+
displayPathname: string;
|
|
33
34
|
formState: ReactFormState | null;
|
|
34
35
|
actionError?: unknown;
|
|
35
36
|
actionFailed?: boolean;
|
|
@@ -2,7 +2,7 @@ import { createRequestContext, runWithRequestContext } from "../shims/unified-re
|
|
|
2
2
|
import { hasBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
4
|
import { ACTION_REVALIDATED_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "./headers.js";
|
|
5
|
-
import { isExternalUrl, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
5
|
+
import { isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
6
6
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
7
7
|
import { applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute, validateImageUrl } from "./request-pipeline.js";
|
|
8
8
|
import { headersContextFromRequest } from "../shims/headers.js";
|
|
@@ -15,11 +15,11 @@ import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js
|
|
|
15
15
|
import "./app-page-response.js";
|
|
16
16
|
import { prerenderRouteParamsPayloadMatchesRoute, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
17
17
|
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
18
|
-
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
19
18
|
import { applyAppMiddleware } from "./app-middleware.js";
|
|
20
19
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
21
20
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
22
21
|
import { handleAppPrerenderEndpoint } from "./app-prerender-endpoints.js";
|
|
22
|
+
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
23
23
|
import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
|
|
24
24
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
25
25
|
import { handleMetadataRouteRequest } from "./metadata-route-response.js";
|
|
@@ -113,7 +113,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
113
113
|
const redirect = matchRedirect(matchPathname(stripRscSuffix(pathname)), options.configRedirects, preMiddlewareRequestContext, basePathState);
|
|
114
114
|
if (redirect) {
|
|
115
115
|
const destination = sanitizeDestination(redirectDestinationWithBasePath(redirect.destination, options.basePath));
|
|
116
|
-
const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : destination;
|
|
116
|
+
const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : preserveRedirectDestinationQuery(destination, url.search);
|
|
117
117
|
return new Response(null, {
|
|
118
118
|
status: redirect.permanent ? 308 : 307,
|
|
119
119
|
headers: { Location: location }
|
|
@@ -302,6 +302,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
302
302
|
const pageResponse = await options.dispatchMatchedPage({
|
|
303
303
|
clientReuseManifest,
|
|
304
304
|
cleanPathname,
|
|
305
|
+
displayPathname: canonicalPathname,
|
|
305
306
|
formState,
|
|
306
307
|
actionError,
|
|
307
308
|
actionFailed,
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { RoutePatternParams } from "../routing/route-pattern.js";
|
|
2
2
|
|
|
3
3
|
//#region src/server/app-rsc-route-matching.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Sentinel slot key used for sibling-style interception entries.
|
|
6
|
+
* When a matched intercept carries this key, the render layer replaces the
|
|
7
|
+
* route's main page element instead of a parallel slot.
|
|
8
|
+
*/
|
|
9
|
+
declare const SIBLING_PAGE_INTERCEPT_SLOT_KEY = "__vinext_page_intercept";
|
|
4
10
|
type AppRscRouteParams = RoutePatternParams;
|
|
5
11
|
type AppRscInterceptForMatching = {
|
|
6
12
|
targetPattern: string;
|
|
@@ -25,15 +31,27 @@ type AppRscInterceptForMatching = {
|
|
|
25
31
|
sourceMatchPattern?: string;
|
|
26
32
|
interceptLayouts: readonly unknown[];
|
|
27
33
|
page: unknown;
|
|
34
|
+
__pageLoader?: (() => Promise<unknown>) | null;
|
|
28
35
|
params: readonly string[];
|
|
29
36
|
};
|
|
30
37
|
type AppRscSlotForMatching = {
|
|
31
38
|
id?: string | null;
|
|
32
39
|
intercepts?: readonly AppRscInterceptForMatching[];
|
|
33
40
|
};
|
|
41
|
+
type AppRscSiblingInterceptForMatching = {
|
|
42
|
+
targetPattern: string;
|
|
43
|
+
sourceMatchPattern: string | null;
|
|
44
|
+
slotId: string | null;
|
|
45
|
+
interceptLayouts: readonly unknown[];
|
|
46
|
+
page: unknown;
|
|
47
|
+
__pageLoader?: (() => Promise<unknown>) | null;
|
|
48
|
+
params: readonly string[];
|
|
49
|
+
};
|
|
34
50
|
type AppRscRouteForMatching = {
|
|
51
|
+
pattern: string;
|
|
35
52
|
patternParts: string[];
|
|
36
53
|
slots?: Record<string, AppRscSlotForMatching>;
|
|
54
|
+
siblingIntercepts?: AppRscSiblingInterceptForMatching[];
|
|
37
55
|
};
|
|
38
56
|
type AppRscInterceptMatch = AppRscInterceptLookupEntry & {
|
|
39
57
|
matchedParams: AppRscRouteParams;
|
|
@@ -47,6 +65,7 @@ type AppRscInterceptLookupEntry = {
|
|
|
47
65
|
sourceMatchPatternParts: string[] | null;
|
|
48
66
|
interceptLayouts: readonly unknown[];
|
|
49
67
|
page: unknown;
|
|
68
|
+
__pageLoader?: (() => Promise<unknown>) | null;
|
|
50
69
|
params: readonly string[];
|
|
51
70
|
slotId: string | null;
|
|
52
71
|
};
|
|
@@ -59,4 +78,4 @@ declare function createAppRscRouteMatcher<Route extends AppRscRouteForMatching>(
|
|
|
59
78
|
};
|
|
60
79
|
declare function matchAppRscRoutePattern(urlParts: string[], patternParts: string[]): AppRscRouteParams | null;
|
|
61
80
|
//#endregion
|
|
62
|
-
export { createAppRscRouteMatcher, matchAppRscRoutePattern };
|
|
81
|
+
export { SIBLING_PAGE_INTERCEPT_SLOT_KEY, createAppRscRouteMatcher, matchAppRscRoutePattern };
|
|
@@ -2,6 +2,12 @@ import { splitPathnameForRouteMatch } from "../routing/utils.js";
|
|
|
2
2
|
import { buildRouteTrie, trieMatch } from "../routing/route-trie.js";
|
|
3
3
|
import { matchRoutePattern, matchRoutePatternPrefix } from "../routing/route-pattern.js";
|
|
4
4
|
//#region src/server/app-rsc-route-matching.ts
|
|
5
|
+
/**
|
|
6
|
+
* Sentinel slot key used for sibling-style interception entries.
|
|
7
|
+
* When a matched intercept carries this key, the render layer replaces the
|
|
8
|
+
* route's main page element instead of a parallel slot.
|
|
9
|
+
*/
|
|
10
|
+
const SIBLING_PAGE_INTERCEPT_SLOT_KEY = "__vinext_page_intercept";
|
|
5
11
|
function createRouteParams() {
|
|
6
12
|
return Object.create(null);
|
|
7
13
|
}
|
|
@@ -54,17 +60,18 @@ function matchInterceptSource(sourceParts, entry) {
|
|
|
54
60
|
return matchRoutePatternPrefix(sourceParts, patternParts);
|
|
55
61
|
}
|
|
56
62
|
function createInterceptLookup(routes) {
|
|
63
|
+
const patternToIndex = new Map(routes.map((r, i) => [r.pattern, i]));
|
|
57
64
|
const interceptLookup = [];
|
|
58
65
|
for (let routeIndex = 0; routeIndex < routes.length; routeIndex++) {
|
|
59
66
|
const route = routes[routeIndex];
|
|
60
|
-
if (
|
|
61
|
-
for (const [slotKey, slotModule] of Object.entries(route.slots)) {
|
|
67
|
+
if (route.slots) for (const [slotKey, slotModule] of Object.entries(route.slots)) {
|
|
62
68
|
if (!slotModule.intercepts) continue;
|
|
63
69
|
for (const intercept of slotModule.intercepts) {
|
|
64
70
|
const sourceMatchPattern = intercept.sourceMatchPattern ?? null;
|
|
65
71
|
const sourceMatchPatternParts = sourceMatchPattern ? sourceMatchPattern.split("/").filter(Boolean) : null;
|
|
72
|
+
const ownerRouteIndex = sourceMatchPattern !== null ? patternToIndex.get(sourceMatchPattern) ?? routeIndex : routeIndex;
|
|
66
73
|
interceptLookup.push({
|
|
67
|
-
sourceRouteIndex:
|
|
74
|
+
sourceRouteIndex: ownerRouteIndex,
|
|
68
75
|
slotKey,
|
|
69
76
|
slotId: typeof slotModule.id === "string" ? slotModule.id : null,
|
|
70
77
|
targetPattern: intercept.targetPattern,
|
|
@@ -73,10 +80,28 @@ function createInterceptLookup(routes) {
|
|
|
73
80
|
sourceMatchPatternParts,
|
|
74
81
|
interceptLayouts: intercept.interceptLayouts,
|
|
75
82
|
page: intercept.page,
|
|
83
|
+
__pageLoader: intercept.__pageLoader,
|
|
76
84
|
params: intercept.params
|
|
77
85
|
});
|
|
78
86
|
}
|
|
79
87
|
}
|
|
88
|
+
if (route.siblingIntercepts) for (const intercept of route.siblingIntercepts) {
|
|
89
|
+
const sourceMatchPattern = intercept.sourceMatchPattern ?? null;
|
|
90
|
+
const sourceMatchPatternParts = sourceMatchPattern ? sourceMatchPattern.split("/").filter(Boolean) : null;
|
|
91
|
+
interceptLookup.push({
|
|
92
|
+
sourceRouteIndex: routeIndex,
|
|
93
|
+
slotKey: SIBLING_PAGE_INTERCEPT_SLOT_KEY,
|
|
94
|
+
slotId: typeof intercept.slotId === "string" ? intercept.slotId : null,
|
|
95
|
+
targetPattern: intercept.targetPattern,
|
|
96
|
+
targetPatternParts: intercept.targetPattern.split("/").filter(Boolean),
|
|
97
|
+
sourceMatchPattern,
|
|
98
|
+
sourceMatchPatternParts,
|
|
99
|
+
interceptLayouts: intercept.interceptLayouts,
|
|
100
|
+
page: intercept.page,
|
|
101
|
+
__pageLoader: intercept.__pageLoader,
|
|
102
|
+
params: intercept.params
|
|
103
|
+
});
|
|
104
|
+
}
|
|
80
105
|
}
|
|
81
106
|
return interceptLookup;
|
|
82
107
|
}
|
|
@@ -87,4 +112,4 @@ function mergeMatchedParams(sourceParams, targetParams) {
|
|
|
87
112
|
return Object.assign(createRouteParams(), sourceParams, targetParams);
|
|
88
113
|
}
|
|
89
114
|
//#endregion
|
|
90
|
-
export { createAppRscRouteMatcher, matchAppRscRoutePattern };
|
|
115
|
+
export { SIBLING_PAGE_INTERCEPT_SLOT_KEY, createAppRscRouteMatcher, matchAppRscRoutePattern };
|
|
@@ -108,6 +108,15 @@ type HandleProgressiveServerActionRequestOptions = {
|
|
|
108
108
|
decodeFormState: AppServerActionFormStateDecoder;
|
|
109
109
|
getAndClearPendingCookies: () => string[];
|
|
110
110
|
getDraftModeCookieHeader: () => string | null | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Whether the posted-to route resolves to an App Router *page* (as opposed to
|
|
113
|
+
* a route handler or no match). Multipart form POSTs to a page are always
|
|
114
|
+
* server-action attempts in Next.js, so a body that decodes to no action must
|
|
115
|
+
* surface as 404 action-not-found rather than rendering the page. Route
|
|
116
|
+
* handlers (which run *after* this dispatch in vinext) legitimately receive
|
|
117
|
+
* raw multipart POSTs, so they must still fall through. See issue #1340.
|
|
118
|
+
*/
|
|
119
|
+
hasPageRoute: boolean;
|
|
111
120
|
maxActionBodySize: number;
|
|
112
121
|
middlewareHeaders: Headers | null;
|
|
113
122
|
readFormDataWithLimit: ReadFormDataWithLimit;
|
|
@@ -143,7 +152,8 @@ type HandleServerActionRscRequestOptions<TElement, TRoute extends AppServerActio
|
|
|
143
152
|
isRscRequest: boolean;
|
|
144
153
|
loadServerAction: (actionId: string) => Promise<unknown>;
|
|
145
154
|
matchRoute: (pathname: string) => AppServerActionMatch<TRoute> | null;
|
|
146
|
-
maxActionBodySize: number;
|
|
155
|
+
maxActionBodySize: number; /** Verbatim `serverActions.bodySizeLimit` config string (e.g. "2mb") for the body-exceeded error. */
|
|
156
|
+
maxActionBodySizeLabel: string;
|
|
147
157
|
middlewareHeaders: Headers | null;
|
|
148
158
|
middlewareStatus: number | null | undefined;
|
|
149
159
|
mountedSlotsHeader: string | null;
|