vinext 0.1.2 → 0.1.3
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/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +2 -1
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.js +73 -14
- package/dist/config/next-config.d.ts +46 -4
- package/dist/config/next-config.js +147 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +180 -99
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -5
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +53 -8
- package/dist/entries/pages-server-entry.js +41 -5
- package/dist/index.js +200 -62
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/optimize-imports.d.ts +2 -1
- package/dist/plugins/optimize-imports.js +11 -9
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/routing/app-route-graph.d.ts +2 -1
- package/dist/routing/app-route-graph.js +44 -14
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +22 -1
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +167 -90
- package/dist/server/app-browser-error.d.ts +10 -6
- package/dist/server/app-browser-error.js +43 -8
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +4 -2
- package/dist/server/app-browser-navigation-controller.js +23 -2
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -0
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-optimistic-routing.js +2 -2
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +27 -14
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +62 -1
- package/dist/server/app-page-dispatch.d.ts +26 -0
- package/dist/server/app-page-dispatch.js +149 -92
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +5 -2
- package/dist/server/app-page-execution.d.ts +6 -1
- package/dist/server/app-page-execution.js +21 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +12 -1
- package/dist/server/app-page-render.js +42 -4
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +2 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +14 -5
- package/dist/server/app-page-stream.d.ts +15 -3
- package/dist/server/app-page-stream.js +11 -5
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +154 -54
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +42 -13
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +83 -10
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +244 -51
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/navigation-planner.d.ts +133 -30
- package/dist/server/navigation-planner.js +114 -0
- package/dist/server/navigation-trace.d.ts +8 -1
- package/dist/server/navigation-trace.js +8 -1
- package/dist/server/pages-api-route.d.ts +6 -0
- package/dist/server/pages-api-route.js +13 -2
- package/dist/server/pages-asset-tags.d.ts +2 -1
- package/dist/server/pages-asset-tags.js +6 -2
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +11 -2
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.js +2 -2
- package/dist/server/pages-page-data.d.ts +11 -2
- package/dist/server/pages-page-data.js +204 -33
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +59 -22
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +7 -4
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +73 -36
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.js +9 -3
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +3 -2
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.js +6 -4
- package/dist/shims/error-boundary.d.ts +2 -0
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +3 -2
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +45 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/headers.js +29 -4
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.js +8 -17
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +61 -31
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +419 -128
- package/dist/shims/server.d.ts +16 -1
- package/dist/shims/server.js +44 -12
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +7 -1
- package/dist/utils/path.js +9 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -24,6 +24,7 @@ type AppPageInterceptOptions<TModule extends AppPageModule = AppPageModule> = {
|
|
|
24
24
|
interceptSlotId?: string | null;
|
|
25
25
|
interceptSlotKey?: string | null;
|
|
26
26
|
interceptSourceMatchedUrl?: string | null;
|
|
27
|
+
interceptSourcePageSegments?: readonly string[] | null;
|
|
27
28
|
};
|
|
28
29
|
type AppPagePageRequest<TModule extends AppPageModule = AppPageModule> = {
|
|
29
30
|
/** Interception context from current-route navigation (null for direct visits). */opts?: AppPageInterceptOptions<TModule> | null; /** URL search params from the incoming request (null when unavailable). */
|
|
@@ -6,7 +6,7 @@ import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
|
6
6
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
7
7
|
import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
|
|
8
8
|
import { makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
|
|
9
|
-
import { buildAppPageElements, createAppPageTreePath } from "./app-page-route-wiring.js";
|
|
9
|
+
import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath } from "./app-page-route-wiring.js";
|
|
10
10
|
import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
|
|
11
11
|
import "./app-rsc-route-matching.js";
|
|
12
12
|
import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
|
|
@@ -36,6 +36,7 @@ async function buildPageElements(options) {
|
|
|
36
36
|
const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
|
|
37
37
|
const EffectivePageComponent = effectivePageModule?.default;
|
|
38
38
|
const effectiveParams = isSiblingIntercept ? opts.interceptParams ?? params : params;
|
|
39
|
+
const sourcePageSegments = isSiblingIntercept ? opts?.interceptSourcePageSegments : route.routeSegments;
|
|
39
40
|
const hasPageModule = !!pageModule;
|
|
40
41
|
const renderIdentity = createAppPageRenderIdentity({
|
|
41
42
|
displayPathname,
|
|
@@ -56,7 +57,8 @@ async function buildPageElements(options) {
|
|
|
56
57
|
interceptionContext: renderIdentity.interceptionContext,
|
|
57
58
|
layoutIds: noExportLayoutIds,
|
|
58
59
|
rootLayoutTreePath: noExportRootLayout,
|
|
59
|
-
routeId: renderIdentity.routeId
|
|
60
|
+
routeId: renderIdentity.routeId,
|
|
61
|
+
sourcePage: createAppPageSourcePage(sourcePageSegments)
|
|
60
62
|
}),
|
|
61
63
|
[renderIdentity.routeId]: createElement("div", null, "Page has no default export")
|
|
62
64
|
};
|
|
@@ -112,6 +114,7 @@ async function buildPageElements(options) {
|
|
|
112
114
|
resolvedViewport,
|
|
113
115
|
renderIdentity,
|
|
114
116
|
routePath,
|
|
117
|
+
sourcePageSegments,
|
|
115
118
|
rootNotFoundModule: rootNotFoundModule ?? null,
|
|
116
119
|
rootForbiddenModule: rootForbiddenModule ?? null,
|
|
117
120
|
rootUnauthorizedModule: rootUnauthorizedModule ?? null,
|
|
@@ -121,13 +121,18 @@ type ProbeAppPageComponentOptions = {
|
|
|
121
121
|
probePage: () => unknown;
|
|
122
122
|
runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;
|
|
123
123
|
};
|
|
124
|
+
type ProbeAppPageThrownErrorOptions = {
|
|
125
|
+
probePage: () => unknown;
|
|
126
|
+
runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;
|
|
127
|
+
};
|
|
124
128
|
declare function resolveAppPageSpecialError(error: unknown): AppPageSpecialError | null;
|
|
125
129
|
declare function buildAppPageSpecialErrorResponse(options: BuildAppPageSpecialErrorResponseOptions): Promise<Response>;
|
|
126
130
|
/** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */
|
|
127
131
|
declare function probeAppPageLayouts(options: ProbeAppPageLayoutsOptions): Promise<ProbeAppPageLayoutsResult>;
|
|
128
132
|
declare function probeAppPageComponent(options: ProbeAppPageComponentOptions): Promise<Response | null>;
|
|
133
|
+
declare function probeAppPageThrownError(options: ProbeAppPageThrownErrorOptions): Promise<unknown>;
|
|
129
134
|
declare function readAppPageBinaryStream(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer>;
|
|
130
135
|
declare function teeAppPageRscStreamForCapture(stream: ReadableStream<Uint8Array>, shouldCapture: boolean): AppPageRscStreamCapture;
|
|
131
136
|
declare function buildAppPageFontLinkHeader(preloads: readonly AppPageFontPreload[] | null | undefined): string;
|
|
132
137
|
//#endregion
|
|
133
|
-
export { AppPageFontPreload, AppPageSpecialError, LayoutClassificationOptions, type LayoutFlags, buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, resolveAppPageSpecialError, tagAppPageMetadataError, teeAppPageRscStreamForCapture };
|
|
138
|
+
export { AppPageFontPreload, AppPageSpecialError, LayoutClassificationOptions, type LayoutFlags, buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, probeAppPageThrownError, readAppPageBinaryStream, resolveAppPageSpecialError, tagAppPageMetadataError, teeAppPageRscStreamForCapture };
|
|
@@ -274,6 +274,26 @@ async function probeAppPageComponent(options) {
|
|
|
274
274
|
return outcome.completed ? outcome.result : null;
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
|
+
async function probeAppPageThrownError(options) {
|
|
278
|
+
return options.runWithSuppressedHookWarning(async () => {
|
|
279
|
+
const outcome = await runWithConnectionProbe(async () => {
|
|
280
|
+
try {
|
|
281
|
+
const pageResult = options.probePage();
|
|
282
|
+
if (isPromiseLike(pageResult)) await pageResult;
|
|
283
|
+
} catch (error) {
|
|
284
|
+
return {
|
|
285
|
+
error,
|
|
286
|
+
thrown: true
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
error: null,
|
|
291
|
+
thrown: false
|
|
292
|
+
};
|
|
293
|
+
});
|
|
294
|
+
return outcome.completed && outcome.result.thrown ? outcome.result.error : null;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
277
297
|
async function readAppPageBinaryStream(stream) {
|
|
278
298
|
const reader = stream.getReader();
|
|
279
299
|
const chunks = [];
|
|
@@ -305,4 +325,4 @@ function buildAppPageFontLinkHeader(preloads) {
|
|
|
305
325
|
return preloads.map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`).join(", ");
|
|
306
326
|
}
|
|
307
327
|
//#endregion
|
|
308
|
-
export { buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, resolveAppPageSpecialError, tagAppPageMetadataError, teeAppPageRscStreamForCapture };
|
|
328
|
+
export { buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, probeAppPageThrownError, readAppPageBinaryStream, resolveAppPageSpecialError, tagAppPageMetadataError, teeAppPageRscStreamForCapture };
|
|
@@ -119,6 +119,7 @@ type ProbeAppPageBeforeRenderResult = {
|
|
|
119
119
|
};
|
|
120
120
|
type ProbeAppPageBeforeRenderOptions = {
|
|
121
121
|
hasLoadingBoundary: boolean;
|
|
122
|
+
skipProbes?: boolean;
|
|
122
123
|
layoutCount: number;
|
|
123
124
|
probeLayoutAt: (layoutIndex: number) => unknown;
|
|
124
125
|
probePage: () => unknown;
|
|
@@ -227,6 +227,10 @@ function buildAppPageProbes(options) {
|
|
|
227
227
|
}
|
|
228
228
|
async function probeAppPageBeforeRender(options) {
|
|
229
229
|
let layoutFlags = {};
|
|
230
|
+
if (options.skipProbes) return {
|
|
231
|
+
response: null,
|
|
232
|
+
layoutFlags
|
|
233
|
+
};
|
|
230
234
|
if (options.layoutCount > 0) {
|
|
231
235
|
const layoutProbeResult = await probeAppPageLayouts({
|
|
232
236
|
layoutCount: options.layoutCount,
|
|
@@ -7,6 +7,8 @@ type AppPageRenderObservationState = Readonly<{
|
|
|
7
7
|
requestApis: readonly RenderRequestApiKind[];
|
|
8
8
|
}>;
|
|
9
9
|
declare function createEmptyAppPageRenderObservationState(): AppPageRenderObservationState;
|
|
10
|
+
declare function consumeAppPageRenderObservationState(): AppPageRenderObservationState;
|
|
11
|
+
declare function discardAppPageRenderState(): void;
|
|
10
12
|
declare function createAppPageRenderObservation(options: {
|
|
11
13
|
boundaryOutcome: BoundaryOutcome;
|
|
12
14
|
cacheTags: readonly string[];
|
|
@@ -31,4 +33,4 @@ declare function createAppPageHtmlOutputScope(options: {
|
|
|
31
33
|
routePattern: string;
|
|
32
34
|
}): CacheProofOutputScope;
|
|
33
35
|
//#endregion
|
|
34
|
-
export { AppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope, createEmptyAppPageRenderObservationState };
|
|
36
|
+
export { AppPageRenderObservationState, consumeAppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope, createEmptyAppPageRenderObservationState, discardAppPageRenderState };
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { consumeDynamicUsage, consumeInvalidDynamicUsageError, consumeRenderRequestApiUsage } from "../shims/headers.js";
|
|
1
2
|
import { fnv1a64 } from "../utils/hash.js";
|
|
3
|
+
import { _consumeRequestScopedCacheLife } from "../shims/cache.js";
|
|
2
4
|
import { AppElementsWire, isAppElementsRecord } from "./app-elements-wire.js";
|
|
3
5
|
import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
|
|
4
6
|
import "./app-elements.js";
|
|
7
|
+
import { consumeDynamicFetchObservations } from "../shims/fetch-cache.js";
|
|
5
8
|
import { buildRenderObservation, buildRenderRequestApiObservations } from "./cache-proof.js";
|
|
6
9
|
//#region src/server/app-page-render-observation.ts
|
|
7
10
|
function readRootBoundaryId(element) {
|
|
@@ -30,6 +33,19 @@ function createEmptyAppPageRenderObservationState() {
|
|
|
30
33
|
requestApis: []
|
|
31
34
|
};
|
|
32
35
|
}
|
|
36
|
+
function consumeAppPageRenderObservationState() {
|
|
37
|
+
return {
|
|
38
|
+
dynamicFetches: consumeDynamicFetchObservations(),
|
|
39
|
+
requestApis: consumeRenderRequestApiUsage()
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function discardAppPageRenderState() {
|
|
43
|
+
_consumeRequestScopedCacheLife();
|
|
44
|
+
consumeDynamicFetchObservations();
|
|
45
|
+
consumeRenderRequestApiUsage();
|
|
46
|
+
consumeInvalidDynamicUsageError();
|
|
47
|
+
consumeDynamicUsage();
|
|
48
|
+
}
|
|
33
49
|
function createAppPageRenderObservation(options) {
|
|
34
50
|
return buildRenderObservation({
|
|
35
51
|
boundaryOutcome: options.boundaryOutcome,
|
|
@@ -63,4 +79,4 @@ function createAppPageHtmlOutputScope(options) {
|
|
|
63
79
|
};
|
|
64
80
|
}
|
|
65
81
|
//#endregion
|
|
66
|
-
export { createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope, createEmptyAppPageRenderObservationState };
|
|
82
|
+
export { consumeAppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope, createEmptyAppPageRenderObservationState, discardAppPageRenderState };
|
|
@@ -7,8 +7,8 @@ import { AppPageMiddlewareContext } from "./app-page-response.js";
|
|
|
7
7
|
import { RootParams } from "../shims/root-params.js";
|
|
8
8
|
import { AppPageSsrHandler } from "./app-page-stream.js";
|
|
9
9
|
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
10
|
-
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
11
10
|
import { AppPageRenderObservationState } from "./app-page-render-observation.js";
|
|
11
|
+
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
12
12
|
import { ReactNode } from "react";
|
|
13
13
|
import { ReactFormState } from "react-dom/client";
|
|
14
14
|
|
|
@@ -49,6 +49,7 @@ type RenderAppPageLifecycleOptions = {
|
|
|
49
49
|
peekRequestCacheLife?: () => AppPageRequestCacheLife | null;
|
|
50
50
|
getDraftModeCookieHeader: () => string | null | undefined;
|
|
51
51
|
handlerStart: number;
|
|
52
|
+
hasCustomGlobalError?: boolean;
|
|
52
53
|
hasLoadingBoundary: boolean;
|
|
53
54
|
dynamicStaleTimeSeconds?: number;
|
|
54
55
|
isDynamicError: boolean;
|
|
@@ -70,6 +71,9 @@ type RenderAppPageLifecycleOptions = {
|
|
|
70
71
|
middlewareContext: AppPageMiddlewareContext;
|
|
71
72
|
navigationParams: Record<string, unknown>;
|
|
72
73
|
params: Record<string, unknown>;
|
|
74
|
+
pprFallbackShellSignal?: AbortSignal;
|
|
75
|
+
pprFallbackShellReactSignal?: AbortSignal;
|
|
76
|
+
abortPprFallbackShell?: () => void;
|
|
73
77
|
rootParams?: RootParams;
|
|
74
78
|
peekRenderObservationState?: () => AppPageRenderObservationState;
|
|
75
79
|
probeLayoutAt: (layoutIndex: number) => unknown;
|
|
@@ -82,7 +86,14 @@ type RenderAppPageLifecycleOptions = {
|
|
|
82
86
|
renderPageSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;
|
|
83
87
|
renderToReadableStream: (element: ReactNode | AppOutgoingElements, options: {
|
|
84
88
|
onError: AppPageBoundaryOnError;
|
|
89
|
+
signal?: AbortSignal;
|
|
85
90
|
}) => ReadableStream<Uint8Array>;
|
|
91
|
+
prerenderToReadableStream?: (element: ReactNode | AppOutgoingElements, options: {
|
|
92
|
+
onError: AppPageBoundaryOnError;
|
|
93
|
+
signal?: AbortSignal;
|
|
94
|
+
}) => Promise<{
|
|
95
|
+
prelude: ReadableStream<Uint8Array>;
|
|
96
|
+
}>;
|
|
86
97
|
routePattern: string;
|
|
87
98
|
runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;
|
|
88
99
|
scriptNonce?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NO_STORE_CACHE_CONTROL } from "./cache-control.js";
|
|
1
|
+
import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
|
|
2
2
|
import { createArtifactCompatibilityEnvelope, createArtifactCompatibilityGraphVersion } from "./artifact-compatibility.js";
|
|
3
3
|
import { AppElementsWire, isAppElementsRecord } from "./app-elements-wire.js";
|
|
4
4
|
import "./app-elements.js";
|
|
@@ -249,6 +249,7 @@ function wrapRscResponseForDevErrorReporting(response, consumeInvalidDynamicUsag
|
|
|
249
249
|
async function renderAppPageLifecycle(options) {
|
|
250
250
|
const preRenderResult = await probeAppPageBeforeRender({
|
|
251
251
|
hasLoadingBoundary: options.hasLoadingBoundary,
|
|
252
|
+
skipProbes: options.pprFallbackShellSignal !== void 0,
|
|
252
253
|
layoutCount: options.layoutCount,
|
|
253
254
|
probeLayoutAt(layoutIndex) {
|
|
254
255
|
return options.probeLayoutAt(layoutIndex);
|
|
@@ -315,11 +316,31 @@ async function renderAppPageLifecycle(options) {
|
|
|
315
316
|
});
|
|
316
317
|
const compileEnd = options.isProduction ? void 0 : performance.now();
|
|
317
318
|
const rscErrorTracker = createAppPageRscErrorTracker(options.createRscOnErrorHandler(options.cleanPathname, options.routePattern));
|
|
318
|
-
|
|
319
|
+
let rscStream = await runWithFetchDedupe(async () => {
|
|
320
|
+
if (options.pprFallbackShellSignal && options.prerenderToReadableStream) {
|
|
321
|
+
const reactSignal = options.pprFallbackShellReactSignal ?? options.pprFallbackShellSignal;
|
|
322
|
+
const pendingResult = options.prerenderToReadableStream(outgoingElement, {
|
|
323
|
+
onError: rscErrorTracker.onRenderError,
|
|
324
|
+
signal: reactSignal
|
|
325
|
+
});
|
|
326
|
+
if (options.abortPprFallbackShell) setTimeout(options.abortPprFallbackShell, 0);
|
|
327
|
+
return (await pendingResult).prelude;
|
|
328
|
+
}
|
|
329
|
+
return options.renderToReadableStream(outgoingElement, { onError: rscErrorTracker.onRenderError });
|
|
330
|
+
});
|
|
331
|
+
let pprFallbackShellRsc = null;
|
|
332
|
+
if (options.pprFallbackShellSignal) pprFallbackShellRsc = new Uint8Array(await readAppPageBinaryStream(rscStream));
|
|
319
333
|
let revalidateSeconds = options.revalidateSeconds;
|
|
320
334
|
let expireSeconds = options.expireSeconds;
|
|
321
335
|
const shouldCaptureRscForCacheMetadata = options.isProgressiveActionRender !== true && (options.isProduction || options.isPrerender === true) && (revalidateSeconds === null || revalidateSeconds > 0 && revalidateSeconds !== Infinity) && !options.isDraftMode && !options.isForceDynamic && !shouldBypassRscCacheForSkipTransport;
|
|
322
|
-
const
|
|
336
|
+
const createBufferedRscStream = (close) => new ReadableStream({ start(controller) {
|
|
337
|
+
if (pprFallbackShellRsc) controller.enqueue(pprFallbackShellRsc);
|
|
338
|
+
if (close) controller.close();
|
|
339
|
+
} });
|
|
340
|
+
const rscCapture = pprFallbackShellRsc ? {
|
|
341
|
+
ssrStream: createBufferedRscStream(false),
|
|
342
|
+
...shouldCaptureRscForCacheMetadata ? { sideStream: createBufferedRscStream(true) } : {}
|
|
343
|
+
} : teeAppPageRscStreamForCapture(rscStream, shouldCaptureRscForCacheMetadata);
|
|
323
344
|
const rscForResponse = rscCapture.ssrStream;
|
|
324
345
|
const capturedRscDataRef = { value: null };
|
|
325
346
|
if (rscCapture.sideStream && options.isRscRequest) capturedRscDataRef.value = readAppPageBinaryStream(rscCapture.sideStream);
|
|
@@ -415,17 +436,19 @@ async function renderAppPageLifecycle(options) {
|
|
|
415
436
|
return renderAppPageHtmlStream({
|
|
416
437
|
capturedRscDataRef,
|
|
417
438
|
fontData,
|
|
439
|
+
hasCustomGlobalError: options.hasCustomGlobalError,
|
|
418
440
|
navigationContext: options.getNavigationContext(),
|
|
419
441
|
basePath: options.basePath,
|
|
420
442
|
clientTraceMetadata: options.clientTraceMetadata,
|
|
421
443
|
reactMaxHeadersLength: options.reactMaxHeadersLength,
|
|
422
444
|
rootParams: options.rootParams,
|
|
445
|
+
pprFallbackShellSignal: options.pprFallbackShellSignal,
|
|
423
446
|
formState: options.formState ?? null,
|
|
424
447
|
rscStream: rscForResponse,
|
|
425
448
|
scriptNonce: options.scriptNonce,
|
|
426
449
|
sideStream: rscCapture.sideStream,
|
|
427
450
|
ssrHandler,
|
|
428
|
-
waitForAllReady: options.isPrerender
|
|
451
|
+
waitForAllReady: options.isPrerender === true
|
|
429
452
|
});
|
|
430
453
|
},
|
|
431
454
|
renderSpecialErrorResponse(specialError) {
|
|
@@ -482,6 +505,21 @@ async function renderAppPageLifecycle(options) {
|
|
|
482
505
|
renderEnd,
|
|
483
506
|
responseKind: "html"
|
|
484
507
|
});
|
|
508
|
+
if (htmlRender.shellErrorRecovered) {
|
|
509
|
+
const response = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
510
|
+
draftCookie,
|
|
511
|
+
linkHeader,
|
|
512
|
+
isEdgeRuntime: options.isEdgeRuntime,
|
|
513
|
+
middlewareContext: {
|
|
514
|
+
headers: options.middlewareContext.headers,
|
|
515
|
+
status: 500
|
|
516
|
+
},
|
|
517
|
+
policy: { cacheControl: NEVER_CACHE_CONTROL },
|
|
518
|
+
timing: htmlResponseTiming
|
|
519
|
+
});
|
|
520
|
+
applyCdnResponseHeaders(response.headers, { cacheControl: NEVER_CACHE_CONTROL });
|
|
521
|
+
return response;
|
|
522
|
+
}
|
|
485
523
|
const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
|
|
486
524
|
if (htmlResponsePolicy.shouldWriteToCache || shouldSpeculativelyWriteCache) {
|
|
487
525
|
const isrResponse = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
@@ -29,6 +29,7 @@ type ResolveAppPageGenerateStaticParamsSourcesOptions = {
|
|
|
29
29
|
};
|
|
30
30
|
type BuildAppPageElementOptions<TElement> = {
|
|
31
31
|
buildPageElement: () => Promise<TElement>;
|
|
32
|
+
probePageSpecialError?: () => Promise<AppPageSpecialError | null>;
|
|
32
33
|
renderErrorBoundaryPage: (error: unknown) => Promise<Response | null>;
|
|
33
34
|
renderSpecialError: (specialError: AppPageSpecialError) => Promise<Response>;
|
|
34
35
|
resolveSpecialError: (error: unknown) => AppPageSpecialError | null;
|
|
@@ -44,6 +45,7 @@ type AppPageInterceptMatch<TPage = unknown> = {
|
|
|
44
45
|
slotId?: string | null;
|
|
45
46
|
slotKey: string;
|
|
46
47
|
sourceRouteIndex: number;
|
|
48
|
+
sourcePageSegments?: readonly string[] | null;
|
|
47
49
|
};
|
|
48
50
|
type ResolveAppPageInterceptMatchOptions<TRoute, TPage, TInterceptOpts> = {
|
|
49
51
|
cleanPathname: string;
|
|
@@ -180,7 +180,8 @@ async function buildAppPageElement(options) {
|
|
|
180
180
|
response: null
|
|
181
181
|
};
|
|
182
182
|
} catch (error) {
|
|
183
|
-
const
|
|
183
|
+
const buildSpecialError = options.resolveSpecialError(error);
|
|
184
|
+
const specialError = (buildSpecialError ? await options.probePageSpecialError?.() : null) ?? buildSpecialError;
|
|
184
185
|
if (specialError) return {
|
|
185
186
|
element: null,
|
|
186
187
|
response: await options.renderSpecialError(specialError)
|
|
@@ -130,6 +130,7 @@ type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule,
|
|
|
130
130
|
renderIdentity?: AppPageRenderIdentity;
|
|
131
131
|
renderMode?: AppRscRenderMode;
|
|
132
132
|
routePath: string;
|
|
133
|
+
sourcePageSegments?: readonly string[] | null;
|
|
133
134
|
};
|
|
134
135
|
declare function createAppPageTreePath(routeSegments: readonly string[] | null | undefined, treePosition: number): string;
|
|
135
136
|
declare function probeAppPageLayoutWithTracking<TModule extends AppPageModule>(options: {
|
|
@@ -143,7 +144,8 @@ declare function createAppPageLayoutEntries<TModule extends AppPageModule, TErro
|
|
|
143
144
|
forbiddens?: readonly (TModule | null | undefined)[] | null;
|
|
144
145
|
unauthorizeds?: readonly (TModule | null | undefined)[] | null;
|
|
145
146
|
}): AppPageLayoutEntry<TModule, TErrorModule>[];
|
|
147
|
+
declare function createAppPageSourcePage(routeSegments: readonly string[] | null | undefined): string;
|
|
146
148
|
declare function createAppPageRouteBodyMetadata(metadata: Metadata | null, pathname: string, metadataPlacement: "body" | "head", trailingSlash?: boolean): ReactNode;
|
|
147
149
|
declare function buildAppPageElements<TModule extends AppPageModule, TErrorModule extends AppPageErrorModule>(options: BuildAppPageElementsOptions<TModule, TErrorModule>): AppElements;
|
|
148
150
|
//#endregion
|
|
149
|
-
export { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute, AppPageSlotOverride, buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageTreePath, probeAppPageLayoutWithTracking, resolveAppPageChildSegments };
|
|
151
|
+
export { AppPageErrorModule, AppPageModule, AppPageRouteWiringRoute, AppPageSlotOverride, buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath, probeAppPageLayoutWithTracking, resolveAppPageChildSegments };
|
|
@@ -2,7 +2,8 @@ import { createAppRenderDependency, registerAppElementRenderDependencies, render
|
|
|
2
2
|
import { APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
3
3
|
import { APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL, shouldSuppressLoadingBoundaries } from "./app-rsc-render-mode.js";
|
|
4
4
|
import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY } from "./app-elements.js";
|
|
5
|
-
import
|
|
5
|
+
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
6
|
+
import { ErrorBoundary, ForbiddenBoundary, GlobalErrorBoundary, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
6
7
|
import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
|
|
7
8
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
8
9
|
import { MetadataHead, ViewportHead, renderMetadataToHtml } from "../shims/metadata.js";
|
|
@@ -14,6 +15,7 @@ import { Fragment, Suspense } from "react";
|
|
|
14
15
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
15
16
|
//#region src/server/app-page-route-wiring.tsx
|
|
16
17
|
const APP_PAGE_LAYOUT_PROBE_CHILD = /* @__PURE__ */ jsx(Fragment, {});
|
|
18
|
+
const DEFAULT_GLOBAL_ERROR_COMPONENT = DefaultGlobalError;
|
|
17
19
|
function getDefaultExport(module) {
|
|
18
20
|
return module?.default ?? null;
|
|
19
21
|
}
|
|
@@ -85,6 +87,9 @@ function createAppPageTemplateEntries(route) {
|
|
|
85
87
|
};
|
|
86
88
|
});
|
|
87
89
|
}
|
|
90
|
+
function createAppPageSourcePage(routeSegments) {
|
|
91
|
+
return `/${[...routeSegments ?? [], "page"].join("/")}`;
|
|
92
|
+
}
|
|
88
93
|
function createAppPageErrorEntries(route) {
|
|
89
94
|
return (route.errorPaths ?? route.errors ?? []).flatMap((errorModule, index) => {
|
|
90
95
|
if (!errorModule) return [];
|
|
@@ -206,6 +211,7 @@ function buildAppPageElements(options) {
|
|
|
206
211
|
layoutIds: options.route.ids?.layouts ?? layoutEntries.map((entry) => entry.id),
|
|
207
212
|
rootLayoutTreePath,
|
|
208
213
|
routeId,
|
|
214
|
+
sourcePage: createAppPageSourcePage(options.sourcePageSegments ?? routeSegments),
|
|
209
215
|
slotBindings: createAppPageSlotBindings(options.route, layoutEntries, resolveSlotOverride, {
|
|
210
216
|
interception: renderIdentity?.interception ?? options.interception ?? null,
|
|
211
217
|
interceptionContext,
|
|
@@ -427,9 +433,12 @@ function buildAppPageElements(options) {
|
|
|
427
433
|
});
|
|
428
434
|
}
|
|
429
435
|
const globalErrorComponent = getErrorBoundaryExport(options.globalErrorModule);
|
|
430
|
-
|
|
431
|
-
fallback:
|
|
432
|
-
children:
|
|
436
|
+
routeChildren = /* @__PURE__ */ jsx(GlobalErrorBoundary, {
|
|
437
|
+
fallback: DEFAULT_GLOBAL_ERROR_COMPONENT,
|
|
438
|
+
children: globalErrorComponent ? /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
439
|
+
fallback: globalErrorComponent,
|
|
440
|
+
children: routeChildren
|
|
441
|
+
}) : routeChildren
|
|
433
442
|
});
|
|
434
443
|
elements[routeId] = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
435
444
|
createAppPageRouteHead(options.resolvedMetadata, options.resolvedViewport, options.resolvedMetadataPathname ?? options.routePath, metadataPlacement, options.trailingSlash),
|
|
@@ -440,4 +449,4 @@ function buildAppPageElements(options) {
|
|
|
440
449
|
return elements;
|
|
441
450
|
}
|
|
442
451
|
//#endregion
|
|
443
|
-
export { buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageTreePath, probeAppPageLayoutWithTracking, resolveAppPageChildSegments };
|
|
452
|
+
export { buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath, probeAppPageLayoutWithTracking, resolveAppPageChildSegments };
|
|
@@ -18,6 +18,7 @@ type AppSsrRenderResult = {
|
|
|
18
18
|
htmlStream: ReadableStream<Uint8Array>;
|
|
19
19
|
metadataReady: Promise<void>;
|
|
20
20
|
capturedRscData: Promise<ArrayBuffer> | null;
|
|
21
|
+
shellErrorRecovered?: boolean;
|
|
21
22
|
/**
|
|
22
23
|
* Preload `Link` header value emitted by React during SSR (via `onHeaders`),
|
|
23
24
|
* already capped to `reactMaxHeadersLength`. Empty/undefined when React
|
|
@@ -62,9 +63,14 @@ type AppPageSsrHandler = {
|
|
|
62
63
|
sideStream?: ReadableStream<Uint8Array>;
|
|
63
64
|
capturedRscDataRef?: {
|
|
64
65
|
value: Promise<ArrayBuffer> | null;
|
|
65
|
-
}; /**
|
|
66
|
+
}; /** Abort signal for a build-time PPR fallback-shell static render. */
|
|
67
|
+
pprFallbackShellSignal?: AbortSignal; /** When true, wait for the full React tree before emitting bytes. */
|
|
66
68
|
waitForAllReady?: boolean; /** Dev-only: original server error to surface in the browser overlay. */
|
|
67
69
|
initialDevServerError?: unknown;
|
|
70
|
+
/** When true, an SSR-phase-only shell render error resolves to the
|
|
71
|
+
* default `__next_error__` error-document shell (with the original
|
|
72
|
+
* flight payload and bootstrap) instead of rejecting. See handleSsr. */
|
|
73
|
+
fallbackToErrorDocumentOnShellError?: boolean;
|
|
68
74
|
}) => Promise<ReadableStream<Uint8Array> | AppSsrRenderResult>;
|
|
69
75
|
};
|
|
70
76
|
type RenderAppPageHtmlStreamOptions = {
|
|
@@ -93,9 +99,14 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
93
99
|
sideStream?: ReadableStream<Uint8Array>; /** Out-parameter filled with accumulated raw RSC bytes after stream consumption. */
|
|
94
100
|
capturedRscDataRef?: {
|
|
95
101
|
value: Promise<ArrayBuffer> | null;
|
|
96
|
-
}; /**
|
|
102
|
+
}; /** Abort signal for a build-time PPR fallback-shell static render. */
|
|
103
|
+
pprFallbackShellSignal?: AbortSignal; /** When true, wait for the full React tree before emitting bytes. */
|
|
97
104
|
waitForAllReady?: boolean; /** Dev-only: original server error to surface in the browser overlay. */
|
|
98
105
|
initialDevServerError?: unknown;
|
|
106
|
+
/** True when the app supplies a custom global-error.tsx. Disables the
|
|
107
|
+
* default error-document shell fallback so SSR shell errors keep driving
|
|
108
|
+
* the server-rendered global-error boundary re-render. */
|
|
109
|
+
hasCustomGlobalError?: boolean;
|
|
99
110
|
};
|
|
100
111
|
type RenderAppPageHtmlResponseOptions = {
|
|
101
112
|
clearRequestContext: () => void;
|
|
@@ -108,7 +119,8 @@ type AppPageHtmlStreamRecoveryResult = {
|
|
|
108
119
|
htmlStream: ReadableStream<Uint8Array> | null;
|
|
109
120
|
response: Response | null;
|
|
110
121
|
metadataReady: Promise<void>;
|
|
111
|
-
capturedRscData: Promise<ArrayBuffer> | null;
|
|
122
|
+
capturedRscData: Promise<ArrayBuffer> | null;
|
|
123
|
+
shellErrorRecovered: boolean; /** React-emitted preload `Link` header (already capped). */
|
|
112
124
|
linkHeader?: string;
|
|
113
125
|
};
|
|
114
126
|
type RenderAppPageHtmlStreamWithRecoveryOptions<TSpecialError> = {
|
|
@@ -11,7 +11,8 @@ function normalizeAppSsrRenderResult(raw, fallbackCapturedRscData = null) {
|
|
|
11
11
|
return {
|
|
12
12
|
htmlStream: raw,
|
|
13
13
|
metadataReady: resolvedMetadataReady,
|
|
14
|
-
capturedRscData: fallbackCapturedRscData
|
|
14
|
+
capturedRscData: fallbackCapturedRscData,
|
|
15
|
+
shellErrorRecovered: false
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
@@ -62,8 +63,10 @@ async function renderAppPageHtmlStream(options) {
|
|
|
62
63
|
rootParams: options.rootParams,
|
|
63
64
|
sideStream: options.sideStream,
|
|
64
65
|
capturedRscDataRef: options.capturedRscDataRef,
|
|
66
|
+
pprFallbackShellSignal: options.pprFallbackShellSignal,
|
|
65
67
|
waitForAllReady: options.waitForAllReady,
|
|
66
|
-
initialDevServerError: options.initialDevServerError
|
|
68
|
+
initialDevServerError: options.initialDevServerError,
|
|
69
|
+
fallbackToErrorDocumentOnShellError: options.waitForAllReady !== true && options.hasCustomGlobalError === false
|
|
67
70
|
};
|
|
68
71
|
return normalizeAppSsrRenderResult(await options.ssrHandler.handleSsr(options.rscStream, options.navigationContext, options.fontData, ssrOptions), options.capturedRscDataRef?.value ?? null);
|
|
69
72
|
}
|
|
@@ -121,13 +124,14 @@ async function renderAppPageHtmlResponse(options) {
|
|
|
121
124
|
}
|
|
122
125
|
async function renderAppPageHtmlStreamWithRecovery(options) {
|
|
123
126
|
try {
|
|
124
|
-
const { htmlStream, metadataReady, capturedRscData, linkHeader } = normalizeAppSsrRenderResult(await options.renderHtmlStream());
|
|
127
|
+
const { htmlStream, metadataReady, capturedRscData, linkHeader, shellErrorRecovered } = normalizeAppSsrRenderResult(await options.renderHtmlStream());
|
|
125
128
|
options.onShellRendered?.();
|
|
126
129
|
return {
|
|
127
130
|
htmlStream,
|
|
128
131
|
response: null,
|
|
129
132
|
metadataReady,
|
|
130
133
|
capturedRscData,
|
|
134
|
+
shellErrorRecovered: shellErrorRecovered === true,
|
|
131
135
|
linkHeader
|
|
132
136
|
};
|
|
133
137
|
} catch (error) {
|
|
@@ -136,14 +140,16 @@ async function renderAppPageHtmlStreamWithRecovery(options) {
|
|
|
136
140
|
htmlStream: null,
|
|
137
141
|
response: await options.renderSpecialErrorResponse(specialError),
|
|
138
142
|
metadataReady: resolvedMetadataReady,
|
|
139
|
-
capturedRscData: null
|
|
143
|
+
capturedRscData: null,
|
|
144
|
+
shellErrorRecovered: false
|
|
140
145
|
};
|
|
141
146
|
const boundaryResponse = await options.renderErrorBoundaryResponse(error);
|
|
142
147
|
if (boundaryResponse) return {
|
|
143
148
|
htmlStream: null,
|
|
144
149
|
response: boundaryResponse,
|
|
145
150
|
metadataReady: resolvedMetadataReady,
|
|
146
|
-
capturedRscData: null
|
|
151
|
+
capturedRscData: null,
|
|
152
|
+
shellErrorRecovered: false
|
|
147
153
|
};
|
|
148
154
|
throw error;
|
|
149
155
|
}
|
|
@@ -3,8 +3,22 @@ import { AppMiddlewareContext } from "./app-middleware.js";
|
|
|
3
3
|
//#region src/server/app-pages-bridge.d.ts
|
|
4
4
|
type PagesEntry = {
|
|
5
5
|
handleApiRoute?: (request: Request, url: string) => Promise<Response> | Response;
|
|
6
|
+
matchApiRoute?: (url: string, request: Request) => PagesRouteMatch | null;
|
|
7
|
+
matchPageRoute?: (url: string, request: Request) => PagesRouteMatch | null;
|
|
6
8
|
renderPage?: (request: Request, url: string, query: Record<string, unknown>, parsedUrl: unknown, middlewareRequestHeaders?: Headers | null) => Promise<Response> | Response;
|
|
7
9
|
};
|
|
10
|
+
type PagesRouteMatch = {
|
|
11
|
+
route: {
|
|
12
|
+
isDynamic: boolean;
|
|
13
|
+
pattern: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
type AppRouteMatch = {
|
|
17
|
+
route: {
|
|
18
|
+
isDynamic: boolean;
|
|
19
|
+
pattern: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
8
22
|
type RenderPagesFallbackDependencies = {
|
|
9
23
|
loadPagesEntry: () => Promise<PagesEntry> | PagesEntry;
|
|
10
24
|
buildRequestHeaders: (requestHeaders: Headers, middlewareRequestHeaders: Headers) => Headers | null;
|
|
@@ -28,8 +42,12 @@ type RenderPagesFallbackDependencies = {
|
|
|
28
42
|
getDraftModeCookieHeader: () => string | null | undefined;
|
|
29
43
|
};
|
|
30
44
|
type RenderPagesFallbackOptions = {
|
|
45
|
+
allowRscDocumentFallback?: boolean;
|
|
46
|
+
appRouteMatch?: AppRouteMatch | null;
|
|
31
47
|
isRscRequest: boolean;
|
|
48
|
+
matchKind?: "dynamic" | "static";
|
|
32
49
|
middlewareContext: AppMiddlewareContext;
|
|
50
|
+
pathname?: string;
|
|
33
51
|
request: Request;
|
|
34
52
|
url: URL;
|
|
35
53
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { pagesRouteHasPriorityOverAppRoute } from "./hybrid-route-priority.js";
|
|
1
2
|
//#region src/server/app-pages-bridge.ts
|
|
2
3
|
/**
|
|
3
4
|
* Fallback handler to route App Router requests to the Pages Router when no App Router route matches.
|
|
4
5
|
*/
|
|
5
6
|
async function renderPagesFallback(options, dependencies) {
|
|
6
|
-
const { isRscRequest, middlewareContext, request, url } = options;
|
|
7
|
+
const { allowRscDocumentFallback = false, appRouteMatch = null, isRscRequest, matchKind, middlewareContext, pathname = options.url.pathname, request, url } = options;
|
|
7
8
|
const { loadPagesEntry, buildRequestHeaders, decodePathParams, applyRouteHandlerMiddlewareContext, getDraftModeCookieHeader } = dependencies;
|
|
8
|
-
if (isRscRequest) return null;
|
|
9
|
+
if (isRscRequest && !allowRscDocumentFallback) return null;
|
|
9
10
|
const pagesEntry = await loadPagesEntry();
|
|
10
11
|
const pagesRequestHeaders = middlewareContext.requestHeaders ? buildRequestHeaders(request.headers, middlewareContext.requestHeaders) : null;
|
|
11
12
|
let pagesRequest = request;
|
|
@@ -20,17 +21,33 @@ async function renderPagesFallback(options, dependencies) {
|
|
|
20
21
|
}
|
|
21
22
|
pagesRequest = new Request(request.url, pagesRequestInit);
|
|
22
23
|
}
|
|
23
|
-
const
|
|
24
|
-
const pagesPathname =
|
|
24
|
+
const queryIndex = pathname.indexOf("?");
|
|
25
|
+
const pagesPathname = queryIndex === -1 ? pathname : pathname.slice(0, queryIndex);
|
|
26
|
+
const pagesSearch = queryIndex === -1 ? url.search || "" : pathname.slice(queryIndex);
|
|
27
|
+
const pagesUrl = decodePathParams(pagesPathname) + pagesSearch;
|
|
25
28
|
if (pagesPathname.startsWith("/api/") || pagesPathname === "/api") {
|
|
26
29
|
if (typeof pagesEntry.handleApiRoute !== "function") return null;
|
|
30
|
+
const hasApiMatcher = typeof pagesEntry.matchApiRoute === "function";
|
|
31
|
+
const apiMatch = hasApiMatcher ? pagesEntry.matchApiRoute?.(pagesUrl, pagesRequest) ?? null : null;
|
|
32
|
+
if (hasApiMatcher && apiMatch === null) return null;
|
|
33
|
+
if (apiMatch !== null && matchKind === "static" && apiMatch.route.isDynamic) return null;
|
|
34
|
+
if (apiMatch !== null && matchKind === "dynamic" && !apiMatch.route.isDynamic) return null;
|
|
35
|
+
if (appRouteMatch !== null) {
|
|
36
|
+
if (apiMatch === null || !pagesRouteHasPriorityOverAppRoute(apiMatch.route, appRouteMatch.route)) return null;
|
|
37
|
+
}
|
|
27
38
|
const pagesApiResponse = await pagesEntry.handleApiRoute(pagesRequest, pagesUrl);
|
|
28
39
|
const draftCookie = getDraftModeCookieHeader();
|
|
29
40
|
return applyDraftModeCookie(applyRouteHandlerMiddlewareContext(pagesApiResponse, middlewareContext), draftCookie);
|
|
30
41
|
}
|
|
31
42
|
if (typeof pagesEntry.renderPage !== "function") return null;
|
|
43
|
+
const hasPageMatcher = typeof pagesEntry.matchPageRoute === "function";
|
|
44
|
+
const pageMatch = hasPageMatcher ? pagesEntry.matchPageRoute?.(pagesUrl, pagesRequest) ?? null : null;
|
|
45
|
+
if (hasPageMatcher && pageMatch === null) return null;
|
|
46
|
+
if (pageMatch !== null && matchKind === "static" && pageMatch.route.isDynamic) return null;
|
|
47
|
+
if (pageMatch !== null && matchKind === "dynamic" && !pageMatch.route.isDynamic) return null;
|
|
48
|
+
if (appRouteMatch !== null && (pageMatch === null || !pagesRouteHasPriorityOverAppRoute(pageMatch.route, appRouteMatch.route))) return null;
|
|
32
49
|
const pagesRes = await pagesEntry.renderPage(pagesRequest, pagesUrl, {}, void 0, middlewareContext.requestHeaders);
|
|
33
|
-
if (pagesRes.status === 404) return null;
|
|
50
|
+
if (pagesRes.status === 404 && pageMatch === null) return null;
|
|
34
51
|
return applyDraftModeCookie(pagesRes, getDraftModeCookieHeader());
|
|
35
52
|
}
|
|
36
53
|
/**
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PprFallbackShellState } from "../shims/ppr-fallback-shell.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/server/app-ppr-fallback-shell-render.d.ts
|
|
5
|
+
type AppPageBoundaryOnError = (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;
|
|
6
|
+
type AppPageRenderableElement = ReactNode | Record<string, ReactNode>;
|
|
7
|
+
declare function warmPprFallbackShellCaches(options: {
|
|
8
|
+
element: AppPageRenderableElement;
|
|
9
|
+
onError: AppPageBoundaryOnError;
|
|
10
|
+
renderToReadableStream: (element: AppPageRenderableElement, options: {
|
|
11
|
+
onError: AppPageBoundaryOnError;
|
|
12
|
+
signal?: AbortSignal;
|
|
13
|
+
}) => ReadableStream<Uint8Array>;
|
|
14
|
+
state: PprFallbackShellState;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { warmPprFallbackShellCaches };
|