vinext 0.0.45 → 0.0.47
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 +7 -5
- package/dist/build/prerender.d.ts +2 -1
- package/dist/build/prerender.js +80 -17
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/report.d.ts +1 -1
- package/dist/build/route-classification-injector.d.ts +35 -0
- package/dist/build/route-classification-injector.js +61 -0
- package/dist/build/route-classification-injector.js.map +1 -0
- package/dist/build/route-classification-manifest.d.ts +1 -1
- package/dist/build/standalone.js +4 -3
- package/dist/build/standalone.js.map +1 -1
- package/dist/build/static-export.d.ts +1 -1
- package/dist/check.js +30 -18
- package/dist/check.js.map +1 -1
- package/dist/cli-args.d.ts +31 -0
- package/dist/cli-args.js +104 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.js +6 -19
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +29 -9
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/config/config-matchers.js +1 -0
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +42 -4
- package/dist/config/next-config.js +27 -0
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +18 -23
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +4 -3
- package/dist/entries/app-rsc-entry.js +435 -2317
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +24 -0
- package/dist/entries/app-rsc-manifest.js +155 -0
- package/dist/entries/app-rsc-manifest.js.map +1 -0
- package/dist/entries/pages-server-entry.js +18 -105
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.js +82 -85
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.js +54 -32
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/rsc-client-shim-excludes.d.ts +6 -0
- package/dist/plugins/rsc-client-shim-excludes.js +28 -0
- package/dist/plugins/rsc-client-shim-excludes.js.map +1 -0
- package/dist/routing/app-route-graph.d.ts +109 -0
- package/dist/routing/app-route-graph.js +819 -0
- package/dist/routing/app-route-graph.js.map +1 -0
- package/dist/routing/app-router.d.ts +2 -79
- package/dist/routing/app-router.js +7 -621
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/route-pattern.d.ts +9 -0
- package/dist/routing/route-pattern.js +90 -0
- package/dist/routing/route-pattern.js.map +1 -0
- package/dist/routing/route-trie.js +10 -11
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/server/app-browser-entry.js +94 -232
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-error.d.ts +3 -4
- package/dist/server/app-browser-error.js +8 -4
- package/dist/server/app-browser-error.js.map +1 -1
- package/dist/server/app-browser-navigation-controller.d.ts +73 -0
- package/dist/server/app-browser-navigation-controller.js +282 -0
- package/dist/server/app-browser-navigation-controller.js.map +1 -0
- package/dist/server/app-browser-state.d.ts +1 -1
- package/dist/server/app-browser-state.js.map +1 -1
- package/dist/server/app-elements.js +1 -5
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +57 -0
- package/dist/server/app-fallback-renderer.js +79 -0
- package/dist/server/app-fallback-renderer.js.map +1 -0
- package/dist/server/app-hook-warning-suppression.d.ts +7 -0
- package/dist/server/app-hook-warning-suppression.js +12 -0
- package/dist/server/app-hook-warning-suppression.js.map +1 -0
- package/dist/server/app-middleware.d.ts +32 -0
- package/dist/server/app-middleware.js +147 -0
- package/dist/server/app-middleware.js.map +1 -0
- package/dist/server/app-mounted-slots-header.d.ts +17 -0
- package/dist/server/app-mounted-slots-header.js +21 -0
- package/dist/server/app-mounted-slots-header.js.map +1 -0
- package/dist/server/app-page-boundary-render.d.ts +4 -2
- package/dist/server/app-page-boundary-render.js +50 -30
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +12 -1
- package/dist/server/app-page-boundary.js +27 -12
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +22 -5
- package/dist/server/app-page-cache.js +90 -11
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +123 -0
- package/dist/server/app-page-dispatch.js +348 -0
- package/dist/server/app-page-dispatch.js.map +1 -0
- package/dist/server/app-page-element-builder.d.ts +61 -0
- package/dist/server/app-page-element-builder.js +139 -0
- package/dist/server/app-page-element-builder.js.map +1 -0
- package/dist/server/app-page-execution.d.ts +4 -3
- package/dist/server/app-page-execution.js +5 -8
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +55 -0
- package/dist/server/app-page-head.js +196 -0
- package/dist/server/app-page-head.js.map +1 -0
- package/dist/server/app-page-method.d.ts +16 -0
- package/dist/server/app-page-method.js +30 -0
- package/dist/server/app-page-method.js.map +1 -0
- package/dist/server/app-page-params.d.ts +8 -0
- package/dist/server/app-page-params.js +28 -0
- package/dist/server/app-page-params.js.map +1 -0
- package/dist/server/app-page-render.d.ts +7 -2
- package/dist/server/app-page-render.js +131 -32
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +23 -8
- package/dist/server/app-page-request.js +51 -6
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +1 -0
- package/dist/server/app-page-response.js +3 -7
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +29 -5
- package/dist/server/app-page-route-wiring.js +30 -8
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +10 -0
- package/dist/server/app-page-stream.js +5 -1
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-post-middleware-context.d.ts +16 -0
- package/dist/server/app-post-middleware-context.js +28 -0
- package/dist/server/app-post-middleware-context.js.map +1 -0
- package/dist/server/app-prerender-endpoints.d.ts +19 -0
- package/dist/server/app-prerender-endpoints.js +96 -0
- package/dist/server/app-prerender-endpoints.js.map +1 -0
- package/dist/server/app-prerender-static-params.d.ts +16 -0
- package/dist/server/app-prerender-static-params.js +14 -0
- package/dist/server/app-prerender-static-params.js.map +1 -0
- package/dist/server/app-request-context.d.ts +22 -0
- package/dist/server/app-request-context.js +30 -0
- package/dist/server/app-request-context.js.map +1 -0
- package/dist/server/app-route-handler-cache.d.ts +4 -0
- package/dist/server/app-route-handler-cache.js +11 -3
- package/dist/server/app-route-handler-cache.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +43 -0
- package/dist/server/app-route-handler-dispatch.js +149 -0
- package/dist/server/app-route-handler-dispatch.js.map +1 -0
- package/dist/server/app-route-handler-execution.d.ts +8 -3
- package/dist/server/app-route-handler-execution.js +25 -4
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.d.ts +6 -3
- package/dist/server/app-route-handler-response.js +52 -11
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +4 -1
- package/dist/server/app-route-handler-runtime.js +107 -1
- package/dist/server/app-route-handler-runtime.js.map +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/app-rsc-error-handler.d.ts +21 -0
- package/dist/server/app-rsc-error-handler.js +30 -0
- package/dist/server/app-rsc-error-handler.js.map +1 -0
- package/dist/server/app-rsc-errors.d.ts +27 -0
- package/dist/server/app-rsc-errors.js +42 -0
- package/dist/server/app-rsc-errors.js.map +1 -0
- package/dist/server/app-rsc-handler.d.ts +117 -0
- package/dist/server/app-rsc-handler.js +260 -0
- package/dist/server/app-rsc-handler.js.map +1 -0
- package/dist/server/app-rsc-request-normalization.d.ts +40 -0
- package/dist/server/app-rsc-request-normalization.js +63 -0
- package/dist/server/app-rsc-request-normalization.js.map +1 -0
- package/dist/server/app-rsc-response-finalizer.d.ts +30 -0
- package/dist/server/app-rsc-response-finalizer.js +38 -0
- package/dist/server/app-rsc-response-finalizer.js.map +1 -0
- package/dist/server/app-rsc-route-matching.d.ts +40 -0
- package/dist/server/app-rsc-route-matching.js +66 -0
- package/dist/server/app-rsc-route-matching.js.map +1 -0
- package/dist/server/app-segment-config.d.ts +33 -0
- package/dist/server/app-segment-config.js +86 -0
- package/dist/server/app-segment-config.js.map +1 -0
- package/dist/server/app-server-action-execution.d.ts +88 -1
- package/dist/server/app-server-action-execution.js +257 -5
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +7 -0
- package/dist/server/app-ssr-entry.js +30 -9
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +4 -2
- package/dist/server/app-ssr-stream.js +29 -2
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.d.ts +15 -0
- package/dist/server/app-static-generation.js +20 -0
- package/dist/server/app-static-generation.js.map +1 -0
- package/dist/server/cache-control.d.ts +24 -0
- package/dist/server/cache-control.js +33 -0
- package/dist/server/cache-control.js.map +1 -0
- package/dist/server/dev-error-overlay-store.d.ts +23 -0
- package/dist/server/dev-error-overlay-store.js +67 -0
- package/dist/server/dev-error-overlay-store.js.map +1 -0
- package/dist/server/dev-error-overlay.d.ts +15 -0
- package/dist/server/dev-error-overlay.js +548 -0
- package/dist/server/dev-error-overlay.js.map +1 -0
- package/dist/server/dev-route-files.d.ts +7 -0
- package/dist/server/dev-route-files.js +73 -0
- package/dist/server/dev-route-files.js.map +1 -0
- package/dist/server/dev-server.js +4 -0
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/file-based-metadata.d.ts +17 -0
- package/dist/server/file-based-metadata.js +356 -0
- package/dist/server/file-based-metadata.js.map +1 -0
- package/dist/server/implicit-tags.d.ts +6 -0
- package/dist/server/implicit-tags.js +42 -0
- package/dist/server/implicit-tags.js.map +1 -0
- package/dist/server/instrumentation-runtime.d.ts +44 -0
- package/dist/server/instrumentation-runtime.js +29 -0
- package/dist/server/instrumentation-runtime.js.map +1 -0
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts +16 -3
- package/dist/server/isr-cache.js +56 -8
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-route-build-data.d.ts +25 -0
- package/dist/server/metadata-route-build-data.js +150 -0
- package/dist/server/metadata-route-build-data.js.map +1 -0
- package/dist/server/metadata-route-response.d.ts +17 -0
- package/dist/server/metadata-route-response.js +187 -0
- package/dist/server/metadata-route-response.js.map +1 -0
- package/dist/server/metadata-routes.d.ts +42 -4
- package/dist/server/metadata-routes.js +127 -11
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-matcher.d.ts +15 -0
- package/dist/server/middleware-matcher.js +102 -0
- package/dist/server/middleware-matcher.js.map +1 -0
- package/dist/server/middleware-request-headers.js +2 -1
- package/dist/server/middleware-request-headers.js.map +1 -1
- package/dist/server/middleware-runtime.d.ts +39 -0
- package/dist/server/middleware-runtime.js +159 -0
- package/dist/server/middleware-runtime.js.map +1 -0
- package/dist/server/middleware.d.ts +4 -36
- package/dist/server/middleware.js +18 -228
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +7 -2
- package/dist/server/pages-page-data.js +10 -5
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +5 -3
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/prerender-work-unit-setup.d.ts +7 -0
- package/dist/server/prerender-work-unit-setup.js +30 -0
- package/dist/server/prerender-work-unit-setup.js.map +1 -0
- package/dist/server/prod-server.js +10 -14
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/request-pipeline.d.ts +46 -5
- package/dist/server/request-pipeline.js +84 -5
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/rsc-stream-hints.d.ts +7 -0
- package/dist/server/rsc-stream-hints.js +38 -0
- package/dist/server/rsc-stream-hints.js.map +1 -0
- package/dist/server/seed-cache.js +19 -8
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.d.ts +9 -0
- package/dist/server/server-action-not-found.js +40 -0
- package/dist/server/server-action-not-found.js.map +1 -0
- package/dist/shims/cache-runtime.js +28 -11
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +39 -4
- package/dist/shims/cache.js +93 -16
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/error-boundary.d.ts +66 -5
- package/dist/shims/error-boundary.js +106 -4
- package/dist/shims/error-boundary.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +4 -1
- package/dist/shims/fetch-cache.js +55 -13
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/font-google-base.d.ts +5 -4
- package/dist/shims/font-google-base.js +61 -13
- package/dist/shims/font-google-base.js.map +1 -1
- package/dist/shims/headers.d.ts +14 -2
- package/dist/shims/headers.js +127 -17
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.js +116 -10
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/make-hanging-promise.d.ts +16 -0
- package/dist/shims/internal/make-hanging-promise.js +46 -0
- package/dist/shims/internal/make-hanging-promise.js.map +1 -0
- package/dist/shims/internal/work-unit-async-storage.d.ts +26 -3
- package/dist/shims/internal/work-unit-async-storage.js +6 -3
- package/dist/shims/internal/work-unit-async-storage.js.map +1 -1
- package/dist/shims/metadata.d.ts +38 -26
- package/dist/shims/metadata.js +75 -45
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +10 -1
- package/dist/shims/navigation.js +18 -1
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/navigation.react-server.d.ts +2 -2
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/navigation.react-server.js.map +1 -1
- package/dist/shims/offline.d.ts +5 -0
- package/dist/shims/offline.js +17 -0
- package/dist/shims/offline.js.map +1 -0
- package/dist/shims/request-state-types.d.ts +3 -2
- package/dist/shims/root-params.d.ts +11 -0
- package/dist/shims/root-params.js +24 -0
- package/dist/shims/root-params.js.map +1 -0
- package/dist/shims/router.js +1 -1
- package/dist/shims/server.d.ts +3 -1
- package/dist/shims/server.js +83 -5
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/thenable-params.d.ts +5 -0
- package/dist/shims/thenable-params.js +37 -0
- package/dist/shims/thenable-params.js.map +1 -0
- package/dist/shims/unified-request-context.d.ts +3 -2
- package/dist/shims/unified-request-context.js +3 -0
- package/dist/shims/unified-request-context.js.map +1 -1
- package/dist/shims/use-merged-ref.d.ts +7 -0
- package/dist/shims/use-merged-ref.js +40 -0
- package/dist/shims/use-merged-ref.js.map +1 -0
- package/dist/utils/cache-control-metadata.d.ts +6 -0
- package/dist/utils/cache-control-metadata.js +16 -0
- package/dist/utils/cache-control-metadata.js.map +1 -0
- package/package.json +6 -1
- package/dist/server/middleware-codegen.d.ts +0 -54
- package/dist/server/middleware-codegen.js +0 -414
- package/dist/server/middleware-codegen.js.map +0 -1
|
@@ -15,8 +15,8 @@ type AppPageFontPreload = {
|
|
|
15
15
|
type: string;
|
|
16
16
|
};
|
|
17
17
|
type AppPageRscStreamCapture = {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
/** Stream for createFromReadableStream (SSR). Always set. */ssrStream: ReadableStream<Uint8Array>; /** When capturing, the combined embed+capture stream. handleSsr consumes this. */
|
|
19
|
+
sideStream?: ReadableStream<Uint8Array>;
|
|
20
20
|
};
|
|
21
21
|
type BuildAppPageSpecialErrorResponseOptions = {
|
|
22
22
|
clearRequestContext: () => void;
|
|
@@ -74,8 +74,9 @@ declare function buildAppPageSpecialErrorResponse(options: BuildAppPageSpecialEr
|
|
|
74
74
|
declare function probeAppPageLayouts(options: ProbeAppPageLayoutsOptions): Promise<ProbeAppPageLayoutsResult>;
|
|
75
75
|
declare function probeAppPageComponent(options: ProbeAppPageComponentOptions): Promise<Response | null>;
|
|
76
76
|
declare function readAppPageTextStream(stream: ReadableStream<Uint8Array>): Promise<string>;
|
|
77
|
+
declare function readAppPageBinaryStream(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer>;
|
|
77
78
|
declare function teeAppPageRscStreamForCapture(stream: ReadableStream<Uint8Array>, shouldCapture: boolean): AppPageRscStreamCapture;
|
|
78
79
|
declare function buildAppPageFontLinkHeader(preloads: readonly AppPageFontPreload[] | null | undefined): string;
|
|
79
80
|
//#endregion
|
|
80
|
-
export { AppPageFontPreload, AppPageSpecialError, type ClassificationReason, LayoutClassificationOptions, type LayoutFlags, buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageTextStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
|
|
81
|
+
export { AppPageFontPreload, AppPageSpecialError, type ClassificationReason, LayoutClassificationOptions, type LayoutFlags, buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, readAppPageTextStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
|
|
81
82
|
//# sourceMappingURL=app-page-execution.d.ts.map
|
|
@@ -144,14 +144,11 @@ async function readAppPageBinaryStream(stream) {
|
|
|
144
144
|
return buffer.buffer;
|
|
145
145
|
}
|
|
146
146
|
function teeAppPageRscStreamForCapture(stream, shouldCapture) {
|
|
147
|
-
if (!shouldCapture) return {
|
|
148
|
-
|
|
149
|
-
responseStream: stream
|
|
150
|
-
};
|
|
151
|
-
const [responseStream, captureStream] = stream.tee();
|
|
147
|
+
if (!shouldCapture) return { ssrStream: stream };
|
|
148
|
+
const [ssrStream, sideStream] = stream.tee();
|
|
152
149
|
return {
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
ssrStream,
|
|
151
|
+
sideStream
|
|
155
152
|
};
|
|
156
153
|
}
|
|
157
154
|
function buildAppPageFontLinkHeader(preloads) {
|
|
@@ -159,6 +156,6 @@ function buildAppPageFontLinkHeader(preloads) {
|
|
|
159
156
|
return preloads.map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`).join(", ");
|
|
160
157
|
}
|
|
161
158
|
//#endregion
|
|
162
|
-
export { buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageTextStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
|
|
159
|
+
export { buildAppPageFontLinkHeader, buildAppPageSpecialErrorResponse, probeAppPageComponent, probeAppPageLayouts, readAppPageBinaryStream, readAppPageTextStream, resolveAppPageSpecialError, teeAppPageRscStreamForCapture };
|
|
163
160
|
|
|
164
161
|
//# sourceMappingURL=app-page-execution.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-page-execution.js","names":[],"sources":["../../src/server/app-page-execution.ts"],"sourcesContent":["import type { LayoutFlags } from \"./app-elements.js\";\nimport type { ClassificationReason } from \"../build/layout-classification-types.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\n\nexport type { LayoutFlags };\nexport type { ClassificationReason };\n\nexport type AppPageSpecialError =\n | { kind: \"redirect\"; location: string; statusCode: number }\n | { kind: \"http-access-fallback\"; statusCode: number };\n\nexport type AppPageFontPreload = {\n href: string;\n type: string;\n};\n\ntype AppPageRscStreamCapture = {\n capturedRscDataPromise: Promise<ArrayBuffer> | null;\n responseStream: ReadableStream<Uint8Array>;\n};\n\ntype BuildAppPageSpecialErrorResponseOptions = {\n clearRequestContext: () => void;\n middlewareContext?: { headers: Headers | null };\n renderFallbackPage?: (statusCode: number) => Promise<Response | null>;\n requestUrl: string;\n specialError: AppPageSpecialError;\n};\n\ntype ProbeAppPageLayoutsResult = {\n response: Response | null;\n layoutFlags: LayoutFlags;\n};\n\nexport type LayoutClassificationOptions = {\n /** Build-time classifications from segment config or module graph, keyed by layout index. */\n buildTimeClassifications?: ReadonlyMap<number, \"static\" | \"dynamic\"> | null;\n /**\n * Per-layout classification reasons keyed by layout index. Requires\n * `VINEXT_DEBUG_CLASSIFICATION` at BOTH lifecycle points: at build time so\n * the plugin patches the `__VINEXT_CLASS_REASONS` dispatch stub, and at\n * runtime so the route object actually calls it. Setting the flag only at\n * runtime leaves the stub returning `null`, and every build-time classified\n * layout will fall through to `{ layer: \"no-classifier\" }` in the debug\n * channel. The hot path never reads this and the wire payload is unchanged.\n */\n buildTimeReasons?: ReadonlyMap<number, ClassificationReason> | null;\n /**\n * Emits one log line per layout with the classification reason, keyed by\n * layout ID. Set by the generator when `VINEXT_DEBUG_CLASSIFICATION` is\n * active. When undefined, the probe loop skips debug emission entirely.\n */\n debugClassification?: (layoutId: string, reason: ClassificationReason) => void;\n /** Maps layout index to its layout ID (e.g. \"layout:/blog\"). */\n getLayoutId: (layoutIndex: number) => string;\n /** Runs a function with isolated dynamic usage tracking per layout. */\n runWithIsolatedDynamicScope: <T>(fn: () => T) => Promise<{ result: T; dynamicDetected: boolean }>;\n};\n\ntype ProbeAppPageLayoutsOptions = {\n layoutCount: number;\n onLayoutError: (error: unknown, layoutIndex: number) => Promise<Response | null>;\n probeLayoutAt: (layoutIndex: number) => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n /** When provided, enables per-layout static/dynamic classification. */\n classification?: LayoutClassificationOptions | null;\n};\n\ntype ProbeAppPageComponentOptions = {\n awaitAsyncResult: boolean;\n onError: (error: unknown) => Promise<Response | null>;\n probePage: () => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n};\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return Boolean(\n value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"then\" in value &&\n typeof value.then === \"function\",\n );\n}\n\nfunction getAppPageStatusText(statusCode: number): string {\n return statusCode === 403 ? \"Forbidden\" : statusCode === 401 ? \"Unauthorized\" : \"Not Found\";\n}\n\nfunction mergeAppPageSpecialErrorHeaders(\n response: Response,\n middlewareContext: { headers: Headers | null } | undefined,\n): Response {\n const headers = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(headers, middlewareContext?.headers ?? null);\n\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nexport function resolveAppPageSpecialError(error: unknown): AppPageSpecialError | null {\n if (!(error && typeof error === \"object\" && \"digest\" in error)) {\n return null;\n }\n\n const digest = String(error.digest);\n\n if (digest.startsWith(\"NEXT_REDIRECT;\")) {\n const parts = digest.split(\";\");\n return {\n kind: \"redirect\",\n location: decodeURIComponent(parts[2]),\n statusCode: parts[3] ? parseInt(parts[3], 10) : 307,\n };\n }\n\n if (digest === \"NEXT_NOT_FOUND\" || digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\")) {\n return {\n kind: \"http-access-fallback\",\n statusCode: digest === \"NEXT_NOT_FOUND\" ? 404 : parseInt(digest.split(\";\")[1], 10),\n };\n }\n\n return null;\n}\n\nexport async function buildAppPageSpecialErrorResponse(\n options: BuildAppPageSpecialErrorResponseOptions,\n): Promise<Response> {\n if (options.specialError.kind === \"redirect\") {\n options.clearRequestContext();\n const headers = new Headers({\n Location: new URL(options.specialError.location, options.requestUrl).toString(),\n });\n // Middleware may contribute response headers here, but redirect() owns the\n // status. Do not apply middlewareContext.status on special-error responses.\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);\n\n return new Response(null, {\n headers,\n status: options.specialError.statusCode,\n });\n }\n\n if (options.renderFallbackPage) {\n const fallbackResponse = await options.renderFallbackPage(options.specialError.statusCode);\n if (fallbackResponse) {\n return mergeAppPageSpecialErrorHeaders(fallbackResponse, options.middlewareContext);\n }\n }\n\n options.clearRequestContext();\n return mergeAppPageSpecialErrorHeaders(\n new Response(getAppPageStatusText(options.specialError.statusCode), {\n status: options.specialError.statusCode,\n }),\n options.middlewareContext,\n );\n}\n\n/** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */\nexport async function probeAppPageLayouts(\n options: ProbeAppPageLayoutsOptions,\n): Promise<ProbeAppPageLayoutsResult> {\n const layoutFlags: Record<string, \"s\" | \"d\"> = {};\n const cls = options.classification ?? null;\n\n const response = await options.runWithSuppressedHookWarning(async () => {\n for (let layoutIndex = options.layoutCount - 1; layoutIndex >= 0; layoutIndex--) {\n const buildTimeResult = cls?.buildTimeClassifications?.get(layoutIndex);\n\n if (cls && buildTimeResult) {\n // Build-time classified (Layer 1 or Layer 2): skip dynamic isolation,\n // but still probe for special errors (redirects, not-found).\n layoutFlags[cls.getLayoutId(layoutIndex)] = buildTimeResult === \"static\" ? \"s\" : \"d\";\n if (cls.debugClassification) {\n // `no-classifier` is the documented fallback for a layout that was\n // build-time classified but whose reason payload is absent — either\n // because the build was run without `VINEXT_DEBUG_CLASSIFICATION` or\n // because no Layer 1/2 classifier attached a reason. This is the sole\n // producer of the variant; see `layout-classification-types.ts`.\n cls.debugClassification(\n cls.getLayoutId(layoutIndex),\n cls.buildTimeReasons?.get(layoutIndex) ?? { layer: \"no-classifier\" },\n );\n }\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n continue;\n }\n\n if (cls) {\n // Layer 3: probe with isolated dynamic scope to detect per-layout\n // dynamic API usage (headers(), cookies(), connection(), etc.)\n try {\n const { dynamicDetected } = await cls.runWithIsolatedDynamicScope(() =>\n options.probeLayoutAt(layoutIndex),\n );\n layoutFlags[cls.getLayoutId(layoutIndex)] = dynamicDetected ? \"d\" : \"s\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: dynamicDetected ? \"dynamic\" : \"static\",\n });\n }\n } catch (error) {\n // Probe failed — conservatively treat as dynamic.\n layoutFlags[cls.getLayoutId(layoutIndex)] = \"d\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: \"dynamic\",\n error: error instanceof Error ? error.message : String(error),\n });\n }\n const errorResponse = await options.onLayoutError(error, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n continue;\n }\n\n // No classification options — original behavior\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n\n return null;\n });\n\n return { response, layoutFlags };\n}\n\nasync function probeLayoutForErrors(\n options: ProbeAppPageLayoutsOptions,\n layoutIndex: number,\n): Promise<Response | null> {\n try {\n const layoutResult = options.probeLayoutAt(layoutIndex);\n if (isPromiseLike(layoutResult)) {\n await layoutResult;\n }\n } catch (error) {\n return options.onLayoutError(error, layoutIndex);\n }\n return null;\n}\n\nexport async function probeAppPageComponent(\n options: ProbeAppPageComponentOptions,\n): Promise<Response | null> {\n return options.runWithSuppressedHookWarning(async () => {\n try {\n const pageResult = options.probePage();\n if (isPromiseLike(pageResult)) {\n if (options.awaitAsyncResult) {\n await pageResult;\n } else {\n void Promise.resolve(pageResult).catch(() => {});\n }\n }\n } catch (error) {\n return options.onError(error);\n }\n\n return null;\n });\n}\n\nexport async function readAppPageTextStream(stream: ReadableStream<Uint8Array>): Promise<string> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n}\n\nasync function readAppPageBinaryStream(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(value);\n totalLength += value.byteLength;\n }\n\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return buffer.buffer;\n}\n\nexport function teeAppPageRscStreamForCapture(\n stream: ReadableStream<Uint8Array>,\n shouldCapture: boolean,\n): AppPageRscStreamCapture {\n if (!shouldCapture) {\n return {\n capturedRscDataPromise: null,\n responseStream: stream,\n };\n }\n\n const [responseStream, captureStream] = stream.tee();\n return {\n capturedRscDataPromise: readAppPageBinaryStream(captureStream),\n responseStream,\n };\n}\n\nexport function buildAppPageFontLinkHeader(\n preloads: readonly AppPageFontPreload[] | null | undefined,\n): string {\n if (!preloads || preloads.length === 0) {\n return \"\";\n }\n\n return preloads\n .map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`)\n .join(\", \");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-page-execution.js","names":[],"sources":["../../src/server/app-page-execution.ts"],"sourcesContent":["import type { LayoutFlags } from \"./app-elements.js\";\nimport type { ClassificationReason } from \"../build/layout-classification-types.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\n\nexport type { LayoutFlags };\nexport type { ClassificationReason };\n\nexport type AppPageSpecialError =\n | { kind: \"redirect\"; location: string; statusCode: number }\n | { kind: \"http-access-fallback\"; statusCode: number };\n\nexport type AppPageFontPreload = {\n href: string;\n type: string;\n};\n\ntype AppPageRscStreamCapture = {\n /** Stream for createFromReadableStream (SSR). Always set. */\n ssrStream: ReadableStream<Uint8Array>;\n /** When capturing, the combined embed+capture stream. handleSsr consumes this. */\n sideStream?: ReadableStream<Uint8Array>;\n};\n\ntype BuildAppPageSpecialErrorResponseOptions = {\n clearRequestContext: () => void;\n middlewareContext?: { headers: Headers | null };\n renderFallbackPage?: (statusCode: number) => Promise<Response | null>;\n requestUrl: string;\n specialError: AppPageSpecialError;\n};\n\ntype ProbeAppPageLayoutsResult = {\n response: Response | null;\n layoutFlags: LayoutFlags;\n};\n\nexport type LayoutClassificationOptions = {\n /** Build-time classifications from segment config or module graph, keyed by layout index. */\n buildTimeClassifications?: ReadonlyMap<number, \"static\" | \"dynamic\"> | null;\n /**\n * Per-layout classification reasons keyed by layout index. Requires\n * `VINEXT_DEBUG_CLASSIFICATION` at BOTH lifecycle points: at build time so\n * the plugin patches the `__VINEXT_CLASS_REASONS` dispatch stub, and at\n * runtime so the route object actually calls it. Setting the flag only at\n * runtime leaves the stub returning `null`, and every build-time classified\n * layout will fall through to `{ layer: \"no-classifier\" }` in the debug\n * channel. The hot path never reads this and the wire payload is unchanged.\n */\n buildTimeReasons?: ReadonlyMap<number, ClassificationReason> | null;\n /**\n * Emits one log line per layout with the classification reason, keyed by\n * layout ID. Set by the generator when `VINEXT_DEBUG_CLASSIFICATION` is\n * active. When undefined, the probe loop skips debug emission entirely.\n */\n debugClassification?: (layoutId: string, reason: ClassificationReason) => void;\n /** Maps layout index to its layout ID (e.g. \"layout:/blog\"). */\n getLayoutId: (layoutIndex: number) => string;\n /** Runs a function with isolated dynamic usage tracking per layout. */\n runWithIsolatedDynamicScope: <T>(fn: () => T) => Promise<{ result: T; dynamicDetected: boolean }>;\n};\n\ntype ProbeAppPageLayoutsOptions = {\n layoutCount: number;\n onLayoutError: (error: unknown, layoutIndex: number) => Promise<Response | null>;\n probeLayoutAt: (layoutIndex: number) => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n /** When provided, enables per-layout static/dynamic classification. */\n classification?: LayoutClassificationOptions | null;\n};\n\ntype ProbeAppPageComponentOptions = {\n awaitAsyncResult: boolean;\n onError: (error: unknown) => Promise<Response | null>;\n probePage: () => unknown;\n runWithSuppressedHookWarning<T>(probe: () => Promise<T>): Promise<T>;\n};\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return Boolean(\n value &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"then\" in value &&\n typeof value.then === \"function\",\n );\n}\n\nfunction getAppPageStatusText(statusCode: number): string {\n return statusCode === 403 ? \"Forbidden\" : statusCode === 401 ? \"Unauthorized\" : \"Not Found\";\n}\n\nfunction mergeAppPageSpecialErrorHeaders(\n response: Response,\n middlewareContext: { headers: Headers | null } | undefined,\n): Response {\n const headers = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(headers, middlewareContext?.headers ?? null);\n\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nexport function resolveAppPageSpecialError(error: unknown): AppPageSpecialError | null {\n if (!(error && typeof error === \"object\" && \"digest\" in error)) {\n return null;\n }\n\n const digest = String(error.digest);\n\n if (digest.startsWith(\"NEXT_REDIRECT;\")) {\n const parts = digest.split(\";\");\n return {\n kind: \"redirect\",\n location: decodeURIComponent(parts[2]),\n statusCode: parts[3] ? parseInt(parts[3], 10) : 307,\n };\n }\n\n if (digest === \"NEXT_NOT_FOUND\" || digest.startsWith(\"NEXT_HTTP_ERROR_FALLBACK;\")) {\n return {\n kind: \"http-access-fallback\",\n statusCode: digest === \"NEXT_NOT_FOUND\" ? 404 : parseInt(digest.split(\";\")[1], 10),\n };\n }\n\n return null;\n}\n\nexport async function buildAppPageSpecialErrorResponse(\n options: BuildAppPageSpecialErrorResponseOptions,\n): Promise<Response> {\n if (options.specialError.kind === \"redirect\") {\n options.clearRequestContext();\n const headers = new Headers({\n Location: new URL(options.specialError.location, options.requestUrl).toString(),\n });\n // Middleware may contribute response headers here, but redirect() owns the\n // status. Do not apply middlewareContext.status on special-error responses.\n mergeMiddlewareResponseHeaders(headers, options.middlewareContext?.headers ?? null);\n\n return new Response(null, {\n headers,\n status: options.specialError.statusCode,\n });\n }\n\n if (options.renderFallbackPage) {\n const fallbackResponse = await options.renderFallbackPage(options.specialError.statusCode);\n if (fallbackResponse) {\n return mergeAppPageSpecialErrorHeaders(fallbackResponse, options.middlewareContext);\n }\n }\n\n options.clearRequestContext();\n return mergeAppPageSpecialErrorHeaders(\n new Response(getAppPageStatusText(options.specialError.statusCode), {\n status: options.specialError.statusCode,\n }),\n options.middlewareContext,\n );\n}\n\n/** See `LayoutFlags` type docblock in app-elements.ts for lifecycle. */\nexport async function probeAppPageLayouts(\n options: ProbeAppPageLayoutsOptions,\n): Promise<ProbeAppPageLayoutsResult> {\n const layoutFlags: Record<string, \"s\" | \"d\"> = {};\n const cls = options.classification ?? null;\n\n const response = await options.runWithSuppressedHookWarning(async () => {\n for (let layoutIndex = options.layoutCount - 1; layoutIndex >= 0; layoutIndex--) {\n const buildTimeResult = cls?.buildTimeClassifications?.get(layoutIndex);\n\n if (cls && buildTimeResult) {\n // Build-time classified (Layer 1 or Layer 2): skip dynamic isolation,\n // but still probe for special errors (redirects, not-found).\n layoutFlags[cls.getLayoutId(layoutIndex)] = buildTimeResult === \"static\" ? \"s\" : \"d\";\n if (cls.debugClassification) {\n // `no-classifier` is the documented fallback for a layout that was\n // build-time classified but whose reason payload is absent — either\n // because the build was run without `VINEXT_DEBUG_CLASSIFICATION` or\n // because no Layer 1/2 classifier attached a reason. This is the sole\n // producer of the variant; see `layout-classification-types.ts`.\n cls.debugClassification(\n cls.getLayoutId(layoutIndex),\n cls.buildTimeReasons?.get(layoutIndex) ?? { layer: \"no-classifier\" },\n );\n }\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n continue;\n }\n\n if (cls) {\n // Layer 3: probe with isolated dynamic scope to detect per-layout\n // dynamic API usage (headers(), cookies(), connection(), etc.)\n try {\n const { dynamicDetected } = await cls.runWithIsolatedDynamicScope(() =>\n options.probeLayoutAt(layoutIndex),\n );\n layoutFlags[cls.getLayoutId(layoutIndex)] = dynamicDetected ? \"d\" : \"s\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: dynamicDetected ? \"dynamic\" : \"static\",\n });\n }\n } catch (error) {\n // Probe failed — conservatively treat as dynamic.\n layoutFlags[cls.getLayoutId(layoutIndex)] = \"d\";\n if (cls.debugClassification) {\n cls.debugClassification(cls.getLayoutId(layoutIndex), {\n layer: \"runtime-probe\",\n outcome: \"dynamic\",\n error: error instanceof Error ? error.message : String(error),\n });\n }\n const errorResponse = await options.onLayoutError(error, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n continue;\n }\n\n // No classification options — original behavior\n const errorResponse = await probeLayoutForErrors(options, layoutIndex);\n if (errorResponse) return errorResponse;\n }\n\n return null;\n });\n\n return { response, layoutFlags };\n}\n\nasync function probeLayoutForErrors(\n options: ProbeAppPageLayoutsOptions,\n layoutIndex: number,\n): Promise<Response | null> {\n try {\n const layoutResult = options.probeLayoutAt(layoutIndex);\n if (isPromiseLike(layoutResult)) {\n await layoutResult;\n }\n } catch (error) {\n return options.onLayoutError(error, layoutIndex);\n }\n return null;\n}\n\nexport async function probeAppPageComponent(\n options: ProbeAppPageComponentOptions,\n): Promise<Response | null> {\n return options.runWithSuppressedHookWarning(async () => {\n try {\n const pageResult = options.probePage();\n if (isPromiseLike(pageResult)) {\n if (options.awaitAsyncResult) {\n await pageResult;\n } else {\n void Promise.resolve(pageResult).catch(() => {});\n }\n }\n } catch (error) {\n return options.onError(error);\n }\n\n return null;\n });\n}\n\nexport async function readAppPageTextStream(stream: ReadableStream<Uint8Array>): Promise<string> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const chunks: string[] = [];\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n\n chunks.push(decoder.decode());\n return chunks.join(\"\");\n}\n\nexport async function readAppPageBinaryStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<ArrayBuffer> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(value);\n totalLength += value.byteLength;\n }\n\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return buffer.buffer;\n}\n\nexport function teeAppPageRscStreamForCapture(\n stream: ReadableStream<Uint8Array>,\n shouldCapture: boolean,\n): AppPageRscStreamCapture {\n if (!shouldCapture) {\n return {\n ssrStream: stream,\n };\n }\n\n const [ssrStream, sideStream] = stream.tee();\n return {\n ssrStream,\n sideStream,\n };\n}\n\nexport function buildAppPageFontLinkHeader(\n preloads: readonly AppPageFontPreload[] | null | undefined,\n): string {\n if (!preloads || preloads.length === 0) {\n return \"\";\n }\n\n return preloads\n .map((preload) => `<${preload.href}>; rel=preload; as=font; type=${preload.type}; crossorigin`)\n .join(\", \");\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { MetadataFileRoute } from "./metadata-routes.js";
|
|
2
|
+
import { AppPageParams } from "./app-page-boundary.js";
|
|
3
|
+
import { Metadata, Viewport } from "../shims/metadata.js";
|
|
4
|
+
|
|
5
|
+
//#region src/server/app-page-head.d.ts
|
|
6
|
+
type AppPageSearchParams = Record<string, string | string[]>;
|
|
7
|
+
type AppPageHeadModule = Record<string, unknown>;
|
|
8
|
+
type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
9
|
+
layoutModule?: TModule | null;
|
|
10
|
+
layoutModules?: readonly (TModule | null | undefined)[] | null;
|
|
11
|
+
pageModule?: TModule | null;
|
|
12
|
+
params?: AppPageParams | null;
|
|
13
|
+
routeSegments?: readonly string[] | null;
|
|
14
|
+
};
|
|
15
|
+
type AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
16
|
+
layout?: TModule | null;
|
|
17
|
+
page?: TModule | null;
|
|
18
|
+
};
|
|
19
|
+
type ResolveActiveParallelRouteHeadInputsOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
20
|
+
interceptLayouts?: readonly (TModule | null | undefined)[] | null;
|
|
21
|
+
interceptPage?: TModule | null;
|
|
22
|
+
interceptParams?: AppPageParams | null;
|
|
23
|
+
interceptSlotKey?: string | null;
|
|
24
|
+
params: AppPageParams;
|
|
25
|
+
routeSegments: readonly string[];
|
|
26
|
+
slots?: Record<string, AppPageHeadSlot<TModule>> | null;
|
|
27
|
+
};
|
|
28
|
+
type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {
|
|
29
|
+
fallbackOnFileMetadataError?: boolean;
|
|
30
|
+
layoutModules: readonly (TModule | null | undefined)[];
|
|
31
|
+
layoutTreePositions?: readonly number[] | null;
|
|
32
|
+
metadataRoutes: readonly MetadataFileRoute[];
|
|
33
|
+
pageModule?: TModule | null;
|
|
34
|
+
parallelRoutes?: readonly AppPageHeadParallelRoute<TModule>[] | null;
|
|
35
|
+
params: AppPageParams;
|
|
36
|
+
routePath: string;
|
|
37
|
+
routeSegments?: readonly string[] | null;
|
|
38
|
+
searchParams?: URLSearchParams | null;
|
|
39
|
+
};
|
|
40
|
+
type ResolveAppPageHeadResult = {
|
|
41
|
+
hasSearchParams: boolean;
|
|
42
|
+
metadata: Metadata | null;
|
|
43
|
+
pageSearchParams: AppPageSearchParams;
|
|
44
|
+
viewport: Viewport;
|
|
45
|
+
};
|
|
46
|
+
type AppPageSearchParamsCollection = {
|
|
47
|
+
hasSearchParams: boolean;
|
|
48
|
+
pageSearchParams: AppPageSearchParams;
|
|
49
|
+
};
|
|
50
|
+
declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(options: ResolveActiveParallelRouteHeadInputsOptions<TModule>): AppPageHeadParallelRoute<TModule>[];
|
|
51
|
+
declare function collectAppPageSearchParams(searchParams: URLSearchParams | null | undefined): AppPageSearchParamsCollection;
|
|
52
|
+
declare function resolveAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): Promise<ResolveAppPageHeadResult>;
|
|
53
|
+
//#endregion
|
|
54
|
+
export { collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
55
|
+
//# sourceMappingURL=app-page-head.d.ts.map
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { mergeMetadataEntries, mergeViewport, resolveModuleMetadata, resolveModuleViewport } from "../shims/metadata.js";
|
|
2
|
+
import { resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
3
|
+
import { applyFileBasedMetadata } from "./file-based-metadata.js";
|
|
4
|
+
//#region src/server/app-page-head.ts
|
|
5
|
+
function resolveActiveParallelRouteHeadInputs(options) {
|
|
6
|
+
return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {
|
|
7
|
+
if (options.interceptSlotKey === slotKey && options.interceptPage) return {
|
|
8
|
+
layoutModules: options.interceptLayouts ?? [],
|
|
9
|
+
pageModule: options.interceptPage,
|
|
10
|
+
params: options.interceptParams ?? options.params,
|
|
11
|
+
routeSegments: options.routeSegments
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
layoutModules: slot.layout ? [slot.layout] : [],
|
|
15
|
+
pageModule: slot.page,
|
|
16
|
+
params: options.params,
|
|
17
|
+
routeSegments: options.routeSegments
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function isPresent(value) {
|
|
22
|
+
return value !== null && value !== void 0;
|
|
23
|
+
}
|
|
24
|
+
function collectAppPageSearchParams(searchParams) {
|
|
25
|
+
const pageSearchParams = Object.create(null);
|
|
26
|
+
let hasSearchParams = false;
|
|
27
|
+
searchParams?.forEach((value, key) => {
|
|
28
|
+
hasSearchParams = true;
|
|
29
|
+
const currentValue = pageSearchParams[key];
|
|
30
|
+
if (Array.isArray(currentValue)) {
|
|
31
|
+
pageSearchParams[key] = [...currentValue, value];
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (currentValue !== void 0) {
|
|
35
|
+
pageSearchParams[key] = [currentValue, value];
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
pageSearchParams[key] = value;
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
hasSearchParams,
|
|
42
|
+
pageSearchParams
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createMetadataSources(metadataResults, routeSegments, layoutTreePositions, pageMetadata, includePageSource) {
|
|
46
|
+
const metadataSources = metadataResults.map((metadata, index) => ({
|
|
47
|
+
routeSegments: routeSegments.slice(0, layoutTreePositions[index] ?? 0),
|
|
48
|
+
metadata
|
|
49
|
+
}));
|
|
50
|
+
if (includePageSource) metadataSources.push({
|
|
51
|
+
routeSegments,
|
|
52
|
+
metadata: pageMetadata
|
|
53
|
+
});
|
|
54
|
+
return metadataSources;
|
|
55
|
+
}
|
|
56
|
+
function createLayoutInputs(layoutModules, layoutTreePositions) {
|
|
57
|
+
const layoutInputs = [];
|
|
58
|
+
for (let index = 0; index < layoutModules.length; index++) {
|
|
59
|
+
const layoutModule = layoutModules[index];
|
|
60
|
+
if (!isPresent(layoutModule)) continue;
|
|
61
|
+
layoutInputs.push({
|
|
62
|
+
module: layoutModule,
|
|
63
|
+
treePosition: layoutTreePositions[index] ?? 0
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return layoutInputs;
|
|
67
|
+
}
|
|
68
|
+
async function resolveLayoutMetadata(layoutInputs, params, routeSegments) {
|
|
69
|
+
const layoutMetadataPromises = [];
|
|
70
|
+
let accumulatedMetadata = Promise.resolve({});
|
|
71
|
+
for (const layoutInput of layoutInputs) {
|
|
72
|
+
const parentForLayout = accumulatedMetadata;
|
|
73
|
+
const layoutParams = resolveAppPageSegmentParams(routeSegments, layoutInput.treePosition, params);
|
|
74
|
+
const metadataPromise = resolveModuleMetadata(layoutInput.module, layoutParams, void 0, parentForLayout);
|
|
75
|
+
layoutMetadataPromises.push(metadataPromise);
|
|
76
|
+
metadataPromise.catch(() => null);
|
|
77
|
+
accumulatedMetadata = metadataPromise.then(async (metadataResult) => {
|
|
78
|
+
if (metadataResult) return mergeMetadataEntries([{ metadata: await parentForLayout }, { metadata: metadataResult }]);
|
|
79
|
+
return parentForLayout;
|
|
80
|
+
});
|
|
81
|
+
accumulatedMetadata.catch(() => null);
|
|
82
|
+
}
|
|
83
|
+
return Promise.all(layoutMetadataPromises);
|
|
84
|
+
}
|
|
85
|
+
async function resolveLayoutViewport(layoutInputs, params, routeSegments) {
|
|
86
|
+
return Promise.all(layoutInputs.map((layoutInput) => {
|
|
87
|
+
const layoutParams = resolveAppPageSegmentParams(routeSegments, layoutInput.treePosition, params);
|
|
88
|
+
return resolveModuleViewport(layoutInput.module, layoutParams);
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
async function resolveParallelRouteHead(parallelRoute, fallbackParams, fallbackRouteSegments, pageSearchParams, parent) {
|
|
92
|
+
const params = parallelRoute.params ?? fallbackParams;
|
|
93
|
+
const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;
|
|
94
|
+
const metadataResults = [];
|
|
95
|
+
const viewportResults = [];
|
|
96
|
+
const metadataSources = [];
|
|
97
|
+
let accumulatedMetadata = parent;
|
|
98
|
+
const layoutModules = [...parallelRoute.layoutModules ?? [], parallelRoute.layoutModule].filter(isPresent);
|
|
99
|
+
const layoutViewportPromises = layoutModules.map((layoutModule) => resolveModuleViewport(layoutModule, params));
|
|
100
|
+
const pageViewportPromise = parallelRoute.pageModule ? resolveModuleViewport(parallelRoute.pageModule, params) : Promise.resolve(null);
|
|
101
|
+
for (const layoutViewportPromise of layoutViewportPromises) layoutViewportPromise.catch(() => null);
|
|
102
|
+
pageViewportPromise.catch(() => null);
|
|
103
|
+
for (const layoutModule of layoutModules) {
|
|
104
|
+
const layoutMetadata = await resolveModuleMetadata(layoutModule, params, void 0, accumulatedMetadata);
|
|
105
|
+
metadataResults.push(layoutMetadata);
|
|
106
|
+
metadataSources.push({
|
|
107
|
+
metadata: layoutMetadata,
|
|
108
|
+
routeSegments
|
|
109
|
+
});
|
|
110
|
+
if (layoutMetadata) {
|
|
111
|
+
accumulatedMetadata = accumulatedMetadata.then(async (parentMetadata) => mergeMetadataEntries([{ metadata: parentMetadata }, { metadata: layoutMetadata }]));
|
|
112
|
+
accumulatedMetadata.catch(() => null);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (parallelRoute.pageModule) {
|
|
116
|
+
const pageMetadata = await resolveModuleMetadata(parallelRoute.pageModule, params, pageSearchParams, accumulatedMetadata);
|
|
117
|
+
metadataResults.push(pageMetadata);
|
|
118
|
+
metadataSources.push({
|
|
119
|
+
metadata: pageMetadata,
|
|
120
|
+
routeSegments
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
viewportResults.push(...await Promise.all(layoutViewportPromises));
|
|
124
|
+
const pageViewport = await pageViewportPromise;
|
|
125
|
+
if (parallelRoute.pageModule) viewportResults.push(pageViewport);
|
|
126
|
+
return {
|
|
127
|
+
metadataResults,
|
|
128
|
+
metadataSources,
|
|
129
|
+
viewportResults
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
async function resolveAppPageHead(options) {
|
|
133
|
+
const routeSegments = options.routeSegments ?? [];
|
|
134
|
+
const layoutTreePositions = options.layoutTreePositions ?? [];
|
|
135
|
+
const layoutInputs = createLayoutInputs(options.layoutModules, layoutTreePositions);
|
|
136
|
+
const layoutSourcePositions = layoutInputs.map((input) => input.treePosition);
|
|
137
|
+
const { hasSearchParams, pageSearchParams } = collectAppPageSearchParams(options.searchParams);
|
|
138
|
+
const layoutMetadataPromise = resolveLayoutMetadata(layoutInputs, options.params, routeSegments);
|
|
139
|
+
const layoutViewportPromise = resolveLayoutViewport(layoutInputs, options.params, routeSegments);
|
|
140
|
+
const layoutMetadataResultsForParent = layoutMetadataPromise.then((metadataResults) => metadataResults.filter(isPresent));
|
|
141
|
+
layoutMetadataResultsForParent.catch(() => null);
|
|
142
|
+
const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) => metadataResults.length > 0 ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata }))) : {});
|
|
143
|
+
pageParentPromise.catch(() => null);
|
|
144
|
+
const pageMetadataPromise = options.pageModule ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise) : Promise.resolve(null);
|
|
145
|
+
const pageViewportPromise = options.pageModule ? resolveModuleViewport(options.pageModule, options.params) : Promise.resolve(null);
|
|
146
|
+
const parallelRouteHeadPromise = Promise.all((options.parallelRoutes ?? []).map((parallelRoute) => resolveParallelRouteHead(parallelRoute, options.params, routeSegments, pageSearchParams, pageParentPromise)));
|
|
147
|
+
const [layoutMetadataResults, layoutViewportResults, pageMetadata, pageViewport, parallelRouteHeads] = await Promise.all([
|
|
148
|
+
layoutMetadataPromise,
|
|
149
|
+
layoutViewportPromise,
|
|
150
|
+
pageMetadataPromise,
|
|
151
|
+
pageViewportPromise,
|
|
152
|
+
parallelRouteHeadPromise
|
|
153
|
+
]);
|
|
154
|
+
const parallelMetadataResults = parallelRouteHeads.flatMap((head) => head.metadataResults);
|
|
155
|
+
const parallelViewportResults = parallelRouteHeads.flatMap((head) => head.viewportResults);
|
|
156
|
+
const parallelMetadataSources = parallelRouteHeads.flatMap((head) => head.metadataSources);
|
|
157
|
+
const metadataEntries = [
|
|
158
|
+
...layoutMetadataResults.filter(isPresent).map((metadata) => ({ metadata })),
|
|
159
|
+
...pageMetadata ? [{
|
|
160
|
+
isPage: true,
|
|
161
|
+
metadata: pageMetadata
|
|
162
|
+
}] : [],
|
|
163
|
+
...parallelMetadataResults.filter(isPresent).map((metadata) => ({
|
|
164
|
+
contributesTitle: false,
|
|
165
|
+
metadata
|
|
166
|
+
}))
|
|
167
|
+
];
|
|
168
|
+
const viewportList = [
|
|
169
|
+
...layoutViewportResults.filter(isPresent),
|
|
170
|
+
...pageViewport ? [pageViewport] : [],
|
|
171
|
+
...parallelViewportResults.filter(isPresent)
|
|
172
|
+
];
|
|
173
|
+
const resolvedMetadataBase = metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null;
|
|
174
|
+
const metadataSources = createMetadataSources(layoutMetadataResults, routeSegments, layoutSourcePositions, pageMetadata, Boolean(options.pageModule));
|
|
175
|
+
metadataSources.push(...parallelMetadataSources);
|
|
176
|
+
let metadata = resolvedMetadataBase;
|
|
177
|
+
try {
|
|
178
|
+
metadata = await applyFileBasedMetadata(resolvedMetadataBase, options.routePath, options.params, options.metadataRoutes, {
|
|
179
|
+
routeSegments,
|
|
180
|
+
metadataSources
|
|
181
|
+
});
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (!options.fallbackOnFileMetadataError) throw error;
|
|
184
|
+
console.error(`[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`, error);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
hasSearchParams,
|
|
188
|
+
metadata,
|
|
189
|
+
pageSearchParams,
|
|
190
|
+
viewport: mergeViewport(viewportList)
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
export { collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
|
|
195
|
+
|
|
196
|
+
//# sourceMappingURL=app-page-head.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-page-head.js","names":[],"sources":["../../src/server/app-page-head.ts"],"sourcesContent":["import {\n mergeMetadataEntries,\n mergeViewport,\n resolveModuleMetadata,\n resolveModuleViewport,\n type Metadata,\n type MetadataMergeEntry,\n type Viewport,\n} from \"vinext/shims/metadata\";\nimport { applyFileBasedMetadata } from \"./file-based-metadata.js\";\nimport type { AppPageParams } from \"./app-page-boundary.js\";\nimport { resolveAppPageSegmentParams } from \"./app-page-params.js\";\nimport type { MetadataFileRoute } from \"./metadata-routes.js\";\n\ntype AppPageSearchParams = Record<string, string | string[]>;\n\ntype AppPageHeadModule = Record<string, unknown>;\n\ntype AppPageHeadSource = {\n metadata: Metadata | null;\n routeSegments: readonly string[];\n};\n\ntype AppPageHeadLayout<TModule extends AppPageHeadModule> = {\n module: TModule;\n treePosition: number;\n};\n\ntype AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n layoutModule?: TModule | null;\n layoutModules?: readonly (TModule | null | undefined)[] | null;\n pageModule?: TModule | null;\n params?: AppPageParams | null;\n routeSegments?: readonly string[] | null;\n};\n\ntype AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n layout?: TModule | null;\n page?: TModule | null;\n};\n\ntype ResolveActiveParallelRouteHeadInputsOptions<\n TModule extends AppPageHeadModule = AppPageHeadModule,\n> = {\n interceptLayouts?: readonly (TModule | null | undefined)[] | null;\n interceptPage?: TModule | null;\n interceptParams?: AppPageParams | null;\n interceptSlotKey?: string | null;\n params: AppPageParams;\n routeSegments: readonly string[];\n slots?: Record<string, AppPageHeadSlot<TModule>> | null;\n};\n\ntype ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = {\n fallbackOnFileMetadataError?: boolean;\n layoutModules: readonly (TModule | null | undefined)[];\n layoutTreePositions?: readonly number[] | null;\n metadataRoutes: readonly MetadataFileRoute[];\n pageModule?: TModule | null;\n parallelRoutes?: readonly AppPageHeadParallelRoute<TModule>[] | null;\n params: AppPageParams;\n routePath: string;\n routeSegments?: readonly string[] | null;\n searchParams?: URLSearchParams | null;\n};\n\ntype ResolveAppPageHeadResult = {\n hasSearchParams: boolean;\n metadata: Metadata | null;\n pageSearchParams: AppPageSearchParams;\n viewport: Viewport;\n};\n\ntype AppPageSearchParamsCollection = {\n hasSearchParams: boolean;\n pageSearchParams: AppPageSearchParams;\n};\n\ntype ResolvedParallelRouteHead = {\n metadataResults: (Metadata | null)[];\n metadataSources: AppPageHeadSource[];\n viewportResults: (Viewport | null)[];\n};\n\nexport function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(\n options: ResolveActiveParallelRouteHeadInputsOptions<TModule>,\n): AppPageHeadParallelRoute<TModule>[] {\n return Object.entries(options.slots ?? {}).map(([slotKey, slot]) => {\n if (options.interceptSlotKey === slotKey && options.interceptPage) {\n return {\n layoutModules: options.interceptLayouts ?? [],\n pageModule: options.interceptPage,\n params: options.interceptParams ?? options.params,\n routeSegments: options.routeSegments,\n };\n }\n\n return {\n layoutModules: slot.layout ? [slot.layout] : [],\n pageModule: slot.page,\n params: options.params,\n routeSegments: options.routeSegments,\n };\n });\n}\n\nfunction isPresent<T>(value: T | null | undefined): value is T {\n return value !== null && value !== undefined;\n}\n\nexport function collectAppPageSearchParams(\n searchParams: URLSearchParams | null | undefined,\n): AppPageSearchParamsCollection {\n const pageSearchParams: AppPageSearchParams = Object.create(null);\n let hasSearchParams = false;\n\n searchParams?.forEach((value, key) => {\n hasSearchParams = true;\n const currentValue = pageSearchParams[key];\n if (Array.isArray(currentValue)) {\n pageSearchParams[key] = [...currentValue, value];\n return;\n }\n if (currentValue !== undefined) {\n pageSearchParams[key] = [currentValue, value];\n return;\n }\n pageSearchParams[key] = value;\n });\n\n return { hasSearchParams, pageSearchParams };\n}\n\nfunction createMetadataSources(\n metadataResults: readonly (Metadata | null)[],\n routeSegments: readonly string[],\n layoutTreePositions: readonly number[],\n pageMetadata: Metadata | null,\n includePageSource: boolean,\n): AppPageHeadSource[] {\n const metadataSources: AppPageHeadSource[] = metadataResults.map((metadata, index) => ({\n routeSegments: routeSegments.slice(0, layoutTreePositions[index] ?? 0),\n metadata,\n }));\n\n if (includePageSource) {\n metadataSources.push({\n routeSegments,\n metadata: pageMetadata,\n });\n }\n\n return metadataSources;\n}\n\nfunction createLayoutInputs<TModule extends AppPageHeadModule>(\n layoutModules: readonly (TModule | null | undefined)[],\n layoutTreePositions: readonly number[],\n): AppPageHeadLayout<TModule>[] {\n const layoutInputs: AppPageHeadLayout<TModule>[] = [];\n\n for (let index = 0; index < layoutModules.length; index++) {\n const layoutModule = layoutModules[index];\n if (!isPresent(layoutModule)) {\n continue;\n }\n layoutInputs.push({\n module: layoutModule,\n treePosition: layoutTreePositions[index] ?? 0,\n });\n }\n\n return layoutInputs;\n}\n\nasync function resolveLayoutMetadata<TModule extends AppPageHeadModule>(\n layoutInputs: readonly AppPageHeadLayout<TModule>[],\n params: AppPageParams,\n routeSegments: readonly string[],\n): Promise<(Metadata | null)[]> {\n const layoutMetadataPromises: Promise<Metadata | null>[] = [];\n let accumulatedMetadata = Promise.resolve<Metadata>({});\n\n for (const layoutInput of layoutInputs) {\n const parentForLayout = accumulatedMetadata;\n const layoutParams = resolveAppPageSegmentParams(\n routeSegments,\n layoutInput.treePosition,\n params,\n );\n const metadataPromise = resolveModuleMetadata(\n layoutInput.module,\n layoutParams,\n undefined,\n parentForLayout,\n );\n layoutMetadataPromises.push(metadataPromise);\n void metadataPromise.catch(() => null);\n\n accumulatedMetadata = metadataPromise.then(async (metadataResult) => {\n if (metadataResult) {\n return mergeMetadataEntries([\n { metadata: await parentForLayout },\n { metadata: metadataResult },\n ]);\n }\n return parentForLayout;\n });\n void accumulatedMetadata.catch(() => null);\n }\n\n return Promise.all(layoutMetadataPromises);\n}\n\nasync function resolveLayoutViewport<TModule extends AppPageHeadModule>(\n layoutInputs: readonly AppPageHeadLayout<TModule>[],\n params: AppPageParams,\n routeSegments: readonly string[],\n): Promise<(Viewport | null)[]> {\n return Promise.all(\n layoutInputs.map((layoutInput) => {\n const layoutParams = resolveAppPageSegmentParams(\n routeSegments,\n layoutInput.treePosition,\n params,\n );\n return resolveModuleViewport(layoutInput.module, layoutParams);\n }),\n );\n}\n\nasync function resolveParallelRouteHead<TModule extends AppPageHeadModule>(\n parallelRoute: AppPageHeadParallelRoute<TModule>,\n fallbackParams: AppPageParams,\n fallbackRouteSegments: readonly string[],\n pageSearchParams: AppPageSearchParams,\n parent: Promise<Metadata>,\n): Promise<ResolvedParallelRouteHead> {\n const params = parallelRoute.params ?? fallbackParams;\n const routeSegments = parallelRoute.routeSegments ?? fallbackRouteSegments;\n const metadataResults: (Metadata | null)[] = [];\n const viewportResults: (Viewport | null)[] = [];\n const metadataSources: AppPageHeadSource[] = [];\n let accumulatedMetadata = parent;\n const layoutModules = [...(parallelRoute.layoutModules ?? []), parallelRoute.layoutModule].filter(\n isPresent,\n );\n const layoutViewportPromises = layoutModules.map((layoutModule) =>\n resolveModuleViewport(layoutModule, params),\n );\n const pageViewportPromise = parallelRoute.pageModule\n ? resolveModuleViewport(parallelRoute.pageModule, params)\n : Promise.resolve(null);\n for (const layoutViewportPromise of layoutViewportPromises) {\n void layoutViewportPromise.catch(() => null);\n }\n void pageViewportPromise.catch(() => null);\n\n for (const layoutModule of layoutModules) {\n const layoutMetadata = await resolveModuleMetadata(\n layoutModule,\n params,\n undefined,\n accumulatedMetadata,\n );\n metadataResults.push(layoutMetadata);\n // Parallel route metadata sources are scoped to the active slot branch because\n // the route tree input does not carry per-layout segment positions inside that branch.\n metadataSources.push({ metadata: layoutMetadata, routeSegments });\n if (layoutMetadata) {\n const parentForLayout = accumulatedMetadata;\n accumulatedMetadata = parentForLayout.then(async (parentMetadata) =>\n mergeMetadataEntries([{ metadata: parentMetadata }, { metadata: layoutMetadata }]),\n );\n void accumulatedMetadata.catch(() => null);\n }\n }\n\n if (parallelRoute.pageModule) {\n const pageMetadata = await resolveModuleMetadata(\n parallelRoute.pageModule,\n params,\n pageSearchParams,\n accumulatedMetadata,\n );\n metadataResults.push(pageMetadata);\n // Keep the page source scoped to the same active slot branch as its layouts.\n metadataSources.push({ metadata: pageMetadata, routeSegments });\n }\n\n viewportResults.push(...(await Promise.all(layoutViewportPromises)));\n const pageViewport = await pageViewportPromise;\n if (parallelRoute.pageModule) {\n viewportResults.push(pageViewport);\n }\n\n return { metadataResults, metadataSources, viewportResults };\n}\n\nexport async function resolveAppPageHead<TModule extends AppPageHeadModule>(\n options: ResolveAppPageHeadOptions<TModule>,\n): Promise<ResolveAppPageHeadResult> {\n const routeSegments = options.routeSegments ?? [];\n const layoutTreePositions = options.layoutTreePositions ?? [];\n const layoutInputs = createLayoutInputs(options.layoutModules, layoutTreePositions);\n const layoutSourcePositions = layoutInputs.map((input) => input.treePosition);\n const { hasSearchParams, pageSearchParams } = collectAppPageSearchParams(options.searchParams);\n const layoutMetadataPromise = resolveLayoutMetadata(layoutInputs, options.params, routeSegments);\n const layoutViewportPromise = resolveLayoutViewport(layoutInputs, options.params, routeSegments);\n\n const layoutMetadataResultsForParent = layoutMetadataPromise.then((metadataResults) =>\n metadataResults.filter(isPresent),\n );\n void layoutMetadataResultsForParent.catch(() => null);\n const pageParentPromise = layoutMetadataResultsForParent.then((metadataResults) =>\n metadataResults.length > 0\n ? mergeMetadataEntries(metadataResults.map((metadata) => ({ metadata })))\n : {},\n );\n void pageParentPromise.catch(() => null);\n const pageMetadataPromise = options.pageModule\n ? resolveModuleMetadata(options.pageModule, options.params, pageSearchParams, pageParentPromise)\n : Promise.resolve(null);\n const pageViewportPromise = options.pageModule\n ? resolveModuleViewport(options.pageModule, options.params)\n : Promise.resolve(null);\n const parallelRouteHeadPromise = Promise.all(\n (options.parallelRoutes ?? []).map((parallelRoute) =>\n resolveParallelRouteHead(\n parallelRoute,\n options.params,\n routeSegments,\n pageSearchParams,\n pageParentPromise,\n ),\n ),\n );\n\n const [\n layoutMetadataResults,\n layoutViewportResults,\n pageMetadata,\n pageViewport,\n parallelRouteHeads,\n ] = await Promise.all([\n layoutMetadataPromise,\n layoutViewportPromise,\n pageMetadataPromise,\n pageViewportPromise,\n parallelRouteHeadPromise,\n ]);\n const parallelMetadataResults = parallelRouteHeads.flatMap((head) => head.metadataResults);\n const parallelViewportResults = parallelRouteHeads.flatMap((head) => head.viewportResults);\n const parallelMetadataSources = parallelRouteHeads.flatMap((head) => head.metadataSources);\n\n const metadataEntries: MetadataMergeEntry[] = [\n ...layoutMetadataResults.filter(isPresent).map((metadata) => ({ metadata })),\n ...(pageMetadata ? [{ isPage: true, metadata: pageMetadata }] : []),\n ...parallelMetadataResults\n .filter(isPresent)\n .map((metadata) => ({ contributesTitle: false, metadata })),\n ];\n const viewportList = [\n ...layoutViewportResults.filter(isPresent),\n ...(pageViewport ? [pageViewport] : []),\n ...parallelViewportResults.filter(isPresent),\n ];\n\n const resolvedMetadataBase =\n metadataEntries.length > 0 ? mergeMetadataEntries(metadataEntries) : null;\n const metadataSources = createMetadataSources(\n layoutMetadataResults,\n routeSegments,\n layoutSourcePositions,\n pageMetadata,\n Boolean(options.pageModule),\n );\n metadataSources.push(...parallelMetadataSources);\n let metadata = resolvedMetadataBase;\n\n try {\n metadata = await applyFileBasedMetadata(\n resolvedMetadataBase,\n options.routePath,\n options.params,\n options.metadataRoutes,\n {\n routeSegments,\n metadataSources,\n },\n );\n } catch (error) {\n if (!options.fallbackOnFileMetadataError) {\n throw error;\n }\n console.error(\n `[vinext] File-based metadata resolution failed while rendering error boundary for ${options.routePath}:`,\n error,\n );\n }\n\n return {\n hasSearchParams,\n metadata,\n pageSearchParams,\n viewport: mergeViewport(viewportList),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/server/app-page-method.d.ts
|
|
2
|
+
type AppPageMethodPolicyOptions = {
|
|
3
|
+
dynamicConfig?: string;
|
|
4
|
+
hasGenerateStaticParams: boolean;
|
|
5
|
+
isDynamicRoute: boolean;
|
|
6
|
+
revalidateSeconds: number | null;
|
|
7
|
+
};
|
|
8
|
+
type ResolveAppPageMethodResponseOptions = {
|
|
9
|
+
middlewareHeaders?: Headers | null;
|
|
10
|
+
request: Pick<Request, "headers" | "method">;
|
|
11
|
+
} & AppPageMethodPolicyOptions;
|
|
12
|
+
declare function isStaticOrSsgAppPageCandidate(options: AppPageMethodPolicyOptions): boolean;
|
|
13
|
+
declare function resolveAppPageMethodResponse(options: ResolveAppPageMethodResponseOptions): Response | null;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { isStaticOrSsgAppPageCandidate, resolveAppPageMethodResponse };
|
|
16
|
+
//# sourceMappingURL=app-page-method.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
2
|
+
import { isPossibleAppRouteActionRequest } from "./app-route-handler-policy.js";
|
|
3
|
+
//#region src/server/app-page-method.ts
|
|
4
|
+
function isNonGetOrHead(method) {
|
|
5
|
+
const normalizedMethod = method.toUpperCase();
|
|
6
|
+
return normalizedMethod !== "GET" && normalizedMethod !== "HEAD";
|
|
7
|
+
}
|
|
8
|
+
function isStaticOrSsgAppPageCandidate(options) {
|
|
9
|
+
if (options.dynamicConfig === "force-dynamic" || options.revalidateSeconds === 0) return false;
|
|
10
|
+
if (options.dynamicConfig === "force-static" || options.dynamicConfig === "error") return true;
|
|
11
|
+
if (options.revalidateSeconds !== null && options.revalidateSeconds > 0) return true;
|
|
12
|
+
if (options.hasGenerateStaticParams) return true;
|
|
13
|
+
return !options.isDynamicRoute;
|
|
14
|
+
}
|
|
15
|
+
function resolveAppPageMethodResponse(options) {
|
|
16
|
+
if (!isNonGetOrHead(options.request.method)) return null;
|
|
17
|
+
if (isPossibleAppRouteActionRequest(options.request)) return null;
|
|
18
|
+
if (!isStaticOrSsgAppPageCandidate(options)) return null;
|
|
19
|
+
const headers = new Headers();
|
|
20
|
+
mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
|
|
21
|
+
headers.set("Allow", "GET, HEAD");
|
|
22
|
+
return new Response("Method Not Allowed", {
|
|
23
|
+
headers,
|
|
24
|
+
status: 405
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { isStaticOrSsgAppPageCandidate, resolveAppPageMethodResponse };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=app-page-method.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-page-method.js","names":[],"sources":["../../src/server/app-page-method.ts"],"sourcesContent":["import { isPossibleAppRouteActionRequest } from \"./app-route-handler-policy.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\n\ntype AppPageMethodPolicyOptions = {\n dynamicConfig?: string;\n hasGenerateStaticParams: boolean;\n isDynamicRoute: boolean;\n revalidateSeconds: number | null;\n};\n\ntype ResolveAppPageMethodResponseOptions = {\n middlewareHeaders?: Headers | null;\n request: Pick<Request, \"headers\" | \"method\">;\n} & AppPageMethodPolicyOptions;\n\nfunction isNonGetOrHead(method: string): boolean {\n const normalizedMethod = method.toUpperCase();\n return normalizedMethod !== \"GET\" && normalizedMethod !== \"HEAD\";\n}\n\nexport function isStaticOrSsgAppPageCandidate(options: AppPageMethodPolicyOptions): boolean {\n if (options.dynamicConfig === \"force-dynamic\" || options.revalidateSeconds === 0) {\n return false;\n }\n\n if (options.dynamicConfig === \"force-static\" || options.dynamicConfig === \"error\") {\n return true;\n }\n\n if (options.revalidateSeconds !== null && options.revalidateSeconds > 0) {\n return true;\n }\n\n if (options.hasGenerateStaticParams) {\n return true;\n }\n\n return !options.isDynamicRoute;\n}\n\nexport function resolveAppPageMethodResponse(\n options: ResolveAppPageMethodResponseOptions,\n): Response | null {\n if (!isNonGetOrHead(options.request.method)) {\n return null;\n }\n\n if (isPossibleAppRouteActionRequest(options.request)) {\n return null;\n }\n\n if (!isStaticOrSsgAppPageCandidate(options)) {\n return null;\n }\n\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);\n headers.set(\"Allow\", \"GET, HEAD\");\n\n return new Response(\"Method Not Allowed\", {\n headers,\n status: 405,\n });\n}\n"],"mappings":";;;AAeA,SAAS,eAAe,QAAyB;CAC/C,MAAM,mBAAmB,OAAO,aAAa;AAC7C,QAAO,qBAAqB,SAAS,qBAAqB;;AAG5D,SAAgB,8BAA8B,SAA8C;AAC1F,KAAI,QAAQ,kBAAkB,mBAAmB,QAAQ,sBAAsB,EAC7E,QAAO;AAGT,KAAI,QAAQ,kBAAkB,kBAAkB,QAAQ,kBAAkB,QACxE,QAAO;AAGT,KAAI,QAAQ,sBAAsB,QAAQ,QAAQ,oBAAoB,EACpE,QAAO;AAGT,KAAI,QAAQ,wBACV,QAAO;AAGT,QAAO,CAAC,QAAQ;;AAGlB,SAAgB,6BACd,SACiB;AACjB,KAAI,CAAC,eAAe,QAAQ,QAAQ,OAAO,CACzC,QAAO;AAGT,KAAI,gCAAgC,QAAQ,QAAQ,CAClD,QAAO;AAGT,KAAI,CAAC,8BAA8B,QAAQ,CACzC,QAAO;CAGT,MAAM,UAAU,IAAI,SAAS;AAC7B,gCAA+B,SAAS,QAAQ,qBAAqB,KAAK;AAC1E,SAAQ,IAAI,SAAS,YAAY;AAEjC,QAAO,IAAI,SAAS,sBAAsB;EACxC;EACA,QAAQ;EACT,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AppPageParams } from "./app-page-boundary.js";
|
|
2
|
+
|
|
3
|
+
//#region src/server/app-page-params.d.ts
|
|
4
|
+
declare function getAppPageSegmentParamName(segment: string): string | null;
|
|
5
|
+
declare function resolveAppPageSegmentParams(routeSegments: readonly string[] | null | undefined, treePosition: number, matchedParams: AppPageParams): AppPageParams;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getAppPageSegmentParamName, resolveAppPageSegmentParams };
|
|
8
|
+
//# sourceMappingURL=app-page-params.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/server/app-page-params.ts
|
|
2
|
+
function getAppPageSegmentParamName(segment) {
|
|
3
|
+
if (segment.startsWith("[[...") && segment.endsWith("]]") && segment.length > 7) return segment.slice(5, -2);
|
|
4
|
+
if (segment.startsWith("[...") && segment.endsWith("]") && segment.length > 5) return segment.slice(4, -1);
|
|
5
|
+
if (segment.startsWith("[") && segment.endsWith("]") && !segment.includes(".") && segment.length > 2) return segment.slice(1, -1);
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
function isEmptyOptionalCatchAll(segment, paramValue) {
|
|
9
|
+
return segment.startsWith("[[...") && Array.isArray(paramValue) && paramValue.length === 0;
|
|
10
|
+
}
|
|
11
|
+
function resolveAppPageSegmentParams(routeSegments, treePosition, matchedParams) {
|
|
12
|
+
const segmentParams = {};
|
|
13
|
+
const segments = routeSegments ?? [];
|
|
14
|
+
const end = Math.min(Math.max(treePosition, 0), segments.length);
|
|
15
|
+
for (let index = 0; index < end; index++) {
|
|
16
|
+
const segment = segments[index];
|
|
17
|
+
const paramName = getAppPageSegmentParamName(segment);
|
|
18
|
+
if (!paramName) continue;
|
|
19
|
+
const paramValue = matchedParams[paramName];
|
|
20
|
+
if (paramValue === void 0 || isEmptyOptionalCatchAll(segment, paramValue)) continue;
|
|
21
|
+
segmentParams[paramName] = paramValue;
|
|
22
|
+
}
|
|
23
|
+
return segmentParams;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { getAppPageSegmentParamName, resolveAppPageSegmentParams };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=app-page-params.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-page-params.js","names":[],"sources":["../../src/server/app-page-params.ts"],"sourcesContent":["import type { AppPageParams } from \"./app-page-boundary.js\";\n\nexport function getAppPageSegmentParamName(segment: string): string | null {\n if (segment.startsWith(\"[[...\") && segment.endsWith(\"]]\") && segment.length > 7) {\n return segment.slice(5, -2);\n }\n\n if (segment.startsWith(\"[...\") && segment.endsWith(\"]\") && segment.length > 5) {\n return segment.slice(4, -1);\n }\n\n if (\n segment.startsWith(\"[\") &&\n segment.endsWith(\"]\") &&\n !segment.includes(\".\") &&\n segment.length > 2\n ) {\n return segment.slice(1, -1);\n }\n\n return null;\n}\n\nfunction isEmptyOptionalCatchAll(segment: string, paramValue: string | string[]): boolean {\n return segment.startsWith(\"[[...\") && Array.isArray(paramValue) && paramValue.length === 0;\n}\n\nexport function resolveAppPageSegmentParams(\n routeSegments: readonly string[] | null | undefined,\n treePosition: number,\n matchedParams: AppPageParams,\n): AppPageParams {\n const segmentParams: AppPageParams = {};\n const segments = routeSegments ?? [];\n const end = Math.min(Math.max(treePosition, 0), segments.length);\n\n for (let index = 0; index < end; index++) {\n const segment = segments[index];\n const paramName = getAppPageSegmentParamName(segment);\n if (!paramName) {\n continue;\n }\n\n const paramValue = matchedParams[paramName];\n if (paramValue === undefined || isEmptyOptionalCatchAll(segment, paramValue)) {\n continue;\n }\n\n segmentParams[paramName] = paramValue;\n }\n\n return segmentParams;\n}\n"],"mappings":";AAEA,SAAgB,2BAA2B,SAAgC;AACzE,KAAI,QAAQ,WAAW,QAAQ,IAAI,QAAQ,SAAS,KAAK,IAAI,QAAQ,SAAS,EAC5E,QAAO,QAAQ,MAAM,GAAG,GAAG;AAG7B,KAAI,QAAQ,WAAW,OAAO,IAAI,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,EAC1E,QAAO,QAAQ,MAAM,GAAG,GAAG;AAG7B,KACE,QAAQ,WAAW,IAAI,IACvB,QAAQ,SAAS,IAAI,IACrB,CAAC,QAAQ,SAAS,IAAI,IACtB,QAAQ,SAAS,EAEjB,QAAO,QAAQ,MAAM,GAAG,GAAG;AAG7B,QAAO;;AAGT,SAAS,wBAAwB,SAAiB,YAAwC;AACxF,QAAO,QAAQ,WAAW,QAAQ,IAAI,MAAM,QAAQ,WAAW,IAAI,WAAW,WAAW;;AAG3F,SAAgB,4BACd,eACA,cACA,eACe;CACf,MAAM,gBAA+B,EAAE;CACvC,MAAM,WAAW,iBAAiB,EAAE;CACpC,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI,cAAc,EAAE,EAAE,SAAS,OAAO;AAEhE,MAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,SAAS;EACxC,MAAM,UAAU,SAAS;EACzB,MAAM,YAAY,2BAA2B,QAAQ;AACrD,MAAI,CAAC,UACH;EAGF,MAAM,aAAa,cAAc;AACjC,MAAI,eAAe,KAAA,KAAa,wBAAwB,SAAS,WAAW,CAC1E;AAGF,gBAAc,aAAa;;AAG7B,QAAO"}
|
|
@@ -8,14 +8,16 @@ import { ReactNode } from "react";
|
|
|
8
8
|
//#region src/server/app-page-render.d.ts
|
|
9
9
|
type AppPageBoundaryOnError = (error: unknown, requestInfo: unknown, errorContext: unknown) => unknown;
|
|
10
10
|
type AppPageDebugLogger = (event: string, detail: string) => void;
|
|
11
|
-
type AppPageCacheSetter = (key: string, data: CachedAppPageValue, revalidateSeconds: number, tags: string[]) => Promise<void>;
|
|
11
|
+
type AppPageCacheSetter = (key: string, data: CachedAppPageValue, revalidateSeconds: number, tags: string[], expireSeconds?: number) => Promise<void>;
|
|
12
12
|
type AppPageRequestCacheLife = {
|
|
13
13
|
revalidate?: number;
|
|
14
|
+
expire?: number;
|
|
14
15
|
};
|
|
15
16
|
type RenderAppPageLifecycleOptions = {
|
|
16
17
|
cleanPathname: string;
|
|
17
18
|
clearRequestContext: () => void;
|
|
18
|
-
consumeDynamicUsage: () => boolean;
|
|
19
|
+
consumeDynamicUsage: () => boolean; /** Read and clear any invalid dynamic usage error recorded during render (dev-only). */
|
|
20
|
+
consumeInvalidDynamicUsageError?: () => unknown;
|
|
19
21
|
createRscOnErrorHandler: (pathname: string, routePath: string) => AppPageBoundaryOnError;
|
|
20
22
|
getFontLinks: () => string[];
|
|
21
23
|
getFontPreloads: () => AppPageFontPreload[];
|
|
@@ -23,12 +25,14 @@ type RenderAppPageLifecycleOptions = {
|
|
|
23
25
|
getNavigationContext: () => unknown;
|
|
24
26
|
getPageTags: () => string[];
|
|
25
27
|
getRequestCacheLife: () => AppPageRequestCacheLife | null;
|
|
28
|
+
peekRequestCacheLife?: () => AppPageRequestCacheLife | null;
|
|
26
29
|
getDraftModeCookieHeader: () => string | null | undefined;
|
|
27
30
|
handlerStart: number;
|
|
28
31
|
hasLoadingBoundary: boolean;
|
|
29
32
|
isDynamicError: boolean;
|
|
30
33
|
isForceDynamic: boolean;
|
|
31
34
|
isForceStatic: boolean;
|
|
35
|
+
isPrerender?: boolean;
|
|
32
36
|
isProduction: boolean;
|
|
33
37
|
isRscRequest: boolean;
|
|
34
38
|
isrDebug?: AppPageDebugLogger;
|
|
@@ -41,6 +45,7 @@ type RenderAppPageLifecycleOptions = {
|
|
|
41
45
|
params: Record<string, unknown>;
|
|
42
46
|
probeLayoutAt: (layoutIndex: number) => unknown;
|
|
43
47
|
probePage: () => unknown;
|
|
48
|
+
expireSeconds?: number;
|
|
44
49
|
revalidateSeconds: number | null;
|
|
45
50
|
renderErrorBoundaryResponse: (error: unknown) => Promise<Response | null>;
|
|
46
51
|
renderLayoutSpecialError: (specialError: AppPageSpecialError, layoutIndex: number) => Promise<Response>;
|