@nifrajs/web 4.0.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/build-vite.d.ts +19 -0
- package/dist/build-vite.d.ts.map +1 -1
- package/dist/build-vite.js +31 -10
- package/dist/build-vite.js.map +1 -1
- package/dist/build.d.ts +8 -10
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +90 -31
- package/dist/build.js.map +1 -1
- package/dist/cdn.d.ts +8 -0
- package/dist/cdn.d.ts.map +1 -1
- package/dist/cdn.js +14 -15
- package/dist/cdn.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +25 -7
- package/dist/client.js.map +1 -1
- package/dist/deferred.d.ts +2 -2
- package/dist/deferred.d.ts.map +1 -1
- package/dist/deferred.js +28 -7
- package/dist/deferred.js.map +1 -1
- package/dist/dev-feed.d.ts.map +1 -1
- package/dist/dev-feed.js +24 -5
- package/dist/dev-feed.js.map +1 -1
- package/dist/dev-session.d.ts.map +1 -1
- package/dist/dev-session.js +4 -14
- package/dist/dev-session.js.map +1 -1
- package/dist/dev.d.ts +7 -17
- package/dist/dev.d.ts.map +1 -1
- package/dist/dev.js +13 -1
- package/dist/dev.js.map +1 -1
- package/dist/draft.d.ts +8 -5
- package/dist/draft.d.ts.map +1 -1
- package/dist/draft.js +30 -13
- package/dist/draft.js.map +1 -1
- package/dist/fonts-google.d.ts.map +1 -1
- package/dist/fonts-google.js +7 -0
- package/dist/fonts-google.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/codegen.d.ts +1 -0
- package/dist/internal/codegen.d.ts.map +1 -1
- package/dist/internal/codegen.js +56 -29
- package/dist/internal/codegen.js.map +1 -1
- package/dist/internal/disposable-dir.d.ts +8 -0
- package/dist/internal/disposable-dir.d.ts.map +1 -0
- package/dist/internal/disposable-dir.js +25 -0
- package/dist/internal/disposable-dir.js.map +1 -0
- package/dist/internal/entry-chunks.d.ts +9 -0
- package/dist/internal/entry-chunks.d.ts.map +1 -0
- package/dist/internal/entry-chunks.js +15 -0
- package/dist/internal/entry-chunks.js.map +1 -0
- package/dist/internal/evidence-traversal.d.ts +12 -0
- package/dist/internal/evidence-traversal.d.ts.map +1 -0
- package/dist/internal/evidence-traversal.js +48 -0
- package/dist/internal/evidence-traversal.js.map +1 -0
- package/dist/internal/head-merge.d.ts +6 -0
- package/dist/internal/head-merge.d.ts.map +1 -1
- package/dist/internal/head-merge.js +9 -0
- package/dist/internal/head-merge.js.map +1 -1
- package/dist/internal/js-string.d.ts +2 -0
- package/dist/internal/js-string.d.ts.map +1 -1
- package/dist/internal/js-string.js +5 -1
- package/dist/internal/js-string.js.map +1 -1
- package/dist/internal/mount-shadow.js +1 -1
- package/dist/internal/mount-shadow.js.map +1 -1
- package/dist/internal/output-guard.d.ts +7 -0
- package/dist/internal/output-guard.d.ts.map +1 -1
- package/dist/internal/output-guard.js +80 -8
- package/dist/internal/output-guard.js.map +1 -1
- package/dist/internal/page-execution.d.ts +6 -0
- package/dist/internal/page-execution.d.ts.map +1 -1
- package/dist/internal/page-execution.js +377 -108
- package/dist/internal/page-execution.js.map +1 -1
- package/dist/internal/progressive-cookies.d.ts +14 -0
- package/dist/internal/progressive-cookies.d.ts.map +1 -0
- package/dist/internal/progressive-cookies.js +43 -0
- package/dist/internal/progressive-cookies.js.map +1 -0
- package/dist/internal/public-env.d.ts +2 -0
- package/dist/internal/public-env.d.ts.map +1 -0
- package/dist/internal/public-env.js +13 -0
- package/dist/internal/public-env.js.map +1 -0
- package/dist/internal/render-document.d.ts +1 -0
- package/dist/internal/render-document.d.ts.map +1 -1
- package/dist/internal/render-document.js +28 -5
- package/dist/internal/render-document.js.map +1 -1
- package/dist/internal/response-controls.d.ts +2 -0
- package/dist/internal/response-controls.d.ts.map +1 -1
- package/dist/internal/response-controls.js +26 -16
- package/dist/internal/response-controls.js.map +1 -1
- package/dist/internal/revive-dates.d.ts +16 -0
- package/dist/internal/revive-dates.d.ts.map +1 -0
- package/dist/internal/revive-dates.js +32 -0
- package/dist/internal/revive-dates.js.map +1 -0
- package/dist/internal/route-path.d.ts +8 -0
- package/dist/internal/route-path.d.ts.map +1 -0
- package/dist/internal/route-path.js +8 -0
- package/dist/internal/route-path.js.map +1 -0
- package/dist/internal/secret-scan.d.ts.map +1 -1
- package/dist/internal/secret-scan.js +88 -20
- package/dist/internal/secret-scan.js.map +1 -1
- package/dist/internal/server-boundary.d.ts.map +1 -1
- package/dist/internal/server-boundary.js +33 -5
- package/dist/internal/server-boundary.js.map +1 -1
- package/dist/internal/web-app.d.ts +21 -16
- package/dist/internal/web-app.d.ts.map +1 -1
- package/dist/internal/web-app.js +73 -21
- package/dist/internal/web-app.js.map +1 -1
- package/dist/internal/wire-date.d.ts +3 -0
- package/dist/internal/wire-date.d.ts.map +1 -0
- package/dist/internal/wire-date.js +14 -0
- package/dist/internal/wire-date.js.map +1 -0
- package/dist/internal/zone-graph.d.ts +4 -0
- package/dist/internal/zone-graph.d.ts.map +1 -1
- package/dist/internal/zone-graph.js +54 -14
- package/dist/internal/zone-graph.js.map +1 -1
- package/dist/isr.d.ts +58 -2
- package/dist/isr.d.ts.map +1 -1
- package/dist/isr.js +296 -39
- package/dist/isr.js.map +1 -1
- package/dist/llms-txt.d.ts +2 -0
- package/dist/llms-txt.d.ts.map +1 -1
- package/dist/llms-txt.js +29 -3
- package/dist/llms-txt.js.map +1 -1
- package/dist/manifest.d.ts +28 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +3 -0
- package/dist/manifest.js.map +1 -1
- package/dist/open-resolved.d.ts +18 -0
- package/dist/open-resolved.d.ts.map +1 -0
- package/dist/open-resolved.js +62 -0
- package/dist/open-resolved.js.map +1 -0
- package/dist/plugins/kit.d.ts +1 -0
- package/dist/plugins/kit.d.ts.map +1 -1
- package/dist/plugins/kit.js +26 -11
- package/dist/plugins/kit.js.map +1 -1
- package/dist/plugins/vite-leak-guard.d.ts +3 -1
- package/dist/plugins/vite-leak-guard.d.ts.map +1 -1
- package/dist/plugins/vite-leak-guard.js +4 -0
- package/dist/plugins/vite-leak-guard.js.map +1 -1
- package/dist/public-dir.d.ts +8 -1
- package/dist/public-dir.d.ts.map +1 -1
- package/dist/public-dir.js +17 -6
- package/dist/public-dir.js.map +1 -1
- package/dist/query.d.ts +13 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +89 -26
- package/dist/query.js.map +1 -1
- package/dist/render-seam.d.ts +2 -0
- package/dist/render-seam.d.ts.map +1 -1
- package/dist/render-seam.js +1 -0
- package/dist/render-seam.js.map +1 -1
- package/dist/route-types.d.ts.map +1 -1
- package/dist/route-types.js +20 -9
- package/dist/route-types.js.map +1 -1
- package/dist/router.d.ts +9 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +39 -46
- package/dist/router.js.map +1 -1
- package/dist/server-components/build-info.d.ts +3 -0
- package/dist/server-components/build-info.d.ts.map +1 -0
- package/dist/server-components/build-info.js +7 -0
- package/dist/server-components/build-info.js.map +1 -0
- package/dist/server-components/build-target.d.ts +12 -0
- package/dist/server-components/build-target.d.ts.map +1 -0
- package/dist/server-components/build-target.js +153 -0
- package/dist/server-components/build-target.js.map +1 -0
- package/dist/server-components/build.d.ts +24 -0
- package/dist/server-components/build.d.ts.map +1 -0
- package/dist/server-components/build.js +366 -0
- package/dist/server-components/build.js.map +1 -0
- package/dist/server-components/bundle-proof.d.ts +3 -0
- package/dist/server-components/bundle-proof.d.ts.map +1 -0
- package/dist/server-components/bundle-proof.js +23 -0
- package/dist/server-components/bundle-proof.js.map +1 -0
- package/dist/server-components/client.d.ts +46 -0
- package/dist/server-components/client.d.ts.map +1 -0
- package/dist/server-components/client.js +594 -0
- package/dist/server-components/client.js.map +1 -0
- package/dist/server-components/definition.d.ts +11 -0
- package/dist/server-components/definition.d.ts.map +1 -0
- package/dist/server-components/definition.js +94 -0
- package/dist/server-components/definition.js.map +1 -0
- package/dist/server-components/dev-http.d.ts +5 -0
- package/dist/server-components/dev-http.d.ts.map +1 -0
- package/dist/server-components/dev-http.js +71 -0
- package/dist/server-components/dev-http.js.map +1 -0
- package/dist/server-components/error.d.ts +9 -0
- package/dist/server-components/error.d.ts.map +1 -0
- package/dist/server-components/error.js +24 -0
- package/dist/server-components/error.js.map +1 -0
- package/dist/server-components/frames.d.ts +7 -0
- package/dist/server-components/frames.d.ts.map +1 -0
- package/dist/server-components/frames.js +169 -0
- package/dist/server-components/frames.js.map +1 -0
- package/dist/server-components/html-policy.d.ts +6 -0
- package/dist/server-components/html-policy.d.ts.map +1 -0
- package/dist/server-components/html-policy.js +75 -0
- package/dist/server-components/html-policy.js.map +1 -0
- package/dist/server-components/html.d.ts +4 -0
- package/dist/server-components/html.d.ts.map +1 -0
- package/dist/server-components/html.js +67 -0
- package/dist/server-components/html.js.map +1 -0
- package/dist/server-components/islands.d.ts +44 -0
- package/dist/server-components/islands.d.ts.map +1 -0
- package/dist/server-components/islands.js +42 -0
- package/dist/server-components/islands.js.map +1 -0
- package/dist/server-components/native.d.ts +4 -0
- package/dist/server-components/native.d.ts.map +1 -0
- package/dist/server-components/native.js +81 -0
- package/dist/server-components/native.js.map +1 -0
- package/dist/server-components/portal.d.ts +6 -0
- package/dist/server-components/portal.d.ts.map +1 -0
- package/dist/server-components/portal.js +35 -0
- package/dist/server-components/portal.js.map +1 -0
- package/dist/server-components/props.d.ts +3 -0
- package/dist/server-components/props.d.ts.map +1 -0
- package/dist/server-components/props.js +14 -0
- package/dist/server-components/props.js.map +1 -0
- package/dist/server-components/protocol.d.ts +44 -0
- package/dist/server-components/protocol.d.ts.map +1 -0
- package/dist/server-components/protocol.js +139 -0
- package/dist/server-components/protocol.js.map +1 -0
- package/dist/server-components/range.d.ts +24 -0
- package/dist/server-components/range.d.ts.map +1 -0
- package/dist/server-components/range.js +263 -0
- package/dist/server-components/range.js.map +1 -0
- package/dist/server-components/registry.d.ts +6 -0
- package/dist/server-components/registry.d.ts.map +1 -0
- package/dist/server-components/registry.js +30 -0
- package/dist/server-components/registry.js.map +1 -0
- package/dist/server-components/response.d.ts +4 -0
- package/dist/server-components/response.d.ts.map +1 -0
- package/dist/server-components/response.js +32 -0
- package/dist/server-components/response.js.map +1 -0
- package/dist/server-components/router-integration.d.ts +9 -0
- package/dist/server-components/router-integration.d.ts.map +1 -0
- package/dist/server-components/router-integration.js +29 -0
- package/dist/server-components/router-integration.js.map +1 -0
- package/dist/server-components/runtime.d.ts +14 -0
- package/dist/server-components/runtime.d.ts.map +1 -0
- package/dist/server-components/runtime.js +276 -0
- package/dist/server-components/runtime.js.map +1 -0
- package/dist/server-components/scheduler.d.ts +14 -0
- package/dist/server-components/scheduler.d.ts.map +1 -0
- package/dist/server-components/scheduler.js +74 -0
- package/dist/server-components/scheduler.js.map +1 -0
- package/dist/server-components/schema.d.ts +4 -0
- package/dist/server-components/schema.d.ts.map +1 -0
- package/dist/server-components/schema.js +77 -0
- package/dist/server-components/schema.js.map +1 -0
- package/dist/server-components/server-entry.d.ts +12 -0
- package/dist/server-components/server-entry.d.ts.map +1 -0
- package/dist/server-components/server-entry.js +90 -0
- package/dist/server-components/server-entry.js.map +1 -0
- package/dist/server-components/source.d.ts +15 -0
- package/dist/server-components/source.d.ts.map +1 -0
- package/dist/server-components/source.js +269 -0
- package/dist/server-components/source.js.map +1 -0
- package/dist/server-components/state.d.ts +4 -0
- package/dist/server-components/state.d.ts.map +1 -0
- package/dist/server-components/state.js +123 -0
- package/dist/server-components/state.js.map +1 -0
- package/dist/server-components/stream.d.ts +6 -0
- package/dist/server-components/stream.d.ts.map +1 -0
- package/dist/server-components/stream.js +70 -0
- package/dist/server-components/stream.js.map +1 -0
- package/dist/server-components/trusted-html.d.ts +3 -0
- package/dist/server-components/trusted-html.d.ts.map +1 -0
- package/dist/server-components/trusted-html.js +14 -0
- package/dist/server-components/trusted-html.js.map +1 -0
- package/dist/server-components/types.d.ts +107 -0
- package/dist/server-components/types.d.ts.map +1 -0
- package/dist/server-components/types.js +2 -0
- package/dist/server-components/types.js.map +1 -0
- package/dist/server-components/typescript.d.ts +11 -0
- package/dist/server-components/typescript.d.ts.map +1 -0
- package/dist/server-components/typescript.js +28 -0
- package/dist/server-components/typescript.js.map +1 -0
- package/dist/server-components/value.d.ts +5 -0
- package/dist/server-components/value.d.ts.map +1 -0
- package/dist/server-components/value.js +77 -0
- package/dist/server-components/value.js.map +1 -0
- package/dist/server-components/vite.d.ts +12 -0
- package/dist/server-components/vite.d.ts.map +1 -0
- package/dist/server-components/vite.js +197 -0
- package/dist/server-components/vite.js.map +1 -0
- package/dist/server-components.d.ts +5 -0
- package/dist/server-components.d.ts.map +1 -0
- package/dist/server-components.js +4 -0
- package/dist/server-components.js.map +1 -0
- package/dist/service-worker.d.ts +8 -1
- package/dist/service-worker.d.ts.map +1 -1
- package/dist/service-worker.js +20 -6
- package/dist/service-worker.js.map +1 -1
- package/dist/vite.d.ts +12 -0
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +7 -1
- package/dist/vite.js.map +1 -1
- package/dist/zones.d.ts +40 -0
- package/dist/zones.d.ts.map +1 -1
- package/dist/zones.js +170 -6
- package/dist/zones.js.map +1 -1
- package/package.json +97 -4
- package/src/build-vite.ts +31 -9
- package/src/build.ts +109 -31
- package/src/cdn.ts +18 -12
- package/src/client.ts +25 -6
- package/src/deferred.ts +27 -9
- package/src/dev-feed.ts +24 -5
- package/src/dev-session.ts +4 -13
- package/src/dev.ts +29 -1
- package/src/draft.ts +35 -14
- package/src/fonts-google.ts +10 -0
- package/src/index.ts +3 -2
- package/src/internal/codegen.ts +60 -29
- package/src/internal/disposable-dir.ts +24 -0
- package/src/internal/entry-chunks.ts +18 -0
- package/src/internal/evidence-traversal.ts +57 -0
- package/src/internal/head-merge.ts +16 -0
- package/src/internal/js-string.ts +6 -1
- package/src/internal/mount-shadow.ts +1 -1
- package/src/internal/output-guard.ts +88 -7
- package/src/internal/page-execution.ts +506 -108
- package/src/internal/progressive-cookies.ts +60 -0
- package/src/internal/public-env.ts +14 -0
- package/src/internal/render-document.ts +26 -11
- package/src/internal/response-controls.ts +31 -14
- package/src/internal/revive-dates.ts +35 -0
- package/src/internal/route-path.ts +8 -0
- package/src/internal/secret-scan.ts +90 -18
- package/src/internal/server-boundary.ts +29 -5
- package/src/internal/web-app.ts +116 -37
- package/src/internal/wire-date.ts +16 -0
- package/src/internal/zone-graph.ts +59 -19
- package/src/isr.ts +351 -43
- package/src/llms-txt.ts +32 -3
- package/src/manifest.ts +28 -4
- package/src/open-resolved.ts +64 -0
- package/src/plugins/kit.ts +31 -11
- package/src/plugins/vite-leak-guard.ts +5 -1
- package/src/public-dir.ts +27 -8
- package/src/query.ts +107 -26
- package/src/render-seam.ts +2 -0
- package/src/route-types.ts +34 -7
- package/src/router.ts +58 -55
- package/src/server-components/build-info.ts +11 -0
- package/src/server-components/build-target.ts +194 -0
- package/src/server-components/build.ts +419 -0
- package/src/server-components/bundle-proof.ts +33 -0
- package/src/server-components/client.ts +663 -0
- package/src/server-components/definition.ts +125 -0
- package/src/server-components/dev-http.ts +75 -0
- package/src/server-components/error.ts +24 -0
- package/src/server-components/frames.ts +181 -0
- package/src/server-components/html-policy.ts +94 -0
- package/src/server-components/html.ts +81 -0
- package/src/server-components/islands.ts +111 -0
- package/src/server-components/native.ts +101 -0
- package/src/server-components/portal.ts +42 -0
- package/src/server-components/props.ts +19 -0
- package/src/server-components/protocol.ts +167 -0
- package/src/server-components/range.ts +313 -0
- package/src/server-components/registry.ts +34 -0
- package/src/server-components/response.ts +44 -0
- package/src/server-components/router-integration.ts +40 -0
- package/src/server-components/runtime.ts +376 -0
- package/src/server-components/scheduler.ts +84 -0
- package/src/server-components/schema.ts +69 -0
- package/src/server-components/server-entry.ts +98 -0
- package/src/server-components/source.ts +324 -0
- package/src/server-components/state.ts +143 -0
- package/src/server-components/stream.ts +71 -0
- package/src/server-components/trusted-html.ts +21 -0
- package/src/server-components/types.ts +138 -0
- package/src/server-components/typescript.ts +39 -0
- package/src/server-components/value.ts +82 -0
- package/src/server-components/vite.ts +242 -0
- package/src/server-components.ts +32 -0
- package/src/service-worker.ts +24 -7
- package/src/vite.ts +8 -1
- package/src/zones.ts +208 -7
|
@@ -7,7 +7,7 @@ import { isDraftEnabled } from "../draft.js";
|
|
|
7
7
|
import { routeTags } from "../isr.js";
|
|
8
8
|
import { createMatcher, DATA_HEADER, NAV_FROM_HEADER, REDIRECT_HEADER, RETAIN_HEADER, REVALIDATE_HEADER, STATUS_HEADER, } from "../router.js";
|
|
9
9
|
import { searchOf, searchOfChain } from "../search.js";
|
|
10
|
-
import { mergeHeads,
|
|
10
|
+
import { mergeHeads, resolveChainMeta } from "./head-merge.js";
|
|
11
11
|
import { EMPTY_RETAIN, isControlFlow, isResponseResult, isStatusSignal, layoutErrorId, renderPageResult, STATUS_SIGNAL, STATUS_TEXT, scopeParams, tagLayoutError, withDuplicateInstanceHint, } from "./render-document.js";
|
|
12
12
|
import { urlPartsFor } from "./request-url.js";
|
|
13
13
|
import { ACTION_SCOPE, DATA_RESPONSE_HEADERS, MIDDLEWARE_SCOPE, PAGE_SCOPE, PageResponseControls, PRIVATE_NO_STORE, PRIVATE_PAGE_HEADERS, privateOutcome, varyOnDataHeader, } from "./response-controls.js";
|
|
@@ -107,6 +107,8 @@ function appTarget(location, requestUrl) {
|
|
|
107
107
|
*/
|
|
108
108
|
export function createPageRequestExecutor(options) {
|
|
109
109
|
const { adapter, manifest, clientEntry, api } = options;
|
|
110
|
+
// The action result is request-local; a browser cannot manufacture this handoff.
|
|
111
|
+
const progressiveActionData = new WeakMap();
|
|
110
112
|
// Bound once per render, so every loader, action and boundary in that render shares one view of the
|
|
111
113
|
// in-process client carrying the visitor's platform. An `api` without the seam passes through as-is.
|
|
112
114
|
const bindApi = platformBinderOf(api);
|
|
@@ -165,9 +167,7 @@ export function createPageRequestExecutor(options) {
|
|
|
165
167
|
return chunks ? { preload: chunks } : {};
|
|
166
168
|
};
|
|
167
169
|
const resolveNonce = (request, env) => options.nonce === undefined ? undefined : options.nonce({ request, env });
|
|
168
|
-
const
|
|
169
|
-
const perRoute = options.routeStyles?.[id];
|
|
170
|
-
const styles = perRoute ?? options.styles;
|
|
170
|
+
const stylesFrom = (styles) => {
|
|
171
171
|
if (styles === undefined || styles.length === 0)
|
|
172
172
|
return {};
|
|
173
173
|
return {
|
|
@@ -175,6 +175,7 @@ export function createPageRequestExecutor(options) {
|
|
|
175
175
|
...(cssLoading === "deferred" ? { cssLoading } : {}),
|
|
176
176
|
};
|
|
177
177
|
};
|
|
178
|
+
const stylesOf = (id) => stylesFrom(options.routeStyles?.[id] ?? options.styles);
|
|
178
179
|
// Load a route's layout modules once for the current execution. The render path needs each whole
|
|
179
180
|
// module for its component + meta, while the data path also needs loader/gate/boundary declarations.
|
|
180
181
|
const loadLayoutModules = async (route) => {
|
|
@@ -194,11 +195,32 @@ export function createPageRequestExecutor(options) {
|
|
|
194
195
|
retained: [],
|
|
195
196
|
pending: undefined,
|
|
196
197
|
};
|
|
197
|
-
/**
|
|
198
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Await one gate. A returned redirect, status or Response refuses the request exactly as a thrown
|
|
200
|
+
* one does: stored as layout data it would let the page loader and the action run.
|
|
201
|
+
*/
|
|
202
|
+
const runGate = async (route, index, loader, ctx) => {
|
|
203
|
+
let value;
|
|
204
|
+
try {
|
|
205
|
+
value = await loader(ctx);
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
209
|
+
throw tagLayoutError(err, route.layoutIds[index]);
|
|
210
|
+
}
|
|
211
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
212
|
+
if (isControlFlow(value))
|
|
213
|
+
throw tagLayoutError(value, route.layoutIds[index]);
|
|
214
|
+
return value;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Run layout loaders, awaiting gates before starting the page loader and retaining only safe data.
|
|
218
|
+
* `gated` carries gates that already ran for this request, so none runs twice.
|
|
219
|
+
*/
|
|
220
|
+
const runLayoutChain = async (route, ctx, controls, retain, gated) => {
|
|
199
221
|
if (route.layoutIds.length === 0)
|
|
200
222
|
return emptyLayoutRun;
|
|
201
|
-
const modules = await loadLayoutModules(route);
|
|
223
|
+
const modules = gated?.modules ?? (await loadLayoutModules(route));
|
|
202
224
|
if (!modules.some((m) => m.loader !== undefined)) {
|
|
203
225
|
return { modules, layoutData: undefined, retained: [], pending: undefined };
|
|
204
226
|
}
|
|
@@ -216,6 +238,7 @@ export function createPageRequestExecutor(options) {
|
|
|
216
238
|
keep = keepsLayoutData(route, i, layout, ctx.params, retain);
|
|
217
239
|
}
|
|
218
240
|
catch (err) {
|
|
241
|
+
// biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: The loaded layout array is derived from these same manifest IDs in the same order.
|
|
219
242
|
throw tagLayoutError(err, route.layoutIds[i]);
|
|
220
243
|
}
|
|
221
244
|
if (keep) {
|
|
@@ -229,12 +252,7 @@ export function createPageRequestExecutor(options) {
|
|
|
229
252
|
set: controls.scope(i),
|
|
230
253
|
};
|
|
231
254
|
if (modules[i]?.gate === true) {
|
|
232
|
-
|
|
233
|
-
results[i] = await loader(scoped);
|
|
234
|
-
}
|
|
235
|
-
catch (err) {
|
|
236
|
-
throw tagLayoutError(err, route.layoutIds[i]);
|
|
237
|
-
}
|
|
255
|
+
results[i] = gated === undefined ? await runGate(route, i, loader, scoped) : gated.gates[i];
|
|
238
256
|
continue;
|
|
239
257
|
}
|
|
240
258
|
const layoutId = route.layoutIds[i];
|
|
@@ -271,22 +289,18 @@ export function createPageRequestExecutor(options) {
|
|
|
271
289
|
/** Run only authorization gates before an action; ordinary layout data runs after a native action. */
|
|
272
290
|
const runLayoutGates = async (route, ctx, controls) => {
|
|
273
291
|
const modules = await loadLayoutModules(route);
|
|
292
|
+
const gates = [];
|
|
274
293
|
for (let i = 0; i < modules.length; i++) {
|
|
275
294
|
const mod = modules[i];
|
|
276
295
|
if (mod?.gate !== true || mod.loader === undefined)
|
|
277
296
|
continue;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
catch (err) {
|
|
286
|
-
throw tagLayoutError(err, route.layoutIds[i]);
|
|
287
|
-
}
|
|
297
|
+
gates[i] = await runGate(route, i, mod.loader, {
|
|
298
|
+
...ctx,
|
|
299
|
+
params: scopeParams(ctx.params, route.layoutParams?.[i]),
|
|
300
|
+
set: controls.scope(i),
|
|
301
|
+
});
|
|
288
302
|
}
|
|
289
|
-
return modules;
|
|
303
|
+
return { modules, gates };
|
|
290
304
|
};
|
|
291
305
|
/** Outermost first; a failure carries its directory so the nearest `_error` above it renders. */
|
|
292
306
|
const runMiddleware = async (route, ctx, controls) => {
|
|
@@ -400,13 +414,10 @@ export function createPageRequestExecutor(options) {
|
|
|
400
414
|
}
|
|
401
415
|
return mod.HydrateFallback ?? EMPTY_LEAF;
|
|
402
416
|
};
|
|
403
|
-
const resolveChainAndHead = (layoutModules, page, metaArgs, leaf = page.default) => {
|
|
417
|
+
const resolveChainAndHead = (layoutModules, layoutData, page, metaArgs, leaf = page.default) => {
|
|
404
418
|
const chain = [...layoutModules.map((m) => m.default), leaf];
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
resolveMeta(page.meta, metaArgs),
|
|
408
|
-
];
|
|
409
|
-
return { chain, head: mergeHeads(heads) };
|
|
419
|
+
const metas = [...layoutModules.map((m) => m.meta), page.meta];
|
|
420
|
+
return { chain, head: mergeHeads(resolveChainMeta(metas, layoutData, metaArgs)) };
|
|
410
421
|
};
|
|
411
422
|
/** What `useMatches` reports for a chain: the layouts' ids and `handle`s, then the page's. */
|
|
412
423
|
const matchChainOf = (layoutIds, layoutModules, pageId, page) => ({
|
|
@@ -444,34 +455,128 @@ export function createPageRequestExecutor(options) {
|
|
|
444
455
|
return "/";
|
|
445
456
|
}
|
|
446
457
|
};
|
|
447
|
-
|
|
458
|
+
/** What a status or error page's `meta` receives: no route params, and its own data. */
|
|
459
|
+
const statusMetaArgs = (req, data, nonce) => nonce === undefined
|
|
460
|
+
? { data, pageData: data, params: {}, origin: originOf(req) }
|
|
461
|
+
: { data, pageData: data, params: {}, origin: originOf(req), nonce };
|
|
462
|
+
const renderError = async (req, route, errorId, err, personalized, nonce, layouts) => {
|
|
448
463
|
const errDir = dirOfId(errorId, "_error");
|
|
449
464
|
const keptLayoutIds = route.layoutIds.filter((id) => {
|
|
450
465
|
const ld = dirOfId(id, "_layout");
|
|
451
466
|
return ld === "" || ld === errDir || errDir.startsWith(`${ld}/`);
|
|
452
467
|
});
|
|
453
|
-
const
|
|
454
|
-
const { default: errComp } = await (manifest.errors?.[errorId]).load();
|
|
468
|
+
const errorModule = await (manifest.errors?.[errorId]).load();
|
|
455
469
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
456
|
-
// An error's text can carry a connection string or a query, so a
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
470
|
+
// An error's text can carry a connection string or a query, so only a run that says it is
|
|
471
|
+
// development or test shows it; an unset NODE_ENV (an unbuilt `bun app.ts`) counts as production.
|
|
472
|
+
const nodeEnv = typeof process === "undefined" ? undefined : process.env.NODE_ENV;
|
|
473
|
+
const data = nodeEnv === "development" || nodeEnv === "test"
|
|
474
|
+
? { name: e.name, message: e.message }
|
|
475
|
+
: { name: "Error", message: "Internal Server Error" };
|
|
476
|
+
const inLayouts = errorModule.inLayouts !== false;
|
|
477
|
+
const chain = inLayouts && layouts !== undefined && keptLayoutIds.length > 0
|
|
478
|
+
? await layouts(errorModule, keptLayoutIds.length)
|
|
479
|
+
: undefined;
|
|
480
|
+
const render = (components, wrapped) => {
|
|
481
|
+
const layoutData = wrapped?.chain.layoutData;
|
|
482
|
+
return renderPageResult({
|
|
483
|
+
adapter,
|
|
484
|
+
chain: components,
|
|
485
|
+
data,
|
|
486
|
+
...(wrapped === undefined ? {} : { head: wrapped.head }),
|
|
487
|
+
clientEntry,
|
|
488
|
+
routeId: errorId,
|
|
489
|
+
status: 500,
|
|
490
|
+
hydrate: false,
|
|
491
|
+
...(layoutData === undefined ? {} : { layoutData }),
|
|
492
|
+
...(personalized || layoutData !== undefined ? { headers: PRIVATE_PAGE_HEADERS } : {}),
|
|
493
|
+
...(nonce === undefined ? {} : { nonce }),
|
|
494
|
+
...cspOption,
|
|
495
|
+
...titleOption,
|
|
496
|
+
});
|
|
497
|
+
};
|
|
498
|
+
if (chain !== undefined) {
|
|
499
|
+
const resolved = resolveChainAndHead(chain.modules, chain.layoutData, errorModule, statusMetaArgs(req, data, nonce));
|
|
500
|
+
try {
|
|
501
|
+
return await render(resolved.chain, { head: resolved.head, chain });
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
// A layout that fails to render leaves the error page alone, never a second error.
|
|
505
|
+
return render([errorModule.default]);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
// Layouts whose data did not settle still frame the error page, without their data.
|
|
509
|
+
const layoutComponents = await Promise.all(keptLayoutIds.map((id) => manifest.layouts[id].load().then((m) => m.default)));
|
|
510
|
+
return render([...layoutComponents, errorModule.default]);
|
|
511
|
+
};
|
|
512
|
+
/** The leading `count` layouts of `modules`, unless one of them answered with a status or redirect. */
|
|
513
|
+
const settledLayouts = (modules, layoutData, count) => {
|
|
514
|
+
if (modules.length < count)
|
|
515
|
+
return undefined;
|
|
516
|
+
const data = layoutData?.slice(0, count);
|
|
517
|
+
if (data?.some((value) => isControlFlow(value) || isStatusSignal(value)))
|
|
518
|
+
return undefined;
|
|
519
|
+
return { modules: modules.slice(0, count), layoutData: data };
|
|
520
|
+
};
|
|
521
|
+
/** A run's leading layouts once all of its loaders settle - never when a layout or middleware refused. */
|
|
522
|
+
const leadingLayouts = (run, err) => async (_page, count) => {
|
|
523
|
+
if (run === undefined || (err !== undefined && layoutErrorId(err) !== undefined)) {
|
|
524
|
+
return undefined;
|
|
525
|
+
}
|
|
526
|
+
try {
|
|
527
|
+
await run.pending;
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
return undefined;
|
|
531
|
+
}
|
|
532
|
+
return settledLayouts(run.modules, run.layoutData, count);
|
|
473
533
|
};
|
|
474
|
-
const
|
|
534
|
+
const rootLayoutIds = manifest.layouts._layout === undefined ? [] : ["_layout"];
|
|
535
|
+
const rootMiddlewareIds = manifest.middlewares?._middleware === undefined ? [] : ["_middleware"];
|
|
536
|
+
/**
|
|
537
|
+
* Run the root middleware and layouts for a request no route ran them for (an unmatched URL), as a
|
|
538
|
+
* nested `_404` runs its own. Any refusal or failure renders the page alone.
|
|
539
|
+
*/
|
|
540
|
+
const rootLayoutsFor = (c, controls) => async (page) => {
|
|
541
|
+
const entry = manifest.statusPages?.["404"] ?? manifest.notFound;
|
|
542
|
+
if (rootLayoutIds.length === 0 || entry === undefined)
|
|
543
|
+
return undefined;
|
|
544
|
+
const layoutsOnly = {
|
|
545
|
+
id: "_404",
|
|
546
|
+
pattern: "/*",
|
|
547
|
+
layoutIds: rootLayoutIds,
|
|
548
|
+
errorIds: [],
|
|
549
|
+
file: entry.file,
|
|
550
|
+
load: entry.load,
|
|
551
|
+
};
|
|
552
|
+
const route = rootMiddlewareIds.length === 0
|
|
553
|
+
? layoutsOnly
|
|
554
|
+
: { ...layoutsOnly, middlewareIds: rootMiddlewareIds };
|
|
555
|
+
try {
|
|
556
|
+
const draft = await draftFlag(c.req);
|
|
557
|
+
if (draft)
|
|
558
|
+
controls.personalize();
|
|
559
|
+
const ctx = {
|
|
560
|
+
params: {},
|
|
561
|
+
request: c.req,
|
|
562
|
+
req: c.req,
|
|
563
|
+
api: apiFor(c),
|
|
564
|
+
env: c.env,
|
|
565
|
+
draft,
|
|
566
|
+
search: loaderSearch(page.searchSchema, c.req),
|
|
567
|
+
set: controls.scope(PAGE_SCOPE),
|
|
568
|
+
};
|
|
569
|
+
if (route.middlewareIds !== undefined)
|
|
570
|
+
await runMiddleware(route, ctx, controls);
|
|
571
|
+
const run = await runLayoutChain(route, ctx, controls);
|
|
572
|
+
await run.pending;
|
|
573
|
+
return settledLayouts(run.modules, run.layoutData, rootLayoutIds.length);
|
|
574
|
+
}
|
|
575
|
+
catch {
|
|
576
|
+
return undefined;
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
const renderTerminalStatus = async (status, req, extraHeaders, nonce, layouts) => {
|
|
475
580
|
const page = manifest.statusPages?.[String(status)] ?? manifest.notFound;
|
|
476
581
|
if (page === undefined) {
|
|
477
582
|
const headers = new Headers(extraHeaders);
|
|
@@ -479,31 +584,55 @@ export function createPageRequestExecutor(options) {
|
|
|
479
584
|
return new Response(STATUS_TEXT[status] ?? "Error", { status, headers });
|
|
480
585
|
}
|
|
481
586
|
const routeId = manifest.statusPages?.[String(status)] !== undefined ? `_${status}` : "_404";
|
|
482
|
-
const loaded =
|
|
483
|
-
|
|
587
|
+
const loaded = await page.load();
|
|
588
|
+
const wraps = loaded.inLayouts !== false && rootLayoutIds.length > 0;
|
|
589
|
+
const chain = wraps && layouts !== undefined ? await layouts(loaded, rootLayoutIds.length) : undefined;
|
|
590
|
+
const modules = chain?.modules ?? [];
|
|
591
|
+
const layoutIds = chain === undefined ? [] : rootLayoutIds;
|
|
592
|
+
const layoutData = chain?.layoutData;
|
|
593
|
+
const { chain: components, head } = resolveChainAndHead(modules, layoutData, loaded, statusMetaArgs(req, null, nonce));
|
|
594
|
+
let headers = extraHeaders;
|
|
595
|
+
if (layoutData !== undefined) {
|
|
596
|
+
// The page now shows what a layout loaded for this visitor.
|
|
597
|
+
const privateHeaders = new Headers(extraHeaders);
|
|
598
|
+
privateHeaders.set("cache-control", PRIVATE_NO_STORE);
|
|
599
|
+
headers = privateHeaders;
|
|
600
|
+
}
|
|
601
|
+
const statusPage = {
|
|
484
602
|
adapter,
|
|
485
|
-
chain:
|
|
603
|
+
chain: components,
|
|
486
604
|
data: null,
|
|
605
|
+
head,
|
|
487
606
|
clientEntry,
|
|
488
607
|
routeId,
|
|
489
|
-
matchChain:
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
search: searchOf(loaded.searchSchema, path.includes("?") ? path.slice(path.indexOf("?")) : ""),
|
|
493
|
-
}
|
|
494
|
-
: {}),
|
|
495
|
-
...(path !== undefined ? { path } : {}),
|
|
608
|
+
matchChain: matchChainOf(layoutIds, modules, routeId, loaded),
|
|
609
|
+
search: searchChainOf(modules, loaded, req),
|
|
610
|
+
path: pathOf(req),
|
|
496
611
|
status,
|
|
497
|
-
|
|
612
|
+
// The browser renders this page inside the root layout, so a page that had to render alone
|
|
613
|
+
// stays server-only, as a nested `_404` does.
|
|
614
|
+
...(wraps && chain === undefined ? { hydrate: false } : {}),
|
|
615
|
+
...(layoutData === undefined ? {} : { layoutData }),
|
|
616
|
+
...(headers !== undefined ? { headers } : {}),
|
|
498
617
|
...(nonce === undefined ? {} : { nonce }),
|
|
499
618
|
...cspOption,
|
|
500
619
|
...preloadOf(routeId),
|
|
501
|
-
|
|
620
|
+
// The build keys stylesheets by route, so a page inside the root layout links the whole-app one.
|
|
621
|
+
...(chain === undefined ? stylesOf(routeId) : stylesFrom(options.styles)),
|
|
502
622
|
...prerenderedHandover,
|
|
503
623
|
...titleOption,
|
|
504
|
-
}
|
|
624
|
+
};
|
|
625
|
+
if (chain === undefined)
|
|
626
|
+
return renderPageResult(statusPage);
|
|
627
|
+
try {
|
|
628
|
+
return await renderPageResult(statusPage);
|
|
629
|
+
}
|
|
630
|
+
catch {
|
|
631
|
+
// A layout that fails to render leaves the status page alone, never a second error.
|
|
632
|
+
return renderTerminalStatus(status, req, extraHeaders, nonce);
|
|
633
|
+
}
|
|
505
634
|
};
|
|
506
|
-
const renderStatusSignal = async (req, env, signal, personalized) => {
|
|
635
|
+
const renderStatusSignal = async (req, env, signal, personalized, layouts) => {
|
|
507
636
|
const { status, headers } = signal[STATUS_SIGNAL];
|
|
508
637
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
509
638
|
// Same URL as the status page, so it is never storable: a cache keyed on the URL alone would
|
|
@@ -516,7 +645,7 @@ export function createPageRequestExecutor(options) {
|
|
|
516
645
|
}
|
|
517
646
|
const nonce = await resolveNonce(req, env);
|
|
518
647
|
if (headers === undefined && !personalized) {
|
|
519
|
-
return renderTerminalStatus(status,
|
|
648
|
+
return renderTerminalStatus(status, req, undefined, nonce, layouts);
|
|
520
649
|
}
|
|
521
650
|
const documentHeaders = new Headers(headers);
|
|
522
651
|
if (headers !== undefined) {
|
|
@@ -525,7 +654,7 @@ export function createPageRequestExecutor(options) {
|
|
|
525
654
|
// A cookie queued before the signal makes the status page specific to this visitor.
|
|
526
655
|
if (personalized)
|
|
527
656
|
documentHeaders.set("cache-control", PRIVATE_NO_STORE);
|
|
528
|
-
return renderTerminalStatus(status,
|
|
657
|
+
return renderTerminalStatus(status, req, documentHeaders, nonce, layouts);
|
|
529
658
|
};
|
|
530
659
|
const reportLoaderError = (route, req, params, err) => {
|
|
531
660
|
if (options.onLoaderError === undefined)
|
|
@@ -537,9 +666,11 @@ export function createPageRequestExecutor(options) {
|
|
|
537
666
|
// A faulty reporter must never break error rendering.
|
|
538
667
|
}
|
|
539
668
|
};
|
|
540
|
-
const handleDataOrDocument = async (req, env, route, params, mod, data, layoutData, layoutModules, layoutRetained, boundaryStates, assemblyCache, responseHeaders, personalized) => {
|
|
669
|
+
const handleDataOrDocument = async (req, env, route, params, mod, data, layoutData, layoutModules, layoutRetained, boundaryStates, assemblyCache, responseHeaders, personalized, serverComponents) => {
|
|
670
|
+
// Every layout loader settled before the page rendered, so a status or error page can reuse them.
|
|
671
|
+
const settled = async (_page, count) => settledLayouts(layoutModules, layoutData, count);
|
|
541
672
|
if (isStatusSignal(data))
|
|
542
|
-
return renderStatusSignal(req, env, data, personalized);
|
|
673
|
+
return renderStatusSignal(req, env, data, personalized, settled);
|
|
543
674
|
if (isControlFlow(data))
|
|
544
675
|
return data;
|
|
545
676
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
@@ -557,7 +688,7 @@ export function createPageRequestExecutor(options) {
|
|
|
557
688
|
...deferred,
|
|
558
689
|
...(boundarySplit === undefined ? [] : boundarySplit.deferred),
|
|
559
690
|
];
|
|
560
|
-
const payload = layoutData === undefined && boundarySplit === undefined
|
|
691
|
+
const payload = layoutData === undefined && boundarySplit === undefined && serverComponents === undefined
|
|
561
692
|
? pageSplit.forClient
|
|
562
693
|
: {
|
|
563
694
|
v: 1,
|
|
@@ -565,6 +696,7 @@ export function createPageRequestExecutor(options) {
|
|
|
565
696
|
layoutData: layoutSplits.map((split) => split.forClient),
|
|
566
697
|
retained: layoutRetained,
|
|
567
698
|
...(boundarySplit === undefined ? {} : { boundaries: boundarySplit.forClient }),
|
|
699
|
+
...(serverComponents === undefined ? {} : { serverComponents }),
|
|
568
700
|
};
|
|
569
701
|
if (allDeferred.length === 0) {
|
|
570
702
|
return Response.json(payload ?? null, { headers: DATA_RESPONSE_HEADERS });
|
|
@@ -577,8 +709,9 @@ export function createPageRequestExecutor(options) {
|
|
|
577
709
|
});
|
|
578
710
|
}
|
|
579
711
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(req, env);
|
|
580
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
712
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
581
713
|
data,
|
|
714
|
+
pageData: data,
|
|
582
715
|
params,
|
|
583
716
|
origin: originOf(req),
|
|
584
717
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -595,6 +728,8 @@ export function createPageRequestExecutor(options) {
|
|
|
595
728
|
path: pathOf(req),
|
|
596
729
|
search: searchChainOf(layoutModules, mod, req),
|
|
597
730
|
matchChain: matchChainOf(route.layoutIds, layoutModules, route.id, mod),
|
|
731
|
+
...(serverComponents === undefined ? {} : { serverComponents }),
|
|
732
|
+
...(progressiveActionData.has(req) ? { actionData: progressiveActionData.get(req) } : {}),
|
|
598
733
|
hydrate: mod.hydrate !== false,
|
|
599
734
|
...(layoutData !== undefined ? { layoutData } : {}),
|
|
600
735
|
...(boundaryStates !== undefined ? { boundaries: boundaryStates } : {}),
|
|
@@ -622,31 +757,33 @@ export function createPageRequestExecutor(options) {
|
|
|
622
757
|
}
|
|
623
758
|
catch (err) {
|
|
624
759
|
if (isStatusSignal(err))
|
|
625
|
-
return renderStatusSignal(req, env, err, personalized);
|
|
760
|
+
return renderStatusSignal(req, env, err, personalized, settled);
|
|
626
761
|
if (isControlFlow(err))
|
|
627
762
|
throw err;
|
|
628
763
|
reportLoaderError(route, req, { ...params }, err);
|
|
629
764
|
const errorId = boundaryFor(route, err);
|
|
630
765
|
if (errorId === undefined)
|
|
631
766
|
throw err;
|
|
632
|
-
|
|
767
|
+
options.logBoundaryError?.(err, req);
|
|
768
|
+
return renderError(req, route, errorId, withDuplicateInstanceHint(err), personalized, nonce, settled);
|
|
633
769
|
}
|
|
634
770
|
};
|
|
635
771
|
/** What a failed loader answers with, once a status signal has been ruled out. */
|
|
636
|
-
const renderLoaderFailure = async (route, req, env, params, err, personalized) => {
|
|
772
|
+
const renderLoaderFailure = async (route, req, env, params, err, personalized, layouts) => {
|
|
637
773
|
if (isControlFlow(err))
|
|
638
774
|
throw err;
|
|
639
775
|
reportLoaderError(route, req, params, err);
|
|
640
776
|
const errorId = boundaryFor(route, err);
|
|
641
777
|
if (errorId === undefined)
|
|
642
778
|
throw err;
|
|
779
|
+
options.logBoundaryError?.(err, req);
|
|
643
780
|
if (req.headers.get(DATA_HEADER) !== null) {
|
|
644
781
|
return new Response("Internal Server Error", {
|
|
645
782
|
status: 500,
|
|
646
783
|
headers: { "content-type": "text/plain; charset=utf-8" },
|
|
647
784
|
});
|
|
648
785
|
}
|
|
649
|
-
return renderError(route, errorId, withDuplicateInstanceHint(err), personalized, options.nonce === undefined ? undefined : await resolveNonce(req, env));
|
|
786
|
+
return renderError(req, route, errorId, withDuplicateInstanceHint(err), personalized, options.nonce === undefined ? undefined : await resolveNonce(req, env), layouts);
|
|
650
787
|
};
|
|
651
788
|
/**
|
|
652
789
|
* Render a nested `_404` inside its layouts. `layoutModules` and `layoutData` are exactly the
|
|
@@ -665,8 +802,9 @@ export function createPageRequestExecutor(options) {
|
|
|
665
802
|
}
|
|
666
803
|
const mod = await page.load();
|
|
667
804
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(req, env);
|
|
668
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
805
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
669
806
|
data: null,
|
|
807
|
+
pageData: null,
|
|
670
808
|
params,
|
|
671
809
|
origin: originOf(req),
|
|
672
810
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -721,11 +859,11 @@ export function createPageRequestExecutor(options) {
|
|
|
721
859
|
const kept = page.layoutIds.length;
|
|
722
860
|
return renderNestedNotFound(req, env, id, page, params, run.modules.slice(0, kept), run.layoutData?.slice(0, kept), personalized, signal[STATUS_SIGNAL].headers);
|
|
723
861
|
};
|
|
724
|
-
const renderNotFound = async (
|
|
862
|
+
const renderNotFound = async (c, controls) => {
|
|
725
863
|
const page = manifest.statusPages?.["404"] ?? manifest.notFound;
|
|
726
864
|
if (page === undefined)
|
|
727
|
-
return renderTerminalStatus(404,
|
|
728
|
-
return renderTerminalStatus(404,
|
|
865
|
+
return renderTerminalStatus(404, c.req);
|
|
866
|
+
return renderTerminalStatus(404, c.req, undefined, options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env), rootLayoutsFor(c, controls));
|
|
729
867
|
};
|
|
730
868
|
/**
|
|
731
869
|
* Run a page handler with the request's `ctx.set`, sealed once the handler settles - whatever it
|
|
@@ -779,8 +917,19 @@ export function createPageRequestExecutor(options) {
|
|
|
779
917
|
return assemblySlot;
|
|
780
918
|
};
|
|
781
919
|
return withResponseControls(async (c, controls) => {
|
|
782
|
-
|
|
783
|
-
|
|
920
|
+
const componentRuntime = options.serverComponents;
|
|
921
|
+
const componentOwner = componentRuntime?.owns(route.id) === true;
|
|
922
|
+
let componentRequest;
|
|
923
|
+
try {
|
|
924
|
+
componentRequest = componentRuntime?.classify(c.req, route.id);
|
|
925
|
+
}
|
|
926
|
+
catch (error) {
|
|
927
|
+
return componentRuntime.failure(error);
|
|
928
|
+
}
|
|
929
|
+
if (componentOwner || componentRequest !== undefined)
|
|
930
|
+
controls.personalize();
|
|
931
|
+
if (!componentOwner && is404Fallback && !prerenderedSet.has(urlPartsFor(c.req).pathname)) {
|
|
932
|
+
return renderNotFound(c, controls);
|
|
784
933
|
}
|
|
785
934
|
const mod = await route.load();
|
|
786
935
|
const draft = await draftFlag(c.req);
|
|
@@ -793,6 +942,7 @@ export function createPageRequestExecutor(options) {
|
|
|
793
942
|
let layoutModules;
|
|
794
943
|
let layoutRetained = [];
|
|
795
944
|
let responseHeaders;
|
|
945
|
+
let componentState;
|
|
796
946
|
const requestApi = apiFor(c);
|
|
797
947
|
let run;
|
|
798
948
|
try {
|
|
@@ -808,13 +958,15 @@ export function createPageRequestExecutor(options) {
|
|
|
808
958
|
};
|
|
809
959
|
if (route.middlewareIds !== undefined)
|
|
810
960
|
await runMiddleware(route, ctx, controls);
|
|
811
|
-
run = await runLayoutChain(route, ctx, controls, retainContextOf(c.req));
|
|
961
|
+
run = await runLayoutChain(route, ctx, controls, componentOwner ? undefined : retainContextOf(c.req));
|
|
812
962
|
layoutModules = run.modules;
|
|
813
963
|
layoutRetained = run.retained;
|
|
814
|
-
const boundaryDefinitions =
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
964
|
+
const boundaryDefinitions = componentRequest === undefined
|
|
965
|
+
? [
|
|
966
|
+
...run.modules.flatMap((layout) => layout.boundaries ?? []),
|
|
967
|
+
...(mod.boundaries ?? []),
|
|
968
|
+
]
|
|
969
|
+
: [];
|
|
818
970
|
if (boundaryDefinitions.length > 0)
|
|
819
971
|
boundaryDescriptors(boundaryDefinitions);
|
|
820
972
|
const effectiveSearch = searchChainOf(run.modules, mod, c.req);
|
|
@@ -840,6 +992,25 @@ export function createPageRequestExecutor(options) {
|
|
|
840
992
|
: await Promise.all([pageResult, run.pending, staticBoundaryPromise]);
|
|
841
993
|
data = pageData;
|
|
842
994
|
layoutData = run.layoutData;
|
|
995
|
+
if (componentOwner) {
|
|
996
|
+
for (let i = 0; i < (layoutData?.length ?? 0); i++) {
|
|
997
|
+
const outcome = layoutData?.[i];
|
|
998
|
+
if (isControlFlow(outcome) || isStatusSignal(outcome))
|
|
999
|
+
throw tagLayoutError(outcome, route.layoutIds[i]);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (componentRequest !== undefined && (isControlFlow(data) || isStatusSignal(data)))
|
|
1003
|
+
return componentRuntime.failure(data);
|
|
1004
|
+
if (componentOwner && !isControlFlow(data) && !isStatusSignal(data)) {
|
|
1005
|
+
const componentContext = Object.create(c, Object.getOwnPropertyDescriptors({
|
|
1006
|
+
...ctx,
|
|
1007
|
+
search: effectiveSearch,
|
|
1008
|
+
signal: c.signal === undefined ? c.req.signal : AbortSignal.any([c.signal, c.req.signal]),
|
|
1009
|
+
data,
|
|
1010
|
+
layoutData: layoutData ?? [],
|
|
1011
|
+
}));
|
|
1012
|
+
componentState = await componentRuntime.execute(route.id, componentContext, componentRequest, options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env));
|
|
1013
|
+
}
|
|
843
1014
|
if (boundaryBatch !== undefined) {
|
|
844
1015
|
const streamed = { ...boundaryBatch.initial, ...(staticBoundaries ?? {}) };
|
|
845
1016
|
for (const entry of boundaryBatch.pending) {
|
|
@@ -857,17 +1028,28 @@ export function createPageRequestExecutor(options) {
|
|
|
857
1028
|
responseHeaders = controls.documentHeaders();
|
|
858
1029
|
}
|
|
859
1030
|
catch (err) {
|
|
1031
|
+
if (componentRequest !== undefined)
|
|
1032
|
+
return componentRuntime.failure(err);
|
|
860
1033
|
if (isStatusSignal(err)) {
|
|
861
|
-
return ((await renderRouteNotFound(c.req, c.env, route, c.params, err, run, controls.personalized)) ??
|
|
1034
|
+
return ((await renderRouteNotFound(c.req, c.env, route, c.params, err, run, controls.personalized)) ??
|
|
1035
|
+
renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err)));
|
|
862
1036
|
}
|
|
863
|
-
return renderLoaderFailure(route, c.req, c.env, c.params, err, controls.personalized);
|
|
1037
|
+
return renderLoaderFailure(route, c.req, c.env, c.params, err, controls.personalized, leadingLayouts(run, err));
|
|
1038
|
+
}
|
|
1039
|
+
if (componentRequest !== undefined && componentState !== undefined) {
|
|
1040
|
+
const answer = componentRuntime.response(componentState, componentRequest);
|
|
1041
|
+
const headers = new Headers(answer.headers);
|
|
1042
|
+
for (const [name, value] of Object.entries(responseHeaders ?? {}))
|
|
1043
|
+
if (name !== "cache-control" && name !== "content-type" && name !== "vary")
|
|
1044
|
+
headers.set(name, value);
|
|
1045
|
+
return new Response(answer.body, { status: answer.status, headers });
|
|
864
1046
|
}
|
|
865
1047
|
if (isStatusSignal(data)) {
|
|
866
1048
|
const nested = await renderRouteNotFound(c.req, c.env, route, c.params, data, run, controls.personalized);
|
|
867
1049
|
if (nested !== undefined)
|
|
868
1050
|
return nested;
|
|
869
1051
|
}
|
|
870
|
-
return handleDataOrDocument(c.req, c.env, route, c.params, mod, data, layoutData, layoutModules ?? (await loadLayoutModules(route)), layoutRetained, boundaryStates, layoutModules === undefined ? undefined : assemblyCacheFor(mod, layoutModules), responseHeaders, controls.personalized);
|
|
1052
|
+
return handleDataOrDocument(c.req, c.env, route, c.params, mod, data, layoutData, layoutModules ?? (await loadLayoutModules(route)), layoutRetained, boundaryStates, layoutModules === undefined ? undefined : assemblyCacheFor(mod, layoutModules), responseHeaders, controls.personalized, componentState);
|
|
871
1053
|
});
|
|
872
1054
|
},
|
|
873
1055
|
post: (route) => withResponseControls(async (c, controls) => {
|
|
@@ -893,12 +1075,12 @@ export function createPageRequestExecutor(options) {
|
|
|
893
1075
|
set: controls.scope(ACTION_SCOPE),
|
|
894
1076
|
};
|
|
895
1077
|
const isDataRequest = c.req.headers.get(DATA_HEADER) !== null;
|
|
896
|
-
let
|
|
1078
|
+
let gated;
|
|
897
1079
|
let result;
|
|
898
1080
|
try {
|
|
899
1081
|
if (route.middlewareIds !== undefined)
|
|
900
1082
|
await runMiddleware(route, actionContext, controls);
|
|
901
|
-
|
|
1083
|
+
gated = await runLayoutGates(route, actionContext, controls);
|
|
902
1084
|
result = await mod.action(actionContext);
|
|
903
1085
|
}
|
|
904
1086
|
catch (err) {
|
|
@@ -933,23 +1115,109 @@ export function createPageRequestExecutor(options) {
|
|
|
933
1115
|
},
|
|
934
1116
|
});
|
|
935
1117
|
}
|
|
1118
|
+
if (options.serverComponents?.owns(route.id)) {
|
|
1119
|
+
if (options.rerenderOwnerGET === undefined)
|
|
1120
|
+
throw new Error("component_contract");
|
|
1121
|
+
const actionHeaders = controls.documentHeaders();
|
|
1122
|
+
if (controls.progressiveRedirect(c.req)) {
|
|
1123
|
+
// Relative, so a browser behind a TLS terminator stays on its own scheme. A `//` path
|
|
1124
|
+
// would read as another host, so that one keeps the absolute URL.
|
|
1125
|
+
const { pathname, search } = new URL(c.req.url);
|
|
1126
|
+
const location = pathname.startsWith("//") ? c.req.url : pathname + search;
|
|
1127
|
+
return new Response(null, {
|
|
1128
|
+
status: 303,
|
|
1129
|
+
headers: { ...actionHeaders, location, "cache-control": PRIVATE_NO_STORE },
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
const headers = new Headers(c.req.headers);
|
|
1133
|
+
for (const name of [
|
|
1134
|
+
DATA_HEADER,
|
|
1135
|
+
RETAIN_HEADER,
|
|
1136
|
+
NAV_FROM_HEADER,
|
|
1137
|
+
"x-nifra-component",
|
|
1138
|
+
"content-type",
|
|
1139
|
+
"content-length",
|
|
1140
|
+
"transfer-encoding",
|
|
1141
|
+
])
|
|
1142
|
+
headers.delete(name);
|
|
1143
|
+
const cookie = controls.progressiveCookies(c.req);
|
|
1144
|
+
if (cookie)
|
|
1145
|
+
headers.set("cookie", cookie);
|
|
1146
|
+
else
|
|
1147
|
+
headers.delete("cookie");
|
|
1148
|
+
const request = new Request(c.req.url, {
|
|
1149
|
+
method: "GET",
|
|
1150
|
+
headers,
|
|
1151
|
+
signal: c.signal === undefined ? c.req.signal : AbortSignal.any([c.signal, c.req.signal]),
|
|
1152
|
+
});
|
|
1153
|
+
progressiveActionData.set(request, actionResult);
|
|
1154
|
+
try {
|
|
1155
|
+
const response = await options.rerenderOwnerGET(request, c);
|
|
1156
|
+
const merged = new Headers(response.headers);
|
|
1157
|
+
for (const [name, value] of Object.entries(actionHeaders ?? {}))
|
|
1158
|
+
if (!merged.has(name))
|
|
1159
|
+
merged.set(name, value);
|
|
1160
|
+
merged.set("cache-control", PRIVATE_NO_STORE);
|
|
1161
|
+
return new Response(response.body, {
|
|
1162
|
+
status: response.status,
|
|
1163
|
+
statusText: response.statusText,
|
|
1164
|
+
headers: merged,
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
finally {
|
|
1168
|
+
progressiveActionData.delete(request);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
const layoutModules = gated.modules;
|
|
936
1172
|
const search = searchChainOf(layoutModules, mod, c.req);
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1173
|
+
let run;
|
|
1174
|
+
let data;
|
|
1175
|
+
let responseHeaders;
|
|
1176
|
+
// The ordinary layout loaders run now, after the mutation, as a GET of this page would.
|
|
1177
|
+
try {
|
|
1178
|
+
run = await runLayoutChain(route, actionContext, controls, undefined, gated);
|
|
1179
|
+
const pageResult = mod.loader
|
|
1180
|
+
? mod.loader({
|
|
1181
|
+
params: c.params,
|
|
1182
|
+
request: c.req,
|
|
1183
|
+
req: c.req,
|
|
1184
|
+
api: requestApi,
|
|
1185
|
+
env: c.env,
|
|
1186
|
+
draft,
|
|
1187
|
+
search,
|
|
1188
|
+
set: controls.scope(PAGE_SCOPE),
|
|
1189
|
+
})
|
|
1190
|
+
: null;
|
|
1191
|
+
const [pageData] = run.pending === undefined
|
|
1192
|
+
? [await pageResult]
|
|
1193
|
+
: await Promise.all([pageResult, run.pending]);
|
|
1194
|
+
data = pageData;
|
|
1195
|
+
responseHeaders = controls.documentHeaders();
|
|
1196
|
+
}
|
|
1197
|
+
catch (err) {
|
|
1198
|
+
if (isStatusSignal(err)) {
|
|
1199
|
+
return ((await renderRouteNotFound(c.req, c.env, route, c.params, err, run, controls.personalized)) ??
|
|
1200
|
+
renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err)));
|
|
1201
|
+
}
|
|
1202
|
+
return renderLoaderFailure(route, c.req, c.env, c.params, err, controls.personalized, leadingLayouts(run, err));
|
|
1203
|
+
}
|
|
1204
|
+
// The re-render answers a returned redirect or status the way the page's GET does.
|
|
1205
|
+
if (isStatusSignal(data))
|
|
1206
|
+
return ((await renderRouteNotFound(c.req, c.env, route, c.params, data, run, controls.personalized)) ??
|
|
1207
|
+
renderStatusSignal(c.req, c.env, data, controls.personalized, leadingLayouts(run, data)));
|
|
1208
|
+
if (isControlFlow(data))
|
|
1209
|
+
return data;
|
|
1210
|
+
const layoutData = run.layoutData;
|
|
1211
|
+
const layoutProps = {};
|
|
1212
|
+
if (layoutData !== undefined) {
|
|
1213
|
+
layoutProps.layoutData = layoutData;
|
|
1214
|
+
// The page now shows what a layout loaded for this visitor.
|
|
1215
|
+
responseHeaders = { ...responseHeaders, ...PRIVATE_PAGE_HEADERS };
|
|
1216
|
+
}
|
|
950
1217
|
const nonce = options.nonce === undefined ? undefined : await resolveNonce(c.req, c.env);
|
|
951
|
-
const { chain, head } = resolveChainAndHead(layoutModules, mod, {
|
|
1218
|
+
const { chain, head } = resolveChainAndHead(layoutModules, layoutData, mod, {
|
|
952
1219
|
data,
|
|
1220
|
+
pageData: data,
|
|
953
1221
|
params: c.params,
|
|
954
1222
|
origin: originOf(c.req),
|
|
955
1223
|
...(nonce === undefined ? {} : { nonce }),
|
|
@@ -967,6 +1235,7 @@ export function createPageRequestExecutor(options) {
|
|
|
967
1235
|
search,
|
|
968
1236
|
matchChain: matchChainOf(route.layoutIds, layoutModules, route.id, mod),
|
|
969
1237
|
hydrate: mod.hydrate !== false,
|
|
1238
|
+
...layoutProps,
|
|
970
1239
|
...preloadOf(route.id),
|
|
971
1240
|
...stylesOf(route.id),
|
|
972
1241
|
...prerenderedHandover,
|
|
@@ -980,7 +1249,7 @@ export function createPageRequestExecutor(options) {
|
|
|
980
1249
|
const match = matchNotFoundScope?.(pathOf(c.req)) ?? null;
|
|
981
1250
|
const target = match === null ? undefined : notFoundTargets[Number(match.routeId)];
|
|
982
1251
|
if (match === null || target === undefined) {
|
|
983
|
-
return renderNotFound(c
|
|
1252
|
+
return renderNotFound(c, controls);
|
|
984
1253
|
}
|
|
985
1254
|
const params = {};
|
|
986
1255
|
for (let i = 0; i < target.names.length; i++) {
|
|
@@ -1010,9 +1279,9 @@ export function createPageRequestExecutor(options) {
|
|
|
1010
1279
|
}
|
|
1011
1280
|
catch (err) {
|
|
1012
1281
|
if (isStatusSignal(err)) {
|
|
1013
|
-
return renderStatusSignal(c.req, c.env, err, controls.personalized);
|
|
1282
|
+
return renderStatusSignal(c.req, c.env, err, controls.personalized, leadingLayouts(run, err));
|
|
1014
1283
|
}
|
|
1015
|
-
return renderLoaderFailure(target.route, c.req, c.env, params, err, controls.personalized);
|
|
1284
|
+
return renderLoaderFailure(target.route, c.req, c.env, params, err, controls.personalized, leadingLayouts(run, err));
|
|
1016
1285
|
}
|
|
1017
1286
|
return renderNestedNotFound(c.req, c.env, target.id, target.page, params, run.modules, run.layoutData, controls.personalized);
|
|
1018
1287
|
}),
|